基於FPGA的UART協議實現(通過線性序列機)


//////////////////2018/10/15 更新源代碼;
實現uart這東西其實早就寫了,不過不太完善,對於一個完美主義者來說,必須解決掉它。
1.什么是UART?
       通用異步收發傳輸器(Universal Asynchronous Receiver/Transmitter),通常稱作UART,是一種異步收發傳輸器。是異步通信協議。
       特性:兩根線,全雙工,異步通信,速度較慢。
2.什么是RS232?
RS232是物理層的電氣接口要求。是一種接口標准。uart可以使用rs232物理層來通信。總的來說,對於一項通信任務,通信協議可以使用UART協議,而UART協議可以通過COM端口來實現硬件連線,此協議下的傳輸方式可以選用RS232或者RS485等。
開發板上的是:
UART實現方式:狀態機或者線性序列機。
3.什么叫線性序列機?
當知曉信號在每個時刻的改變情況,那么就可以用計數器去擬合信號變化,比如在cnt=5的時候信號變1了,cnt=8的時候信號變0;當然這是可以自定義的。
簡單的測試邏輯(回環測試):
以下通過線性序列機實現:
首先看看uart協議的數據格式:信號線上空閑的時候為高電平,當出現下跳到低電平的時候表示數據的起始位,接着的是低位在前高位在后的數據流,尾部可加奇偶校驗位,最后加停止位,停止位長度可以定義。本例實現無奇偶校驗位,1bit停止位,波特率可改變。

編碼實現:
波特率產生,波特率選擇。波特率模塊塞tx以及rx模塊中了。rx中的采樣時鍾要比波特率時鍾快16倍,實現在數據中間采樣,避免采到錯誤的數據。
什么叫波特率?
9600bps/s:表示1s信號可以傳輸9600bit的數據。
波特率與FPGA時鍾關系:
總計數等於系統頻率除以波特率。比如50m/9600=5208;
rtl圖:

 

回環測試綜合資源使用情況以及糟糕條件下的Fmax: 

通過串口助手測試: 發送ab回傳ab顯示。

測試ok。
 
