当前位置:   article > 正文

小梅哥12——串口接收模块设计与验证_小梅哥 接收

小梅哥 接收

一、FPGA接收其他设备通过uart协议发送的数据

         使用ISSP查看uart接收模块接收到的数据,串口接收到的数据由PC机发出

1. uart通信协议工业环境下数据接收实现(干扰状态,进行一些处理保证稳定性)

        工业应用中,往往有较强的电磁干扰,因此只采集一次作为该数据的电平判定不保险,需要多次采样求概率

         将每一位数据平均分成 16 小段,在刚发生变化和即将发生变化时期,数据极可能不稳定,因此灰色这段忽略。考虑中间6次采样,选取出现次数较多的电平。各占一半时判定当前通信线路环境非常恶劣,数据不具有可靠性,不进行处理。

         将中间6次结果加起来(3位),>3(最高位为1)为1,<3为0,最高位数即为统计结果

         reg [2:0] r_data_byte [7:0]8个3位寄存器,r_data_byte[0][2]:第0个寄存器的第2位

2. 异步时钟同步处理

           Rs232_tx是外部输入信号,是异步信号,对其采样可能采集到不定态,D触发器会发生振荡,振荡后在下一个时钟信号到来前稳定下来,其稳定结果不确定,因此经过两级寄存器同步处理(与系统时钟变化一致)。

           第一个D触发器采集异步信号,q有振荡,但在下一个时钟信号前稳定,因此第二级D触发器(延迟一个时钟周期)采集到的是稳定态

3. ISSP探针probe使用

          

外部输入Rs232_rx,使用探针(8位)探测 data_rx_r(只有在rx_done高电平时将data_rx赋值给data_rx_r)

二、时序图

uart发送端发送一个字节Byte(8bit)数据时序图 

       每个bps_clk上升沿发送数据 

串口接收时序图 

      对数据线 Rs232_tx 上的每一位进行采样:开始和结束段数据变化,一般认为每一位数据的中间点最稳定,因此一般采集中间时刻时的电平即认为是此位数据的电平

      bps_clk上升沿对齐中点,在每个上升沿读取数据

三、模块设计

 起始位检测进程:起始位低电平,检测到下降沿,表面可能数据传输,开启波特率时钟(异步转   同步(两个同步寄存器s0_)、边沿检测(两个暂存寄存器tem0_,比较前后状态))。起始位可能检测错误,第12位起始位不为0(>=3)可判断为检测错误

波特率产生模块:每位采集16次,频率:Bps*16

数据接收进程

串口接收模块框图

        先有顶层设计思路,再分块实现 

注意 

 1. 

     一个bps_cnt会维持多个系统时钟,在Clk上升沿触发条件下,一个状态多次被检测到,多次相加

      bps_clk为高电平时,bps_cnt才计数,在bps_cnt为指定值且bps_clk为高电平(已经是下一个)时才采样,则会滞后一个周期,即在bps_cnt为6时采样得到的是7对应的电平,因此可以将6改为5,得到6对应的电平 

2.  

           data_byte的不同位来赋值,不是直接data_byte

