• uart协议--Verilog及仿真


    1、协议原理:

    UART(universal asynchronous receiver-transmitter)通用异步收发传输器。

    uart串口通信需要两根信号线来实现,一根用于串口发送,一根用于串口接收。一开始高电平,然后拉低表示开始位,接着8个数据位,最后拉高表示停止位,并且进入空闲状态,等待下一次的数据传输。

     因为uart通信没有时钟,因此只能规定多少时间发送一个二进制位来保证数据收发不会出错,这就是波特率。这里时钟频率50MHz,波特率9600bps,因此发送一个二进制位需要(50_000_000/9600=5208)个时钟,换言之,计数到5208就发送一位二进制。


    2、协议代码:

    代码由顶层模块、接收模块和发送模块构成。其中仿真的代码是仿真通过接收模块接收数据,再发送出来。同样串口调试助手也是通过接收模块接收数据,然后再发出来。

    顶层模块:

     1 module uart_top(
     2 input sys_clk,
     3 input sys_rst_n,
     4 input uart_recv,
     5 output uart_send
     6 );
     7     
     8 wire [7:0]data;
     9 wire data_en;
    10 
    11 uart_recv  
    12 #(
    13 .BPS_CNT  (52)           //仿真用的,串口调试不用直接删掉!
    14 )
    15 u_uart_recv
    16 (
    17     .sys_clk          (sys_clk),
    18     .sys_rst_n        (sys_rst_n),
    19     .data_in_recv     (uart_recv),
    20     .data_out_recv    (data),
    21     .data_en          (data_en)
    22 );
    23 
    24 uart_send 
    25 #(
    26 .BPS_CNT  (52)          //仿真用的,串口调试不用直接删掉!
    27 )
    28 u_uart_send
    29 (
    30     .sys_clk          (sys_clk),
    31     .sys_rst_n        (sys_rst_n),
    32     .data_en          (data_en),
    33     .data_in_send     (data),
    34     .data_out_send    (uart_send)
    35 );
    36 endmodule 

    接收模块:

      1 module uart_recv
      2 (
      3 input sys_clk,
      4 input sys_rst_n,
      5 input data_in_recv,
      6 output reg[7:0]data_out_recv,
      7 output reg data_en
      8 );
      9 parameter CLK=50_000_000;
     10 parameter UART_BPS=9600;
     11 parameter BPS_CNT=CLK/UART_BPS;
     12 reg data_in_recv_d0;
     13 reg data_in_recv_d1;
     14 reg [15:0]bps_cnt;
     15 reg [3:0]bit_cnt;
     16 reg [7:0]data;
     17 reg flag;
     18 wire start_flag;
     19 
     20 always @(posedge sys_clk or negedge sys_rst_n)begin
     21 if(!sys_rst_n)begin
     22 data_in_recv_d0<=1'b0;
     23 data_in_recv_d1<=1'b0;
     24 end
     25 else begin
     26 data_in_recv_d0<=data_in_recv;
     27 data_in_recv_d1<=data_in_recv_d0;
     28 end
     29 end
     30 assign start_flag=data_in_recv_d1 & (~data_in_recv_d0);
     31 
     32 
     33 always @(posedge sys_clk or negedge sys_rst_n)begin
     34 if(!sys_rst_n)
     35 flag<=1'b0;
     36 else if(start_flag)
     37 flag<=1'b1;
     38 else if((bit_cnt==9)&&(bps_cnt==BPS_CNT/2))
     39 flag<=1'b0;
     40 else
     41 flag<=flag;
     42 end
     43 
     44 always @(posedge sys_clk or negedge sys_rst_n)begin
     45 if(!sys_rst_n)begin
     46 bps_cnt<=16'd0;
     47 bit_cnt<=4'd0;
     48 end
     49 else if(flag)begin
     50 if(bps_cnt<BPS_CNT-1)begin
     51 bps_cnt<=bps_cnt+1'b1;
     52 bit_cnt<=bit_cnt;
     53 end
     54 else begin
     55 bps_cnt<=16'd0;
     56 bit_cnt<=bit_cnt+1;
     57 end
     58 end
     59 else begin
     60 bps_cnt<=16'd0;
     61 bit_cnt<=4'd0;
     62 end
     63 end
     64 
     65 always @(posedge sys_clk or negedge sys_rst_n) begin 
     66     if ( !sys_rst_n)  
     67         data <= 8'd0;                                     
     68     else if(flag)                            
     69         if (bps_cnt == BPS_CNT/2) begin         
     70             case ( bit_cnt )
     71              4'd1 : data[0] <= data_in_recv_d1;   
     72              4'd2 : data[1] <= data_in_recv_d1;
     73              4'd3 : data[2] <= data_in_recv_d1;
     74              4'd4 : data[3] <= data_in_recv_d1;
     75              4'd5 : data[4] <= data_in_recv_d1;
     76              4'd6 : data[5] <= data_in_recv_d1;
     77              4'd7 : data[6] <= data_in_recv_d1;
     78              4'd8 : data[7] <= data_in_recv_d1;   
     79              default:;                                    
     80             endcase
     81         end
     82         else 
     83             data <= data;
     84     else
     85         data <= 8'd0;
     86 end
     87 
     88 always @(posedge sys_clk or negedge sys_rst_n)begin
     89 if(!sys_rst_n)begin
     90 data_out_recv<=8'd0;
     91 data_en<=1'b0;
     92 end
     93 else if(bit_cnt==9)begin
     94 data_out_recv<=data;
     95 data_en<=1'b1;
     96 end
     97 else begin
     98 data_en<=1'b0;
     99 end
    100 end
    101 endmodule 

    发送模块:

     1 module uart_send
     2 (
     3 input sys_clk,
     4 input sys_rst_n,
     5 input data_en,
     6 input [7:0]data_in_send,
     7 output reg data_out_send
     8 );
     9 parameter CLK=50_000_000;
    10 parameter UART_BPS=9600;
    11 parameter BPS_CNT=CLK/UART_BPS;
    12 reg [7:0]tem_data;
    13 reg [15:0]bps_cnt;
    14 reg [3:0]bit_cnt;
    15 reg send_flag;
    16 
    17 always @(posedge sys_clk or negedge sys_rst_n)begin
    18 if(!sys_rst_n)
    19 send_flag<=1'b0;
    20 else if(data_en)begin
    21 tem_data<=data_in_send;
    22 send_flag<=1'b1;
    23 end
    24 else if((bit_cnt==4'd9)&&(bps_cnt==BPS_CNT/2))begin
    25 tem_data<=8'd0;
    26 send_flag<=1'b0;
    27 end
    28 else begin
    29 tem_data<=tem_data;
    30 send_flag<=send_flag;
    31 end
    32 end
    33 
    34 always @(posedge sys_clk or negedge sys_rst_n)begin
    35 if(!sys_rst_n)begin
    36 bps_cnt<=16'd0;
    37 bit_cnt<=4'd0;
    38 end
    39 else if(send_flag)begin
    40 if(bps_cnt<BPS_CNT-1)begin
    41 bps_cnt<=bps_cnt+1'b1;
    42 bit_cnt<=bit_cnt;
    43 end
    44 else begin
    45 bps_cnt<=16'd0;
    46 bit_cnt<=bit_cnt+1'b1;
    47 end
    48 end
    49 else begin
    50 bps_cnt<=16'd0;
    51 bit_cnt<=4'd0;
    52 end
    53 end
    54 
    55 always @(posedge sys_clk or negedge sys_rst_n) begin        
    56     if (!sys_rst_n)  
    57         data_out_send <= 1'b1;        
    58     else if (send_flag)
    59         case(bit_cnt)
    60             4'd0: data_out_send <= 1'b0;         
    61             4'd1: data_out_send <= tem_data[0];  
    62             4'd2: data_out_send <= tem_data[1];
    63             4'd3: data_out_send <= tem_data[2];
    64             4'd4: data_out_send <= tem_data[3];
    65             4'd5: data_out_send <= tem_data[4];
    66             4'd6: data_out_send <= tem_data[5];
    67             4'd7: data_out_send <= tem_data[6];
    68             4'd8: data_out_send <= tem_data[7];   
    69             4'd9: data_out_send <= 1'b1;       
    70             default: ;
    71         endcase
    72     else 
    73         data_out_send <= 1'b1;                  
    74 end
    75 endmodule 

    仿真:

     1 `timescale 1ns/1ns 
     2 module uart_top_tb;
     3 reg                         sys_clk                 ; 
     4 reg                         sys_rst_n              ; 
     5 reg                         uart_recv             ;
     6 wire                        uart_send           ;
     7 
     8 uart_top u_uart_top
     9 (
    10     .sys_clk                    (sys_clk                ),
    11     .sys_rst_n                  (sys_rst_n              ),
    12     .uart_recv                (uart_recv            ),
    13     .uart_send                (uart_send            )
    14 );
    15 
    16 initial begin
    17     sys_clk = 1;
    18 end
    19 always #10 sys_clk = ~sys_clk;
    20 
    21 initial begin
    22     sys_rst_n = 0; 
    23    #30 sys_rst_n = 1;
    24 end
    25 
    26 reg  [7:0]              mem[15:0]           ; 
    27 integer                 i                         ;
    28 integer                 j                         ;
    29 
    30 
    31 initial $readmemh("./data.txt",mem);
    32 
    33 task bit_cnt
    34 (
    35     input [7:0]         data
    36 );
    37     begin
    38         for(i=0;i<=9;i=i+1) begin   //10?bit?
    39             case(i)
    40                  0: uart_recv = 1'b0;
    41                  1: uart_recv = data[i-1];
    42                  2: uart_recv = data[i-1];
    43                  3: uart_recv = data[i-1];
    44                  4: uart_recv = data[i-1];
    45                  5: uart_recv = data[i-1];
    46                  6: uart_recv = data[i-1];
    47                  7: uart_recv = data[i-1];
    48                  8: uart_recv = data[i-1];
    49                  9: uart_recv = 1'b1;
    50             endcase
    51             #1040; 
    52         end        
    53     end
    54 endtask
    55 
    56 task rx_byte;
    57     begin
    58         for(j=0;j<=15;j=j+1) 
    59             bit_cnt(mem[j]);
    60     end
    61 endtask
    62 
    63 initial begin
    64     # 401 rx_byte();
    65 end
    66 
    67 initial begin
    68     #180000;
    69     $stop;
    70 end
    71 endmodule

     仿真的时候,在sim目录下建立一个data.txt存放宽度8位,深度16位的文件,然后仿真接收这个文件,然后发出这个文件。

    这里的数字是十六进制,比如8'h00  8'h01...

    仿真结果以及串口调试结果:

    暂时还没有解惑的地方:

    ①不明白作者为什么在仿真的时候,顶层模块这里需要有一个52?

    #(
    .BPS_CNT (52) //仿真用的,串口调试不用直接删掉!
    )

    ②根据接收模块最后的代码可以知道,当接收成功每一个字(8'h00  8'h01...)的所有二进制位,data_en就会被拉高,前面的8'h00  8'h01...到8'h0e,一直都是接收完之后就拉高data_en,然而为什么到了最后一个字8'h0f就没有出现了?

    参考文章:https://www.cnblogs.com/xianyufpga/p/11086676.html

  • 相关阅读:
    java 多线程
    构造N位格雷码(递归,面向对象)
    字典树trie
    快速排序
    C++ 链表
    15-谜问题(深拷贝、LC检索、面向对象编程)
    [编程题] 扫描透镜(本题还涉及如何从字符串中提取数字)
    python爬虫提取冰与火之歌五季的种子
    带有限期和效益的单位时间的作业排序贪心算法
    0/1背包问题与动态规划
  • 原文地址:https://www.cnblogs.com/FPGAer/p/13788424.html
Copyright © 2020-2023  润新知