基于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'd144)) 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
以上。