原创 三十而立学FPGA之UART

2022-5-20 07:14 712 2 3 分类: FPGA/CPLD 文集: FPGA
UART介绍 简介

通用异步收发器(Universal Asynchronous Receiver/Transmitter),既UART

时序

 

根据时序图可以了解到:

1. uart在空闲的时候是高电平
2. 当突变为低电平或者有一个下降沿,则是告知接收方uart要传数据了
3. 这里实现为8bit数据传输,当数据传输完成,在1或1.5或2个时钟周期内将传输线拉高,表示停止传输

UART之RX实现 状态转移图

 

源代码 
状态转移实现

  1. always @(*)
  2. begin
  3. case (state)
  4. IDLE:begin
  5. if(rx_pin==1'b0)
  6. nextstate <= START;
  7. else
  8. nextstate <= IDLE;
  9. end
  10. START:begin
  11. if(cycle_cnt == CYCLE_CNT_MAX-1)//当一个BIT周期后,接收数据
  12. nextstate <= REC_BYTE;
  13. else
  14. nextstate <= START;
  15. end
  16. REC_BYTE:begin
  17. if(cycle_cnt == CYCLE_CNT_MAX-1&&bit_cnt==4'd7)//8位数据接收完成,跳转到检测停止位
  18. nextstate <= STOP;
  19. else
  20. nextstate <= REC_BYTE;
  21. end
  22. STOP:begin
  23. if(cycle_cnt == CYCLE_CNT_MAX/2-1)//半个bit周期,检测到停止位,将接收的数据发送到其他模块
  24. nextstate <= DATA;
  25. else
  26. nextstate <= STOP;
  27. end
  28. DATA:begin //一个时钟周期后模块进入空闲态
  29. nextstate <= IDLE;
  30. end
  31. endcase
  32. end

时序描述

 

  1. //周期计数,既系统时钟内每个BIT所需要的周期数,通过波特率可计算出最大计数值</p><p style="margin-top: 0; margin-bottom: 0;">
  2. always@(posedge clk or negedge rst_n)
  3. begin
  4. if(rst_n == 1'b0)
  5. cycle_cnt <= 16'd0;
  6. else if(state == REC_BYTE && (cycle_cnt == CYCLE_CNT_MAX-1||nextstate != state))//只需要在开始接收数据时开始计数,所以前提条件是状态在REC_BYTE,而且如果计数值达到最大值或者在状态跳转的时候都需要将计数值清零
  7. cycle_cnt <= 16'd0;
  8. else
  9. cycle_cnt <= cycle_cnt + 16'd1;
  10. end
  11. //位计数,以确认接收的位数
  12. always@(posedge clk or negedge rst_n)
  13. begin
  14. if(rst_n == 1'b0)
  15. bit_cnt <= 4'd0;
  16. else if(state == REC_BYTE) //仅在接收数据状态时进行位计数
  17. if(cycle_cnt == CYCLE_CNT_MAX-1)
  18. bit_cnt <= bit_cnt + 4'd1;
  19. else
  20. bit_cnt <= bit_cnt;
  21. else
  22. bit_cnt <= 4'd0;
  23. end
  24. //数据接收
  25. always@(posedge clk or negedge rst_n)
  26. begin
  27. if(rst_n == 1'b0)
  28. rx_data_r <= 8'd0;
  29. else if(state == REC_BYTE && cycle_cnt == CYCLE_CNT_MAX/2-1)
  30. rx_data_r[bit_cnt] <= tx_pin;
  31. else
  32. rx_data_r <= rx_data_r;
  33. end
  34. //将数据传输给其他模块
  35. always@(posedge clk or negedge rst_n)
  36. begin
  37. if(rst_n == 1'b0)
  38. rx_data <= 8'd0;
  39. else if(state == STOP || nextstate != state)
  40. rx_data <= rx_data_r;
  41. end
  42. //接收完成标志
  43. always@(posedge clk or negedge rst_n)
  44. begin
  45. if(rst_n == 1'b0)
  46. rx_done <= 1'b0;
  47. else if(state == STOP )
  48. rx_done <= 1'b1;
  49. else
  50. rx_done <= 1'b0;
  51. end

 

UART之TX实现

实现TX就不用三段式状态机这么麻烦了,直接用序列机完全就可以了

模块使能或者说发送请求

  1. always@(posedge clk or negedge rst_n)
  2. begin
  3. if(rst_n == 1'b0)
  4. tx_en <= 1'b0;
  5. else if(tx_req_pos == 1'b1)
  6. tx_en <= 1'b1;
  7. else if(bit_cnt == 4'd11)
  8. tx_en <= 1'b0;
  9. else
  10. tx_en <= tx_en;
  11. end

 

周期计数、位计数

  1. //周期计数,既系统时钟内每个BIT所需要的周期数,通过波特率可计算出最大计数值
  2. always@(posedge clk or negedge rst_n)
  3. begin
  4. if(rst_n == 1'b0)
  5. cycle_cnt <= 16'd0;
  6. else if(tx_en)
  7. if(cycle_cnt == CYCLE_CNT_MAX-1)//当模块使能时,开始计数,计数到最大值再从零开始
  8. cycle_cnt <= 16'd0;
  9. else
  10. cycle_cnt <= cycle_cnt + 16'd1;
  11. else
  12. cycle_cnt <= 16'd0;
  13. end
  14. //位计数
  15. always@(posedge clk or negedge rst_n)
  16. begin
  17. if(rst_n == 1'b0)
  18. bit_cnt <= 4'd0;
  19. else if(cycle_cnt == 16'd1) //如果计数到最大值bit_cnt累加的话,那么数据发送需要多等一个bit周期
  20. bit_cnt <= bit_cnt + 4'd1;
  21. else if(bit_cnt == 4'd11)
  22. bit_cnt <= 4'd0;
  23. else
  24. bit_cnt <= bit_cnt;
  25. end

发送数据

  1. always@(posedge clk or negedge rst_n)
  2. begin
  3. if(rst_n == 1'b0)
  4. tx_pin_r <= 1'b1;
  5. else
  6. case(bit_cnt)
  7. 0:tx_pin_r <= 1'b1; //这里需要避免bit_cnt=0的时候发送起始位,因为当复位的时候bit_cnt的值是零的,会在复位时就已经发出了起始位,而导致接收端的误判和发送的时序紊乱
  8. 1:tx_pin_r <= START_BIT;
  9. 2:tx_pin_r <= send_data[0];
  10. 3:tx_pin_r <= send_data[1];
  11. 4:tx_pin_r <= send_data[2];
  12. 5:tx_pin_r <= send_data[3];
  13. 6:tx_pin_r <= send_data[4];
  14. 7:tx_pin_r <= send_data[5];
  15. 8:tx_pin_r <= send_data[6];
  16. 9:tx_pin_r <= send_data[7];
  17. 10:tx_pin_r <= STOP_BIT;
  18. default: tx_pin_r <= 1'b1;
  19. end

 

 

作者: 雏羽, 来源:面包板社区

链接: https://mbb.eet-china.com/blog/uid-me-1862109.html

版权声明:本文为博主原创,未经本人允许,禁止转载!

给作者打赏,鼓励TA抓紧创作!

赞赏支持
点赞 2
赞赏1

文章评论2条评论)

登录后参与讨论

雏羽 2022-6-16 17:17

luckyzy2000: 现在的三十还是算年轻人:)
不年轻了吧,再过十年就没啥精力了

luckyzy2000 2022-6-16 09:58

现在的三十还是算年轻人:)
相关推荐阅读
雏羽 2022-06-12 16:47
三十而立学FPGA之数码管
简介 数码管,一种把多个发光二极管通过简单阵列的方式组合而成的显示器件。多个二极管阴极连在一起,通过控制阳极的高低电平来控制数码管相应LED亮灭的叫做共阴,反之共阳。每个发光二极管称之为数码管的段,...
雏羽 2021-09-17 16:40
FPGA基础、高级功能与工业电子应用》+略读感受
当得知我能得到这本书的时候,还是很兴奋的。然后就是等京东的快递,可惜的是京东小哥弄了个乌龙,书放在我公司了一直说没带,一直持续了三天,在我拿其他快递的时候,无意中看见了另一个包裹,拆开后是惊喜也是好笑...
雏羽 2019-10-28 10:45
Allegro做中文丝印竟如此简单
​所需软件AutoCAD(或者其他CAD软件)AbleSoftwareR2V(链接:https://pan.baidu.com/s/16RYYCFzm_S9OGWeBuV1dKg提取码:tt63 )A...
雏羽 2015-11-22 20:12
可尽早捕获缺陷的DDR仿真策略
DDR验证是任何SoC设计过程中最关键也是最复杂的任务之一,因为它牵涉到位于待测器件内的控制器和位于待测器件外的DDR存储器。一个DDR系统由在一起工作的控制器、I/O、封装、插座、电源、时钟和外部存...
我要评论
2
2
1
2
3
4
5
6
7
8
9
0
关闭 热点推荐上一条 /3 下一条