基于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

以上。

posted @ 2017-11-11 16:07  小翁同学  阅读(6896)  评论(0编辑  收藏  举报