Uart 串口通訊協議接收設計

该博文介绍了一个UART串口通信协议的接收模块设计,针对工业环境中的干扰,通过接收中间6个最稳定的采样点来判断数据是1还是0,确保数据的准确性。设计包括状态机、波特率设置、分频计数器、亚稳态消除、边沿检测、数据采样等部分。
摘要由CSDN通过智能技术生成

因考慮到工業環境外界因素干擾,故將每位接收數據分為16等份,僅接收中間最穩定的6份相加最後再判斷是1或0

  1. module uart_rx(
  2.      clk,
  3.      rst,
  4.      baud_set, //波特率設置
  5.      rx,             //接收數據
  6.      data,         
  7.      done         //接收結束時done為1
  8. );
  9.  
  10. input  clk;
  11. input  rst;
  12. input  [2:0] baud_set;
  13. input  rx;
  14. output [7:0] data; 
  15. output done;
  16.  
  17. reg reg0_rx;
  18. reg reg1_rx;
  19. reg tmp0_rx;
  20. reg tmp1_rx;
  21. wire nedge;
  22. wire error;
  23. reg done;
  24. reg en;
  25. reg [8:0] div_cnt;
  26. reg [7:0] bps_cnt;
  27. reg [2:0] reg_data [9:0];
  28. wire [9:0] tmp_data;
  29. reg [7:0] data;
  30. reg [8:0] bps_DR;
  31.  
  32. //===========================================
  33. // 狀態機
  34. //===========================================
  35.  
  36. parameter   idle  = 1'b0,   //空閒
  37.                     trans = 1'b1; //接收數據
  38.  
  39. reg  present_state, next_state;
  40.  
  41. always@(posedge clk or negedge rst)
  42. begin
  43.      if(!rst)  present_state <= idle;
  44.      else     present_state <= next_state;
  45. end
  46.  
  47. always@(*)
  48. begin
  49.      case(present_state)
  50.      idle  : if(nedge) 
  51.                   next_state = trans;
  52.                 else   
  53.                   next_state = idle;
  54.      trans : if(div_cnt == 9'd324 && bps_cnt == 8'd159
  55.                     next_state = idle;
  56.                   else   
  57.                     next_state = trans;
  58.      endcase
  59. end
  60.  
  61. always@(posedge clk or negedge rst)
  62. begin
  63.     if(!rst) en <= 1'b0;
  64.     else
  65.     begin
  66.         case(present_state)
  67.         idle  :  en <= 1'b0;
  68.         trans :  en <= 1'b1;
  69.         endcase
  70.     end
  71. end
  72.  
  73. //===========================================
  74. // 波特率設置
  75. //===========================================
  76.  
  77. always@(posedge clk or negedge rst)
  78. begin
  79.     if(!rst)
  80.        bps_DR <= 9'd324;
  81.     else 
  82.     begin
  83.         case(baud_set)
  84.         0 : bps_DR <= 9'd324;       //9600 bps
  85.         1 : bps_DR <= 9'd162;       //19200 bps
  86.         2 : bps_DR <= 9'd80;         //38400 bps
  87.         3 : bps_DR <= 9'd53;         //57600 bps
  88.         4 : bps_DR <= 9'd26;         //115200 bps
  89.         default : bps_DR <= 9'd324;
  90.         endcase
  91.     end
  92. end
  93.  
  94. //===========================================
  95. // 分頻計數器
  96. //===========================================
  97.  
  98. always@(posedge clk or negedge rst)   
  99. begin
  100.     if(!rst)                                 div_cnt <= 9'd0;
  101.     else if(en & (~error))
  102.     begin
  103.         if(div_cnt == bps_DR)   div_cnt <= 9'd0;
  104.         else                                 div_cnt <= div_cnt + 9'd1;
  105.     end 
  106.     else                                     div_cnt <= div_cnt;
  107. end
  108.  
  109. always@(posedge clk or negedge rst)   
  110. begin
  111.     if(!rst)                                     bps_cnt <= 8'd0;
  112.     else if(div_cnt == bps_DR)
  113.     begin
  114.         if(bps_cnt == 8'd159)       bps_cnt <= 8'd0;
  115.         else                                    bps_cnt <= bps_cnt + 8'd1;
  116.     end
  117.     else                                        bps_cnt <= bps_cnt;
  118. end 
  119.  
  120. //===========================================
  121. // 除亞穩態
  122. //===========================================
  123.  
  124. always @(posedge clk)
  125. begin
  126.     reg0_rx <= rx;
  127.     reg1_rx <= reg0_rx;
  128. end
  129.  
  130. //===========================================
  131. // 邊沿檢測
  132. //===========================================
  133.  
  134. always @(posedge clk)
  135. begin
  136.     tmp0_rx <= reg1_rx;
  137.     tmp1_rx <= tmp0_rx;
  138. end
  139.  
  140. assign nedge = !tmp0_rx & tmp1_rx;  //下降沿檢測
  141.  
  142. //===========================================
  143. // 採樣中間段6位數據
  144. //===========================================
  145.  
  146. always@(posedge clk or negedge rst)   
  147. begin
  148.     if(!rst)
  149.     begin
  150.         reg_data[0] <= 3'd0;
  151.         reg_data[1] <= 3'd0;
  152.         reg_data[2] <= 3'd0;
  153.         reg_data[3] <= 3'd0;
  154.         reg_data[4] <= 3'd0;
  155.         reg_data[5] <= 3'd0;
  156.         reg_data[6] <= 3'd0;
  157.         reg_data[7] <= 3'd0;
  158.         reg_data[8] <= 3'd0;
  159.         reg_data[9] <= 3'd0;
  160.     end
  161.     else
  162.     begin
  163.         case(bps_cnt)
  164.         8'd6,8'd7,8'd8,8'd9,8'd10,8'd11                     : reg_data[0] <= reg_data[0] + tmp1_rx;
  165.         8'd22,8'd23,8'd24,8'd25,8'd26,8'd27             : reg_data[1] <= reg_data[1] + tmp1_rx;
  166.         8'd38,8'd39,8'd40,8'd41,8'd42,8'd43             : reg_data[2] <= reg_data[2] + tmp1_rx;
  167.         8'd54,8'd55,8'd56,8'd57,8'd58,8'd59             : reg_data[3] <= reg_data[3] + tmp1_rx;
  168.         8'd70,8'd71,8'd72,8'd73,8'd74,8'd75             : reg_data[4] <= reg_data[4] + tmp1_rx;
  169.         8'd86,8'd87,8'd88,8'd89,8'd90,8'd91             : reg_data[5] <= reg_data[5] + tmp1_rx;
  170.         8'd102,8'd103,8'd104,8'd105,8'd106,8'd107 : reg_data[6] <= reg_data[6] + tmp1_rx;
  171.         8'd118,8'd119,8'd120,8'd121,8'd122,8'd123 : reg_data[7] <= reg_data[7] + tmp1_rx;
  172.         8'd134,8'd135,8'd136,8'd137,8'd138,8'd139 : reg_data[8] <= reg_data[8] + tmp1_rx;
  173.         8'd150,8'd151,8'd152,8'd153,8'd154,8'd155 : reg_data[9] <= reg_data[9] + tmp1_rx;
  174.         default:;
  175.         endcase
  176.     end
  177. end
  178.  
  179. //===========================================
  180. // 若採樣的6位數據相加結果大於等於4則判斷為1,否則為0
  181. //===========================================
  182.  
  183. assign tmp_data[0] = (reg_data[0] >= 3'd4) ? 1'b1 : 1'b0;  //start bit起始位
  184.  
  185. assign tmp_data[1] = (reg_data[1] >= 3'd4) ? 1'b1 : 1'b0;
  186.  
  187. assign tmp_data[2] = (reg_data[2] >= 3'd4) ? 1'b1 : 1'b0;
  188.  
  189. assign tmp_data[3] = (reg_data[3] >= 3'd4) ? 1'b1 : 1'b0;
  190.  
  191. assign tmp_data[4] = (reg_data[4] >= 3'd4) ? 1'b1 : 1'b0;
  192.  
  193. assign tmp_data[5] = (reg_data[5] >= 3'd4) ? 1'b1 : 1'b0;
  194.  
  195. assign tmp_data[6] = (reg_data[6] >= 3'd4) ? 1'b1 : 1'b0;
  196.  
  197. assign tmp_data[7] = (reg_data[7] >= 3'd4) ? 1'b1 : 1'b0;
  198.  
  199. assign tmp_data[8] = (reg_data[8] >= 3'd4) ? 1'b1 : 1'b0;
  200.  
  201. assign tmp_data[9] = (reg_data[9] >= 3'd4) ? 1'b1 : 1'b0;  //stop bit停止位
  202.  
  203. //===========================================
  204. //若起始位為1時表示接收錯誤立即停止接收數據
  205. //===========================================
  206.  
  207. assign error = (tmp_data[0] == 1'b1) ?  1'b1 : 1'b0;
  208.  
  209. //===========================================
  210. // 數據接收結束done信號
  211. //===========================================
  212.  
  213. always@(posedge clk or negedge rst)   
  214. begin
  215.     if(!rst)
  216.        done <= 1'b0;
  217.     else if(bps_cnt == 8'd159)
  218.        done <= 1'b1;
  219.     else
  220.        done <= 1'b0;
  221. end
  222.  
  223. //==========================================
  224. // 將數據寄存起來最後輸出
  225. //==========================================
  226.  
  227. always@(posedge clk or negedge rst) 
  228. begin
  229.     if(!rst)
  230.        data <= 8'b0;
  231.     else if(div_cnt == bps_DR  &&  bps_cnt == 8'd159)
  232.        data <= tmp_data[8:1];
  233.     else 
  234.        data <= data;
  235. end
  236.  
  237. //===========================================
  238.  
  239. endmodule
  240.  
  241. //===========================================
  242. // 將發送模組與接收模組連接,測試是否能正確接收數據
  243. //===========================================
  244.  
  245. module uart_top(
  246.      clk,
  247.      rst,
  248.      baud_set,
  249.      in_data,
  250.      out_data,
  251.      tx_done,
  252.      rx_done
  253. );
  254.  
  255. input  clk;
  256. input  rst;
  257. input  [2:0] baud_set;  //波特率設置
  258. input  [7:0] in_data;     //輸入數據
  259. output [7:0] out_data; //輸出數據
  260. output tx_done;           //發送結束
  261. output rx_done;          //接收結束
  262.  
  263. wire w;
  264.  
  265. uart_tx uart_tx(
  266.     .rst(rst),
  267.     .clk(clk),
  268.     .baud_set(baud_set),
  269.     .din(in_data),     
  270.     .tx(w),      
  271.     .done(tx_done)     
  272. );
  273.  
  274. uart_rx uart_rx(
  275.     .clk(clk),
  276.     .rst(rst),
  277.     .baud_set(baud_set),
  278.     .rx(w),
  279.     .data(out_data),
  280.     .done(rx_done)
  281. );
  282.  
  283. endmodule


  1. // 仿真檔testbench
  2.  
  3. `timescale 1ns/100ps
  4.  
  5. module uart_top_test1;
  6. reg  clk;
  7. reg  rst;
  8. reg  [2:0] baud_set;
  9. reg  [7:0] in_data;
  10. wire [7:0] out_data;
  11. wire tx_done;
  12. wire rx_done;
  13.  
  14. uart_top uart_top(
  15.     .clk(clk),
  16.     .rst(rst),
  17.     .baud_set(baud_set),
  18.     .in_data(in_data),
  19.     .out_data(out_data),
  20.     .tx_done(tx_done),
  21.     .rx_done(rx_done)
  22. );
  23.  
  24. initial
  25. begin
  26.     clk = 1'b1;
  27.     forever #10 clk = ~clk; //clk頻率為50M Hz
  28. end
  29.  
  30. initial
  31. begin
  32.     #0  
  33.     rst = 1'b0
  34.     baud_set = 3'd0;  //設置為9600 bps
  35.     in_data = 8'b10101010;
  36.     #1  
  37.     rst = 1'b1;
  38.     #2000000 
  39.     $stop;
  40.     #10 
  41.     $finish;
  42. end
  43.  
  44. endmodule


在此特別將發送結束信號tx_done與接收結束信號rx_done採取不同寬度以方便區分,

發送數據為10101010,接收數據為10101010,故接收正確!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值