当前位置:   article > 正文

基于FPGA实现uart串口模块(Verilog)--------接收模块及思路总结_uart tx是串转并还是并转串

uart tx是串转并还是并转串

基于FPGA实现uart串口模块(Verilog)--------接收模块及思路总结

uart通信协议简单理解为串转并和并转串的两个模块。同时必须保证数据的正确性。且输入输出端为串行。

此次实现uart协议通过回环来保证数据接收发送的正确。用状态机来理解(也不知道是不是状态机,觉得这样写比较好理解)。

两个接收,发送是对于开发板来说的。开发板的接收端连接的是pc机的发送端。反之。

波特率

串口发送接收的速度,一秒传输多少的数据,此次基于9600波特率。(比特率与波特率不同,比特率为在一个波特率内传输的bit数)

实现原理

(代码仿真的时候,可以使用01010101和10101010这两个数分别来检验模块的正确性)

可以看出,数据为高为通常状况,当需要发送时,首先发送一个低电平,然后开始传输数据,等八位数据发送结束后,再发送一个结束位。这样,结束8bit数据的发送。从上面仿真图的可以很清楚的看出发送接收状况。当接收到起始位时,表示开始接收。具体接收会在下文代码里边具体展现。通过状态机很好的理解。

同时发送的时候,需要先发送最低位。具体在下图表示。