3.  

                uart_state为触发条件,不能用nedge

 uart_byte_rx 

  1. module uart_byte_rx(
  2. Clk,
  3. Rst_n,
  4. Rs232_rx,
  5. baud_set,
  6. data_byte,
  7. rx_done
  8. );
  9. input Clk;
  10. input Rst_n;
  11. input Rs232_rx;//串行数据输入,一位
  12. input [2:0]baud_set;//5个bps,每种可能代表一个bps
  13. output reg [7:0]data_byte;//一个字节8位,每位有0、1两种可能
  14. output reg rx_done;
  15. reg s0_Rs232_rx, s1_Rs232_rx;
  16. reg tmp0_Rs232_rx, tmp1_Rs232_rx;
  17. reg [8:0]bps_DR;//计数,个数
  18. reg [8:0]div_cnt;
  19. reg bps_clk;
  20. reg [8:0]bps_cnt;
  21. reg [2:0]Start_bit,Stop_bit;//起始位、终止位要通过判断赋值!!
  22. reg [2:0]r_data_byte[7:0];//接受的数据共8位,每位对中间6次采样相加判定电平,6需要3位
  23. reg uart_state;//由下降沿判断串口状态,判断错误时由此结束
  24. wire nedge;
  25. //同步寄存器——消除亚稳态
  26. always@(posedge Clk or negedge Rst_n)
  27. if(!Rst_n)begin
  28. s0_Rs232_rx <= 1'b0;
  29. s1_Rs232_rx <= 1'b0;
  30. end
  31. else begin
  32. s0_Rs232_rx <= Rs232_rx;
  33. s1_Rs232_rx <= s0_Rs232_rx;//外部输入的数据稳定寄存在s1_Ts232_rx中,后按bps_clk频率,bps_cnt采样
  34. end
  35. //数据寄存器——边沿检测
  36. always@(posedge Clk or negedge Rst_n)
  37. if(!Rst_n)begin
  38. tmp0_Rs232_rx <= 1'b0;
  39. tmp1_Rs232_rx <= 1'b0;
  40. end
  41. else begin
  42. tmp0_Rs232_rx <= s0_Rs232_rx;
  43. tmp1_Rs232_rx <= tmp0_Rs232_rx;
  44. end
  45. assign nedge = !tmp0_Rs232_rx && tmp1_Rs232_rx;
  46. //baud_set ——> bps_DR ——> div_cnt(nedge) ——> bps_clk ——> bps_cnt(在此判断起始位检测是否正确,计数到12后才能判断)——>rx_done
  47. always@(posedge Clk or negedge Rst_n)
  48. if(!Rst_n)
  49. bps_DR <= 9'd324;
  50. else begin
  51. case(baud_set)
  52. 3'd0: bps_DR <= 9'd324;
  53. 3'd1: bps_DR <= 9'd162;
  54. 3'd2: bps_DR <= 9'd80;
  55. 3'd3: bps_DR <= 9'd53;
  56. 3'd4: bps_DR <= 9'd26;
  57. default: bps_DR <= 9'd324;
  58. endcase
  59. end
  60. always@(posedge Clk or negedge Rst_n)
  61. if(!Rst_n)
  62. div_cnt <= 9'd0;
  63. else if(uart_state)begin//下降沿只有一个周期,只能计一次,需要在接收段一直保持
  64. if(div_cnt == bps_DR - 1'd1)//波特率对应频率大于系统时钟,一个波特率周期包含多个系统时钟,对系统时钟计数得bps_cnt
  65. div_cnt <= 9'd0;
  66. else
  67. div_cnt <= div_cnt + 1'd1;
  68. end
  69. else
  70. div_cnt <= 9'd0;//不是复位,没有计满情况下清零(错误检测)
  71. always@(posedge Clk or negedge Rst_n)
  72. if(!Rst_n)
  73. bps_clk <= 1'b0;
  74. else if(div_cnt == 9'd1 )//位数应为该变量的位宽
  75. bps_clk <= 1'b1;
  76. else
  77. bps_clk <= 1'b0;//其余情况为0,不是保持本身需要写明
  78. always@(posedge Clk or negedge Rst_n)
  79. if(!Rst_n)
  80. bps_cnt <= 9'd0;
  81. else if(bps_cnt == 9'd159 || (bps_cnt==9'd12 && (Start_bit > 3'd2)))//10位,每位16次,计数到12,看起始位6次采样结果,>=3则为错误检测
  82. bps_cnt <= 9'd0;
  83. else if(bps_clk == 1'd1)
  84. bps_cnt <= bps_cnt + 1'd1;//后续按照bps_cnt计数接收数据,计满或检测错误为0,后续接收也为0
  85. always@(posedge Clk or negedge Rst_n)
  86. if(!Rst_n)
  87. rx_done <= 1'b0;
  88. else if(bps_cnt == 9'd159)//能计满则表明起始位检测正确
  89. rx_done <= 1'b1;
  90. else
  91. rx_done <= 1'b0;
  92. always@(posedge Clk or negedge Rst_n)
  93. if(!Rst_n)
  94. uart_state <= 1'b0;
  95. else if(nedge)
  96. uart_state <= 1'b1;
  97. else if(rx_done || (bps_cnt == 9'd12 && (Start_bit > 2)))
  98. uart_state <= 1'b0;
  99. else
  100. uart_state <= uart_state;//结束、错误才为0,在接收时一直保持1
  101. //数据接收暂存
  102. always@(posedge Clk or negedge Rst_n)//
  103. if(!Rst_n)begin
  104. Start_bit <= 3'd0;
  105. r_data_byte[0] <= 3'd0;
  106. r_data_byte[1] <= 3'd0;
  107. r_data_byte[2] <= 3'd0;
  108. r_data_byte[3] <= 3'd0;
  109. r_data_byte[4] <= 3'd0;
  110. r_data_byte[5] <= 3'd0;
  111. r_data_byte[6] <= 3'd0;
  112. r_data_byte[7] <= 3'd0;
  113. Stop_bit <= 3'd0;
  114. end
  115. else if(bps_clk == 1'b1)
  116. case(bps_cnt)
  117. 0: begin
  118. Start_bit <= 3'd0;
  119. r_data_byte[0] <= 3'd0;
  120. r_data_byte[1] <= 3'd0;
  121. r_data_byte[2] <= 3'd0;
  122. r_data_byte[3] <= 3'd0;
  123. r_data_byte[4] <= 3'd0;
  124. r_data_byte[5] <= 3'd0;
  125. r_data_byte[6] <= 3'd0;
  126. r_data_byte[7] <= 3'd0;
  127. Stop_bit <= 3'd0;
  128. end//下次计数要复位
  129. //bps_clk为高电平时,bps_cnt才计数,在bps_cnt为指定值且bps_clk为高电平(已经是下一个)时才采样,则会滞后一个周期,即在bps_cnt为6时采样得到的是7对应的电平,因此可以将6改为5,得到6对应的电平,
  130. 5,6,7,8,9,10: Start_bit <= Start_bit + s1_Rs232_rx;//一个bps_cnt会维持多个系统时钟,在Clk上升沿触发条件下,一个状态多次被检测到,多次相加
  131. 21,22,23,24,25,26: r_data_byte[0] <= r_data_byte[0] + s1_Rs232_rx;
  132. 37,38,39,40,41,42: r_data_byte[1] <= r_data_byte[1] + s1_Rs232_rx;
  133. 53,54,55,56,57,58: r_data_byte[2] <= r_data_byte[2] + s1_Rs232_rx;
  134. 69,70,71,72,73,74: r_data_byte[3] <= r_data_byte[3] + s1_Rs232_rx;
  135. 85,86,87,88,89,90: r_data_byte[4] <= r_data_byte[4] + s1_Rs232_rx;
  136. 101,102,103,104,105,106: r_data_byte[5] <= r_data_byte[5] + s1_Rs232_rx;
  137. 117,118,119,120,121,122: r_data_byte[6] <= r_data_byte[6] + s1_Rs232_rx;
  138. 133,134,135,136,137,138: r_data_byte[7] <= r_data_byte[7] + s1_Rs232_rx;
  139. 149,150,151,152,153,154: Stop_bit <= Stop_bit + s1_Rs232_rx;
  140. default: begin
  141. Start_bit <= Start_bit;
  142. r_data_byte[0] <= r_data_byte[0];
  143. r_data_byte[1] <= r_data_byte[1];
  144. r_data_byte[2] <= r_data_byte[2];
  145. r_data_byte[3] <= r_data_byte[3];
  146. r_data_byte[4] <= r_data_byte[4];
  147. r_data_byte[5] <= r_data_byte[5];
  148. r_data_byte[6] <= r_data_byte[6];
  149. r_data_byte[7] <= r_data_byte[7];
  150. Stop_bit <= Stop_bit;
  151. end//其他情况保持不变(数据接收完后)
  152. endcase
  153. always@(posedge Clk or negedge Rst_n)
  154. if(!Rst_n)begin
  155. data_byte <= 8'd0;
  156. end
  157. else if(bps_cnt == 9'd159)begin
  158. data_byte[0] <= r_data_byte[0][2];//<3最高位为0;>3最高位为1,此处不考虑=3的恶劣情况
  159. data_byte[1] <= r_data_byte[1][2];
  160. data_byte[2] <= r_data_byte[2][2];
  161. data_byte[3] <= r_data_byte[3][2];
  162. data_byte[4] <= r_data_byte[4][2];
  163. data_byte[5] <= r_data_byte[5][2];
  164. data_byte[6] <= r_data_byte[6][2];
  165. data_byte[7] <= r_data_byte[7][2];
  166. end
  167. endmodule

uart_byte_rx_tb

  1. `timescale 1ns/1ns
  2. `define clk_period 20
  3. module uart_byte_rx_tb;
  4. reg Clk;
  5. reg Rst_n;
  6. wire [7:0]data_byte_r;
  7. wire rx_done;
  8. reg [7:0]data_byte_t;
  9. reg [2:0]baud_set;
  10. reg send_en;
  11. wire Rs232_tx;
  12. wire Tx_done;
  13. wire uart_state;
  14. uart_byte_rx uart_byte_rx(
  15. .Clk(Clk),
  16. .Rst_n(Rst_n),
  17. .Rs232_rx(Rs232_tx),
  18. .baud_set(baud_set),
  19. .data_byte(data_byte_r),
  20. .rx_done(rx_done)
  21. );
  22. uart_byte_tx uart_byte_tx(//发送模块产生数据,在tb中使用,工程没有使用,需要保存在该工程下同时setting中添加该文件
  23. .Clk(Clk),
  24. .Rst_n(Rst_n),
  25. .data_byte(data_byte_t),
  26. .baud_set(baud_set),
  27. .send_en(send_en),
  28. .Rs232_tx(Rs232_tx),
  29. .Tx_done(Tx_done),
  30. .uart_state(uart_state)
  31. );
  32. initial Clk = 1'b1;
  33. always#(`clk_period/2)Clk = ~Clk;
  34. initial begin
  35. Rst_n = 1'b0;
  36. data_byte_t = 8'd0;
  37. baud_set = 3'd4;
  38. send_en = 1'd0;
  39. #(`clk_period*20 + 1'b1)
  40. Rst_n = 1'b1;
  41. #(`clk_period*50)
  42. data_byte_t = 8'haa;
  43. send_en = 1'd1;
  44. #`clk_period;
  45. send_en = 1'd0;
  46. @(posedge Tx_done)
  47. #(`clk_period*5000);
  48. data_byte_t = 8'h55;
  49. send_en = 1'd1;
  50. #`clk_period;
  51. send_en = 1'd0;
  52. @(posedge Tx_done)
  53. #(`clk_period*5000);
  54. $stop;
  55. end
  56. endmodule

uart_byte_rx_top

  1. module uart_byte_rx_top(Clk,Rst_n,Rs232_rx);
  2. input Clk;
  3. input Rst_n;
  4. input Rs232_rx;
  5. reg [7:0]data_rx_r;//data_rx可能接收错误,rx_done时才将值赋到data_rx_r上
  6. wire rx_done;//不作为输出,内部信号作为赋值给data_rx_r的触发条件
  7. wire data_rx;//不作为输出,内部信号赋值给data_rx_r,再用探针
  8. uart_byte_rx uart_byte_rx(
  9. .Clk(Clk),
  10. .Rst_n(Rst_n),
  11. .Rs232_rx(Rs232_rx),
  12. .baud_set(3'd0),
  13. .data_byte(data_rx),
  14. .rx_done(rx_done)
  15. );
  16. issp issp(
  17. .probe(data_rx_r),//探针观测data_rx_r数据
  18. .source()
  19. );
  20. always@(posedge Clk or negedge Rst_n)
  21. if(!Rst_n)
  22. data_rx_r <= 8'd0;
  23. else if(rx_done)
  24. data_rx_r <= data_rx;
  25. endmodule

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

闽ICP备14008679号