代碼:
  1 ///////uart 發送模塊;
  2 module  uart_tx (
  3         input    wire             i_clk            , //100MHZ;
  4         input    wire             i_rst_n          ,
  5         input    wire             i_send_en        , //打開發送;
  6         input    wire    [7:0]    i_data_i         ,
  7         output   wire             o_tx             ,
  8         output   wire             o_tx_done          //發送完成指示;
  9 );
 10 /////////////////波特率選擇;
 11 parameter [14:0] BPS_CNT_MAX = 100_000_000/115200;  //時鍾根據需要修改;
 12 //parameter [14:0] BPS_CNT_MAX = 15'd2; //仿真使用2;縮短仿真時間;
 13 reg [1:0] r_i_send_en; //同步兩拍;
 14 always @(posedge i_clk) begin
 15     r_i_send_en <= {r_i_send_en[0],i_send_en};
 16 end 
 17 reg [7:0] tx_data;
 18 always @(posedge i_clk or negedge i_rst_n) begin
 19     if (~i_rst_n) begin
 20         tx_data <= 0;
 21     end //if
 22     else begin
 23         if (r_i_send_en[1]) begin
 24             tx_data <= i_data_i;
 25         end  
 26         else begin
 27             tx_data <= tx_data;  
 28         end  
 29     end //else
 30 end //always
 31 reg tx_en; //整個發送區間計數使能;
 32 reg [14:0] bps_cnt;
 33 reg [3:0] cnt;
 34 always @(posedge i_clk or negedge i_rst_n) begin
 35     if (~i_rst_n) begin
 36         tx_en <= 0;
 37     end //if
 38     else begin
 39         if (r_i_send_en[1]) begin
 40             tx_en <= 1'b1;
 41         end   
 42         else begin
 43             if ((cnt == 4'd10) && (bps_cnt == (BPS_CNT_MAX - 15'd1))) begin
 44                 tx_en <= 1'b0;
 45             end
 46         end
 47     end //else
 48 end //always
 49 always @(posedge i_clk or negedge i_rst_n) begin
 50     if (~i_rst_n) begin
 51         bps_cnt <= 0;
 52     end //if
 53     else begin
 54         if (tx_en) begin
 55             if (bps_cnt == (BPS_CNT_MAX - 15'd1)) begin
 56                 bps_cnt <= 0;
 57             end
 58             else begin
 59                 bps_cnt <= bps_cnt + 15'd1;
 60             end
 61         end 
 62         else begin
 63             bps_cnt <= 0;  
 64         end   
 65     end //else
 66 end //always
 67 always @(posedge i_clk or negedge i_rst_n) begin
 68     if (~i_rst_n) begin
 69         cnt <= 0;
 70     end //if
 71     else begin
 72         if (tx_en) begin
 73             if (bps_cnt == (BPS_CNT_MAX - 15'd1)) begin
 74                 cnt <= cnt + 4'd1; //bps計數到最大值則cnt加1;
 75             end
 76         end 
 77         else begin
 78             cnt <= 0;       
 79         end   
 80     end //else
 81 end //always
 82 reg tx_done;
 83 reg tx;
 84 always @(posedge i_clk) begin
 85     case (cnt)
 86         0 : begin tx <= 1'b1;tx_done <= 1'b0; end //tx默認為高電平;
 87         1 : begin tx <= 1'b0; end
 88         2 : begin tx <= tx_data[0]; end
 89         3 : begin tx <= tx_data[1]; end
 90         4 : begin tx <= tx_data[2]; end
 91         5 : begin tx <= tx_data[3]; end
 92         6 : begin tx <= tx_data[4]; end
 93         7 : begin tx <= tx_data[5]; end
 94         8 : begin tx <= tx_data[6]; end
 95         9 : begin tx <= tx_data[7]; end
 96         10: begin tx <= 1'b1;tx_done <= 1'b1;end //拉高tx,產生發送完成指示信號;
 97         default:  begin tx <= 1'b1;tx_done <= 1'b0; end
 98     endcase //case
 99 end //always
100 assign o_tx = tx;
101 assign o_tx_done = tx_done;
102 
103 endmodule
 1 ////////uart 接收模塊;
 2 module uart_rx (
 3     input     wire             i_clk                , //100M;
 4     input     wire             i_rst_n              ,
 5     input     wire             i_rx                 ,
 6     output    wire             o_rx_finish          ,
 7     output    wire    [7:0]    o_rx_data           
 8 );
 9 /////////////////波特率選擇;默認115200bps/s;
10 parameter [14:0] p_bps_max = 100_000_000/115200/16; 
11 reg [1:0] r_rx;
12 always @(posedge i_clk) begin
13     r_rx <= {r_rx[0],i_rx};
14 end
15 reg [14:0] r_bps_cnt;
16 reg [7:0] r_position_cnt;
17 reg r_cnt_en;
18 always @(posedge i_clk,negedge i_rst_n) begin 
19     if (~i_rst_n) begin
20         r_cnt_en <= 0;
21     end //if
22     else begin
23         if (r_rx == 2'b10) begin
24             r_cnt_en <= 1'b1;
25         end
26         else begin
27             if (((r_position_cnt == 8'd7) && (r_rx[1])) || (r_position_cnt == 8'd159)) begin
28                 r_cnt_en <= 1'b0;
29             end
30         end
31     end //else
32 end //always
33 always @(posedge i_clk,negedge i_rst_n) begin
34     if (~i_rst_n) begin
35         r_bps_cnt <= 0;
36     end //if
37     else begin
38         if (r_cnt_en) begin
39             if (r_bps_cnt == (p_bps_max -15'd1)) begin
40                 r_bps_cnt <= 0;
41             end
42             else begin
43                 r_bps_cnt <= r_bps_cnt + 15'd1;
44             end
45         end
46         else begin
47             r_bps_cnt <= 0;
48         end
49     end //else
50 end //always
51 ////////////位置計數邏輯;
52 always @(posedge i_clk,negedge i_rst_n) begin
53     if (~i_rst_n) begin
54         r_position_cnt <= 0;
55     end //if
56     else begin
57         if (r_cnt_en) begin
58             if (r_bps_cnt == (p_bps_max-15'd1)) begin
59                 r_position_cnt <= r_position_cnt + 8'd1;
60             end
61         end
62         else begin
63             r_position_cnt <= 0;
64         end
65     end //else
66 end //always
67 reg [7:0] r_rx_data;
68 always @(posedge i_clk,negedge i_rst_n) begin
69     if (~i_rst_n) begin
70         r_rx_data <= 0;
71     end //if
72     else begin
73         case (r_position_cnt)
74             15'd23:  begin r_rx_data[0] <= r_rx[1]; end  
75             15'd39:  begin r_rx_data[1] <= r_rx[1]; end  
76             15'd55:  begin r_rx_data[2] <= r_rx[1]; end  
77             15'd71:  begin r_rx_data[3] <= r_rx[1]; end  
78             15'd87:  begin r_rx_data[4] <= r_rx[1]; end  
79             15'd103: begin r_rx_data[5] <= r_rx[1]; end  
80             15'd119: begin r_rx_data[6] <= r_rx[1]; end  
81             15'd135: begin r_rx_data[7] <= r_rx[1]; end  
82           default: ;
83         endcase
84     end //else
85 end //always
86 
87 assign o_rx_finish = (r_position_cnt >= 15'd139) ? 1'b1 : 1'b0;
88 assign o_rx_data = r_rx_data;
89 
90 endmodule // end the uart_rx model;

top.v就不貼了,勿做商業用途。

舊版工程完整源代碼可在碼雲中查看和下載:https://gitee.com/kingstacker/uart

以上。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM