• 简单UART的verilog实现


    下面摘录我写的简单的UART代码,对于灵活性和健壮性做了如下设计:

    1、系统时钟及串口波特率以参数形式输入,例化时可以灵活设置

    2、接受模块在起始位会检测中点电平是否仍然为低,否则判定为抖动

    接收机代码

     1 `timescale 1ns/1ps
     2 
     3 // 系统时钟200MHz,波特率115200
     4 module uart_rx  #(
     5     parameter BAUDRATE = 115200, 
     6     parameter FREQ = 200_000_000)(
     7     input clk, nrst,
     8     input rx,
     9     output reg [7:0] rdata,
    10     output reg vld
    11     );
    12 
    13     localparam T = FREQ / BAUDRATE;
    14 
    15     // flag接受处理标志位,为1表明当前处于接受状态
    16     reg flag;
    17     always @(posedge clk or negedge nrst) begin
    18         if(nrst == 0)
    19             flag <= 0; 
    20         else if(flag == 0 && rx == 0)
    21             flag <= 1;
    22         else if(cnt_bit == 1 - 1 && cnt_clk == T / 2 - 1 && rx == 1)
    23             flag <= 0;
    24         else if(end_cnt_bit)
    25             flag <= 0;
    26     end
    27     
    28     // 两层计数结构,cnt_clk计数每一位所占的时钟数,cnt_bit计数1个开始位,8个数据位,一个停止位,共10位
    29     reg [3:0] cnt_bit;
    30     reg [31:0] cnt_clk;
    31     assign end_cnt_clk = cnt_clk == T - 1;
    32     assign end_cnt_bit = end_cnt_clk && cnt_bit == 10 - 1;
    33     
    34     always @(posedge clk or negedge nrst) begin
    35         if(nrst == 0)
    36             cnt_clk <= 0;
    37         else if(flag) begin
    38             if(end_cnt_clk)
    39                 cnt_clk <= 0;
    40             else
    41                 cnt_clk <= cnt_clk + 1'b1;
    42         end
    43         else
    44             cnt_clk <= 0;
    45     end
    46     
    47     always @(posedge clk or negedge nrst) begin
    48         if(nrst == 0)
    49             cnt_bit <= 0;
    50         else if(end_cnt_clk) begin
    51             if(end_cnt_bit)
    52                 cnt_bit <= 0;
    53             else
    54                 cnt_bit <= cnt_bit + 1'b1;
    55         end
    56     end    
    57     
    58     // 读数据及数据有效指示信号
    59     always @(posedge clk or negedge nrst) begin
    60         if(nrst == 0)
    61             rdata <= 0;
    62         else if(cnt_clk == T / 2 - 1 && cnt_bit != 1 - 1 && cnt_bit != 10 - 1)
    63             rdata[cnt_bit - 1] <= rx;
    64     end
    65     
    66     always @(posedge clk or negedge nrst) begin
    67         if(nrst == 0)
    68             vld <= 0;
    69         else if(end_cnt_bit)
    70             vld <= 1;
    71         else
    72             vld <= 0;
    73     end
    74     
    75 endmodule

    发送机代码

     1 `timescale 1ns/1ps
     2 
     3 // 系统时钟200MHz,波特率115200,带忙闲指示信号rdy
     4 module uart_tx #(
     5     parameter BAUDRATE = 115200, 
     6     parameter FREQ = 200_000_000)(
     7     input clk, nrst,
     8     input wrreq,
     9     input [7:0] wdata,
    10     output reg tx,
    11     output reg rdy
    12     );
    13     
    14     reg [3:0] cnt_bit;
    15     reg [31:0] cnt_clk;
    16     
    17     localparam T = FREQ / BAUDRATE;
    18 
    19     // 有写请求时将rdy信号拉底,待到数据发送完毕再将信号拉
    20     always @(posedge clk or negedge nrst) begin
    21         if(nrst == 0)
    22             rdy <= 1;
    23         else if(wrreq)
    24             rdy <= 0;
    25         else if(end_cnt_bit)
    26             rdy <= 1;
    27     end
    28     
    29     // 两层计数结构,cnt_clk计数每一位所占的时钟数,cnt_bit计数1个开始位,8个数据位,一个停止位,共10位
    30     wire end_cnt_clk;
    31     wire end_cnt_bit;
    32     assign end_cnt_clk = cnt_clk == T - 1;
    33     assign end_cnt_bit = end_cnt_clk && cnt_bit == 10 - 1;
    34     
    35     always @(posedge clk or negedge nrst) begin
    36         if(nrst == 0)
    37             cnt_clk <= 0;
    38         else if(rdy == 0) begin
    39             if(end_cnt_clk)
    40                 cnt_clk <= 0;
    41             else
    42                 cnt_clk <= cnt_clk + 1'b1;
    43         end
    44     end
    45     
    46     always @(posedge clk or negedge nrst) begin
    47         if(nrst == 0)
    48             cnt_bit <= 0;
    49         else if(end_cnt_clk) begin
    50             if(end_cnt_bit)
    51                 cnt_bit <= 0;
    52             else
    53                 cnt_bit <= cnt_bit + 1'b1;
    54         end
    55     end
    56     
    57     // 先发送一个起始位0,然后8位数据位,最后是停止位1
    58     always @(posedge clk or negedge nrst) begin
    59         if(nrst == 0)
    60             tx <= 1;
    61         else if(rdy == 0 && cnt_clk == 0) begin
    62             if(cnt_bit == 1 - 1)
    63                 tx <= 0;
    64             else if(cnt_bit == 10 - 1)
    65                 tx <= 1;
    66             else
    67                 tx <= wdata[cnt_bit - 1];
    68         end
    69     end
    70     
    71 endmodule

    在Xilinx Artix-7平台上验证的顶层代码

     1 `timescale 1ns / 1ps
     2 
     3 module uart_top(
     4     input clk_p, clk_n, nrst,
     5     input rx,
     6     output tx
     7     );
     8     
     9     localparam BAUDRATE = 115200;
    10     localparam FREQ = 200_000_000;
    11     
    12     // 差分时钟信号转为单端信号
    13     IBUFGDS #(
    14         .DIFF_TERM("FALSE"),
    15         .IBUF_LOW_PWR("TRUE"),
    16         .IOSTANDARD("DEFAULT")
    17     )  IBUFGDS_inst(
    18         .O(clk),
    19         .I(clk_p),
    20         .IB(clk_n)
    21     );
    22     
    23     wire [7:0] data;
    24     wire vld;
    25     
    26     uart_rx #(BAUDRATE, FREQ) uart_rx_u(
    27     .clk    (clk    ),
    28     .nrst    (nrst    ),
    29     .rx        (rx        ),
    30     .rdata    (data    ),
    31     .vld    (vld    )
    32     );
    33     
    34     uart_tx #(BAUDRATE, FREQ) uart_tx_u(
    35     .clk    (clk    ),
    36     .nrst    (nrst    ),
    37     .wrreq    (vld    ),
    38     .wdata    (data    ),
    39     .tx        (tx        ),
    40     .rdy    (        )
    41     );
    42     
    43     ila_0 ila_0_u(
    44     .clk     (clk    ), 
    45     .probe0  (nrst   ),
    46     .probe1  ({tx,rx}),
    47     .probe2  (data   ),
    48     .probe3  (vld    )
    49     );
    50     
    51 endmodule
  • 相关阅读:
    SQL Server 2012提供的OFFSET/FETCH NEXT与Row_Number()对比测试
    sql 知识点
    javascript基础拾遗——词法作用域
    Linux 软件包管理
    涉略spring
    WebReBuild年会流水记
    javascript面向对象学习笔记(一)——继承
    算法学习——动态规划策略入门
    编程之美读书笔记——2.3寻找水王
    Linux 引导流程解析
  • 原文地址:https://www.cnblogs.com/qingkai/p/7729621.html
Copyright © 2020-2023  润新知