//////////////////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
以上。