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

    以上。

  • 相关阅读:
    JavaScript数据结构和算法----队列
    JavaScript数据结构和算法----栈
    ES6箭头函数
    JavaScript的错误处理
    easing--缓动函数--贝塞尔函数--圆盘转动抽奖应用
    node之子线程child_process模块
    node上传文件并在网页中展示
    Python内置函数之int()
    从Python的角度来看编码与解码
    关于.pyc文件
  • 原文地址:https://www.cnblogs.com/kingstacker/p/7819258.html
Copyright © 2020-2023  润新知