代码实现

  1. module uart_rx(
  2. //-----------input
  3. clk,rst_n,rx_data,
  4. //-----------output
  5. po_data,po_flag
  6. );
  7. input clk;
  8. input rst_n;
  9. input rx_data;
  10. output [7:0] po_data;
  11. output po_flag;
  12. //------------------------------
  13. parameter idle = 2'd0,
  14. start = 2'd1,
  15. work = 2'd2,
  16. stop = 2'd3;
  17. //------------------------------
  18. /*这里得到5207的方法是系统时钟周期50_000_000/9600 可以改变两者数据实现不同的传输需求*/
  19. localparam baud_cnt_end = 5207 ;
  20. localparam baud_cnt_m = (baud_cnt_end + 1) / 2 - 1;
  21. //------------------------------
  22. reg rx1;
  23. reg rx2;
  24. reg rx_flag;
  25. reg [12:0] baud_cnt;
  26. reg bit_flag;
  27. reg [3:0] bit_cnt;
  28. reg po_flag;
  29. reg [7:0] po_data;
  30. reg [1:0] current_state;
  31. reg [1:0] next_state;
  32. //------------------------------
  33. //第一个进程,同步时序always块,形式固定
  34. always@(posedge clk or negedge rst_n)
  35. begin
  36. if(!rst_n)
  37. current_state <= idle;
  38. else
  39. current_state <= next_state;
  40. end
  41. //第二个always,组合逻辑模块,描述状态迁移条件判断
  42. always@(*)
  43. begin
  44. case(current_state)
  45. idle:/*空闲状态*/
  46. begin
  47. rx_flag = 1'b0;
  48. begin
  49. if(nedge)/*当接收到下降沿的时候开始进入发送起始位状态*/
  50. next_state = start;
  51. else
  52. next_state = idle;
  53. end
  54. end
  55. start:/*发送起始位*/
  56. begin
  57. rx_flag = 1'b1;
  58. begin
  59. if(bit_cnt == 4'b1)
  60. next_state = work;
  61. else
  62. next_state = start;
  63. end
  64. end
  65. work:/*发送数据位*/
  66. begin
  67. rx_flag = 1'b1;
  68. begin
  69. if(bit_cnt == 4'd9)
  70. next_state = stop;
  71. else
  72. next_state = work;
  73. end
  74. end
  75. stop:/*发送停止位*/
  76. begin
  77. rx_flag = 1'b1;
  78. begin
  79. if(bit_cnt == 4'd10)
  80. next_state = idle;
  81. else
  82. next_state = stop;
  83. end
  84. end
  85. default:
  86. begin
  87. next_state = idle;
  88. end
  89. endcase
  90. end
  91. //第三个进程,描述输出,同步时序always块
  92. //下降沿检测------------------------------
  93. /*跨时钟域处理!!?后文专门解释所有的跨时钟域问题
  94. 但bit打两拍*/
  95. //reg rx1;
  96. //reg rx2;
  97. //reg rx3;
  98. always@(posedge clk)
  99. begin
  100. rx1 <= rx_data;
  101. rx2 <= rx1;
  102. end
  103. wire nedge;
  104. assign nedge = rx2 && ~rx1;
  105. /*波特率计数,在发送状态计数*/
  106. //定义band_cnt------------------------------
  107. //reg [12:0] baud_cnt;
  108. always@(posedge clk or negedge rst_n)
  109. begin
  110. if(!rst_n)
  111. baud_cnt <= 13'd0;
  112. else
  113. if(baud_cnt == baud_cnt_end)
  114. baud_cnt <= 13'd0;
  115. else
  116. if(rx_flag)
  117. baud_cnt <= baud_cnt + 1'b1;
  118. else
  119. baud_cnt <= 13'd0;
  120. end
  121. /*发送接收位这里取数据是在接收中点处取数据,因为是串转并,所以在哪里接收数据都无所谓后面等会了
  122. 把小梅哥用数组接收总结下*/
  123. //define bit_flag------------------------------
  124. //reg bit_flag;
  125. always@(posedge clk or negedge rst_n)
  126. begin
  127. if(!rst_n)
  128. bit_flag <= 1'b0;
  129. else
  130. if(baud_cnt == baud_cnt_m)
  131. bit_flag <= 1'b1;
  132. else
  133. bit_flag <= 1'b0;
  134. end
  135. /*发送的是第多少位*/
  136. //define bit_cnt------------------------------
  137. //reg [3:0] bit_cnt;
  138. always@(posedge clk or negedge rst_n)
  139. begin
  140. if(!rst_n)
  141. bit_cnt <= 4'd0;
  142. else
  143. if(rx_flag == 0)
  144. bit_cnt <= 4'd0;
  145. else
  146. if(baud_cnt == baud_cnt_end)
  147. bit_cnt <= bit_cnt + 1'b1;
  148. end
  149. /*接收结束信号*/
  150. //define po_flag------------------------------
  151. //reg po_flag;
  152. always@(posedge clk or negedge rst_n)
  153. begin
  154. if(!rst_n)
  155. po_flag <= 1'b0;
  156. else
  157. if(bit_cnt == 4'd10)
  158. po_flag <= 1'b1;
  159. else
  160. po_flag <= 1'b0;
  161. end
  162. /*数据寄存*/
  163. reg [7:0] po_data_r;
  164. always@(posedge clk )
  165. begin
  166. if(bit_cnt == 4'd10)
  167. po_data <= po_data_r;
  168. else
  169. po_data <= 8'd0;
  170. end
  171. /*数据转换,串行转并行数据,在相应的数据接收数据,忽略起始位和结束位*/
  172. always@(posedge clk or negedge rst_n)
  173. begin
  174. if(!rst_n)
  175. po_data_r <= 8'b0;
  176. else
  177. if(rx_flag)
  178. if(bit_flag)
  179. case(bit_cnt)
  180. 4'd1 : po_data_r[0] <= rx2 ;
  181. 4'd2 : po_data_r[1] <= rx2 ;
  182. 4'd3 : po_data_r[2] <= rx2 ;
  183. 4'd4 : po_data_r[3] <= rx2 ;
  184. 4'd5 : po_data_r[4] <= rx2 ;
  185. 4'd6 : po_data_r[5] <= rx2 ;
  186. 4'd7 : po_data_r[6] <= rx2 ;
  187. 4'd8 : po_data_r[7] <= rx2 ;
  188. default:po_data_r <= po_data_r ;
  189. endcase
  190. else
  191. po_data_r <= po_data_r;
  192. else
  193. po_data_r <= 8'd0;
  194. end
  195. endmodule

19_5_5加更

A:修改前面一些时序的小问题(保证输出有效拉高点输出数据,可以不使用状态机,使用状态机纯粹当初是为了加深理解,这里我把代码还保留,只不过注释掉了,具体可以参考)

B:波特率可改变,改变前面的定义,可以实现任意波特率的发送与接收。可用于图片发送等等一系列模块(奇偶数可以改变,同时改变中点值即可)

查找表:

1,接收模块

  1. module uart_rx(
  2. //-----------input
  3. clk,rst_n,rx_data,
  4. //-----------output
  5. po_data,rx_done
  6. );
  7. input clk;
  8. input rst_n;
  9. input rx_data;
  10. output [7:0] po_data;
  11. output reg rx_done;
  12. localparam baud_cnt_end = 'd434 - 'd1 ;
  13. localparam baud_cnt_m = (baud_cnt_end ) / 'd2 ;
  14. // localparam baud_cnt_m = (baud_cnt_end + 'd1) / 'd2 - 'd1 ;
  15. //------------------------------
  16. reg rx1;
  17. reg rx2;
  18. reg rx_flag;
  19. reg [12:0] baud_cnt;
  20. reg bit_flag;
  21. reg [3:0] bit_cnt;
  22. reg [7:0] po_data;
  23. //第三个进程,描述输出,同步时序always块
  24. //下降沿检测------------------------------
  25. //reg rx1;
  26. //reg rx2;
  27. //reg rx3;
  28. always@(posedge clk)
  29. begin
  30. rx1 <= rx_data;
  31. rx2 <= rx1;
  32. end
  33. wire nedge;
  34. assign nedge = rx2 && ~rx1 && !rx_flag;
  35. // define rx_flag
  36. always @ (posedge clk or negedge rst_n)
  37. begin
  38. if(!rst_n)
  39. rx_flag <= 1'b0;
  40. else
  41. if(nedge)
  42. rx_flag <= 1'b1;
  43. else
  44. if(bit_cnt == 'd8 && baud_cnt == baud_cnt_end)
  45. rx_flag <= 1'b0;
  46. end
  47. //定义band_cnt------------------------------
  48. //reg [12:0] baud_cnt;
  49. always@(posedge clk or negedge rst_n)
  50. begin
  51. if(!rst_n)
  52. baud_cnt <= 13'd0;
  53. else
  54. if(baud_cnt == baud_cnt_end)
  55. baud_cnt <= 13'd0;
  56. else
  57. if(rx_flag)
  58. baud_cnt <= baud_cnt + 1'b1;
  59. else
  60. baud_cnt <= 13'd0;
  61. end
  62. //define bit_flag------------------------------
  63. //reg bit_flag;
  64. always@(posedge clk or negedge rst_n)
  65. begin
  66. if(!rst_n)
  67. bit_flag <= 1'b0;
  68. else
  69. if(baud_cnt == baud_cnt_m)
  70. bit_flag <= 1'b1;
  71. else
  72. bit_flag <= 1'b0;
  73. end
  74. //define bit_cnt------------------------------
  75. //reg [3:0] bit_cnt;
  76. always@(posedge clk or negedge rst_n)
  77. begin
  78. if(!rst_n)
  79. bit_cnt <= 4'd0;
  80. else
  81. if(rx_flag == 0)
  82. bit_cnt <= 4'd0;
  83. else
  84. if(baud_cnt == baud_cnt_end && rx_flag)
  85. bit_cnt <= bit_cnt + 1'b1;
  86. end
  87. //define rx_done------------------------------
  88. //reg rx_done;
  89. always@(posedge clk or negedge rst_n)
  90. begin
  91. if(!rst_n)
  92. rx_done <= 1'b0;
  93. else
  94. if(bit_cnt == 'd8 && baud_cnt == baud_cnt_end - 'd1)
  95. rx_done <= 1'b1;
  96. else
  97. rx_done <= 1'b0;
  98. end
  99. reg [7:0] po_data_r;
  100. always@(posedge clk )
  101. begin
  102. if(bit_cnt == 'd8 && baud_cnt == baud_cnt_end - 'd1)
  103. po_data <= po_data_r;
  104. else
  105. po_data <= 8'd0;
  106. end
  107. always@(posedge clk or negedge rst_n)
  108. begin
  109. if(!rst_n)
  110. po_data_r <= 8'b0;
  111. else
  112. if(rx_flag)
  113. if(bit_flag)
  114. case(bit_cnt)
  115. 4'd1 : po_data_r[0] <= rx2 ;
  116. 4'd2 : po_data_r[1] <= rx2 ;
  117. 4'd3 : po_data_r[2] <= rx2 ;
  118. 4'd4 : po_data_r[3] <= rx2 ;
  119. 4'd5 : po_data_r[4] <= rx2 ;
  120. 4'd6 : po_data_r[5] <= rx2 ;
  121. 4'd7 : po_data_r[6] <= rx2 ;
  122. 4'd8 : po_data_r[7] <= rx2 ;
  123. default:po_data_r <= po_data_r ;
  124. endcase
  125. else
  126. po_data_r <= po_data_r;
  127. else
  128. po_data_r <= 8'd0;
  129. end
  130. endmodule
  131. // //------------------------------
  132. // parameter idle = 2'd0,
  133. // start = 2'd1,
  134. // work = 2'd2,
  135. // stop = 2'd3;
  136. // //------------------------------
  137. // reg [1:0] current_state;
  138. // always@(*)
  139. // begin
  140. // case(current_state)
  141. // idle:
  142. // if(nedge)
  143. // current_state = start;
  144. // else
  145. // current_state = idle;
  146. // start:
  147. // if(bit_cnt == 4'b1)
  148. // current_state = work;
  149. // else
  150. // current_state = start;
  151. // work:
  152. // if(bit_cnt == 'd7 && baud_cnt == baud_cnt_end)
  153. // current_state = stop;
  154. // else
  155. // current_state = work;
  156. // stop:
  157. // if(rx_done)
  158. // current_state = idle;
  159. // else
  160. // current_state = stop;
  161. // default:
  162. // current_state = idle;
  163. // endcase
  164. // end

2,发送模块

  1. module uart_tx(
  2. //-----------input
  3. clk,rst_n,pi_data,tx_en,
  4. //-----------output
  5. tx_data
  6. );
  7. input clk;
  8. input rst_n;
  9. input [7:0] pi_data;
  10. input tx_en;
  11. output reg tx_data;
  12. localparam baud_cnt_end = 'd434 - 'd1 ;
  13. // localparam baud_cnt_m = (baud_cnt_end ) / 'd2 ;
  14. // localparam baud_cnt_m = (baud_cnt_end + 'd1) / 'd2 - 'd1 ;
  15. reg tx_en1;
  16. reg tx_en2;
  17. reg tx_flag;
  18. reg [12:0] baud_cnt;
  19. reg [3:0] bit_cnt;
  20. always@(posedge clk )
  21. begin
  22. tx_en1 <= tx_en;
  23. tx_en2 <= tx_en1;
  24. end
  25. always @ (posedge clk or negedge rst_n)
  26. begin
  27. if(!rst_n)
  28. tx_flag <= 1'b1;
  29. else
  30. if(tx_en2 && !tx_flag)
  31. tx_flag <= 1'b1;
  32. else
  33. if(bit_cnt == 'd8 && baud_cnt == baud_cnt_end)
  34. tx_flag <= 1'b0;
  35. end
  36. //reg [3:0] bit_cnt;
  37. always@(posedge clk or negedge rst_n)
  38. begin
  39. if(!rst_n)
  40. bit_cnt <= 4'd0;
  41. else
  42. if(!tx_flag)
  43. bit_cnt <= 4'd0;
  44. else
  45. if(baud_cnt == baud_cnt_end)
  46. bit_cnt <= bit_cnt + 1'b1;
  47. else
  48. bit_cnt <= bit_cnt;
  49. end
  50. //reg [12:0] baud_cnt;
  51. always@(posedge clk or negedge rst_n)
  52. begin
  53. if(!rst_n)
  54. baud_cnt <= 13'd0;
  55. else
  56. if(baud_cnt == baud_cnt_end)
  57. baud_cnt <= 13'd0;
  58. else
  59. if(tx_flag)
  60. baud_cnt <= baud_cnt + 1'b1;
  61. else
  62. baud_cnt <= 13'd0;
  63. end
  64. reg [7:0] pi_data_r;
  65. always@(posedge clk or negedge rst_n)
  66. begin
  67. if(!rst_n)
  68. pi_data_r <= 8'd0;
  69. else
  70. if(tx_en)
  71. pi_data_r <= pi_data;
  72. else
  73. pi_data_r <= pi_data_r;
  74. end
  75. //define tx_data
  76. always@(posedge clk or negedge rst_n)
  77. begin
  78. if(!rst_n)
  79. tx_data <= 1'b1;
  80. else
  81. if(tx_flag)
  82. case(bit_cnt)
  83. 4'd0 : tx_data <= 1'b0 ;
  84. 4'd1 : tx_data <= pi_data_r[0] ;
  85. 4'd2 : tx_data <= pi_data_r[1] ;
  86. 4'd3 : tx_data <= pi_data_r[2] ;
  87. 4'd4 : tx_data <= pi_data_r[3] ;
  88. 4'd5 : tx_data <= pi_data_r[4] ;
  89. 4'd6 : tx_data <= pi_data_r[5] ;
  90. 4'd7 : tx_data <= pi_data_r[6] ;
  91. 4'd8 : tx_data <= pi_data_r[7] ;
  92. 4'd9 : tx_data <= 1'b1 ;
  93. default:;
  94. endcase
  95. else
  96. tx_data <= 1'b1;
  97. end
  98. endmodule

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/461607
推荐阅读
相关标签
  

闽ICP备14008679号