【FPGA】UART串口通信

一、UART基础知识

UART 是一种采用异步串行通信方式的通用异步收发传输器
UART串口通信需要两根信号线来实现,一根用于串口发送,另外一根负责串口接收
在这里插入图片描述
传输速率:串口通信的速率用波特率表示,常用的波特率有9600、19200、38400、57600以及115200等。

四、代码

在这里插入图片描述

三、代码

//参数定义
//波特率
`define  BAUD_9600   5208
`define  BAUD_19200  2604
`define  BAUD_38400  1302
`define  BAUD_115200 434

`define STOP_BIT  1'b1      //数据停止位
`define START_BIT 1'b0      //数据开始位

uart_test

module uart_test( 
    input				clk		    ,
    input				rst_n	    ,
    input				uart_rxd	,
    output              uart_txd	
);								 
    //参数定义			 
                        
    //中间信号定义
    //control-->uart_tx
    wire            [7:0]               rx_dout     ;
    wire                                rx_dout_vld ;
    //uart_rx-->control
    wire            [7:0]               tx_din      ;
    wire                                tx_din_vld  ;
    //uart_tx-->control
    wire                                busy        ;

    //模块例化
    control u_control
    (
        /*input                       */.clk             (clk           ),
        /*input                       */.rst_n           (rst_n         ),
        /*input      [7:0]            */.byte_din        (rx_dout       ),
        /*input                       */.byte_din_vld    (rx_dout_vld   ),
        /*input                       */.busy            (busy          ),
        /*output    [7:0]             */.byte_dout       (tx_din        ),
        /*output                      */.byte_dout_vld   (tx_din_vld    )
    );

    uart_rx u_uart_rx
    (
        /*input                       */.clk         (clk               ),
        /*input                       */.rst_n       (rst_n             ),
        /*input                       */.rx_din      (uart_rxd          ),
        /*input           [1:0]       */.baud_sel    (2'b0              ),
        /*output          [7:0]       */.rx_byte     (rx_dout           ),
        /*output                      */.rx_byte_vld (rx_dout_vld       )
    );

    uart_tx u_uart_tx
    (
        /*input                       */.clk         (clk               ),
        /*input                       */.rst_n       (rst_n             ),
        /*input           [1:0]       */.baud_sel    (2'b0              ),
        /*input           [7:0]       */.tx_byte     (tx_din            ),
        /*input                       */.tx_byte_vld (tx_din_vld        ),
        /*output                      */.tx_dout     (uart_txd          ),
        /*output                      */.busy        (busy              )
    );


                        
endmodule

control

module control 
(
    input                       clk             ,
    input                       rst_n           ,
    input        [7:0]          byte_din        ,
    input                       byte_din_vld    ,
    input                       busy            ,
    output       [7:0]          byte_dout       ,
    output                      byte_dout_vld  
);

//信号定义

    reg         [7:0]           rxfifo_data         ;
    reg                         rxfifo_data_vld     ;    
    reg                         rxfifo_wrreq_flag   ;

//rxfifo
    wire        [7:0]           rxfifo_din          ;
    wire                        rxfifo_rdreq        ;
    wire                        rxfifo_wrreq        ;
    wire                        rxfifo_empty        ;
    wire                        rxfifo_full         ;
    wire        [7:0]           rxfifo_dout         ;
    wire        [7:0]           rxfifo_usedw        ;

    //rxfifo_data  数据寄存
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            rxfifo_data <= 0;
        end 
        else if(byte_din_vld)begin 
            rxfifo_data <= byte_din;
        end 
        else begin 
            rxfifo_data <= rxfifo_data;
        end 
    end
    //rxfifo_data_vld 
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            rxfifo_data_vld <= 0;
        end 
        else begin 
            rxfifo_data_vld <= byte_din_vld;
        end 
    end


    //rxfifo_wrreq_flag   当fifo存储数据大于5,fifo存储的数据全部输出
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            rxfifo_wrreq_flag <= 0;
        end 
        else if(rxfifo_usedw > 5)begin 
            rxfifo_wrreq_flag <= 1;
        end 
        else if(rxfifo_empty)begin
            rxfifo_wrreq_flag <= 0;
        end
    end


//模块例化
//rxfifo
    rxfifo	u_rxfifo (
    	.aclr  ( ~rst_n       ),
    	.clock ( clk          ),
    	.data  ( rxfifo_din   ),
    	.rdreq ( rxfifo_rdreq ),
    	.wrreq ( rxfifo_wrreq ),
    	.empty ( rxfifo_empty ),
    	.full  ( rxfifo_full  ),
    	.q     ( rxfifo_dout  ),
    	.usedw ( rxfifo_usedw )
    	);

    assign rxfifo_din = rxfifo_data;
    assign rxfifo_wrreq = rxfifo_data_vld && !rxfifo_full;
    assign byte_dout = rxfifo_dout;
    assign rxfifo_rdreq = !rxfifo_empty && (rxfifo_wrreq_flag) && (busy == 0);
    assign byte_dout_vld = rxfifo_rdreq;

endmodule

uart_rx

`include "param.v"
module uart_rx
(
    input                       clk         ,
    input                       rst_n       ,
    input                       rx_din      ,
    input           [1:0]       baud_sel    ,
    output          [7:0]       rx_byte     ,
    output                      rx_byte_vld 
);
    //信号定义
    reg         [12:0]          cnt_baud        ;
    wire                        add_cnt_baud    ;
    wire                        end_cnt_baud    ;
    reg         [12:0]          baud_num        ;
    reg                         flag            ;

    reg         [3:0]           cnt_byte        ;
    wire                        add_cnt_byte    ;
    wire                        end_cnt_byte    ;

    reg         [1:0]           din_r           ;
    wire                        nege            ;
    reg         [9:0]           rx_data         ;
    reg                         rx_data_vld     ;  


    //计数器
    //波特率计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_baud <= 0;
        end 
        else if(add_cnt_baud)begin 
                if(end_cnt_baud)begin 
                    cnt_baud <= 0;
                end
                else begin 
                    cnt_baud <= cnt_baud + 1;
                end 
        end
       else  begin
           cnt_baud <= cnt_baud;
        end
    end 
    
    assign add_cnt_baud = flag;
    assign end_cnt_baud = add_cnt_baud && cnt_baud == baud_num-1;

    //比特计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_byte <= 0;
        end 
        else if(add_cnt_byte)begin 
                if(end_cnt_byte)begin 
                    cnt_byte <= 0;
                end
                else begin 
                    cnt_byte <= cnt_byte + 1;
                end 
        end
       else  begin
           cnt_byte <= cnt_byte;
        end
    end 
    
    assign add_cnt_byte = end_cnt_baud;
    assign end_cnt_byte = add_cnt_byte && cnt_byte == 9;

    //flag  波特率计数器运行标志 1:运行  0:停止
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            flag <= 0;
        end 
        else if(nege)begin 
            flag <= 1;
        end 
        else if(cnt_byte == 9  && end_cnt_baud)begin 
            flag <= 0;
        end 
    end

    //baud_num   波特率选择    baud_sel:0 ————>9600    1————>19200   2————>38400  3————>115200
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            baud_num <= 0;
        end 
        else begin 
            case (baud_sel)
            0 : begin
                baud_num <= `BAUD_9600;
            end
            1 : begin
                baud_num <= `BAUD_19200;
            end
            2 : begin
                baud_num <= `BAUD_38400;
            end
            3 : begin
                baud_num <= `BAUD_115200;
            end
                default: begin
                    baud_num <= baud_num;
                end
            endcase
        end 
    end

    //nege din_r   打拍 检测数据起始位
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            din_r <= 0;
        end 
        else begin 
            din_r <= {din_r[0],rx_din};
        end 
    end

    assign nege = !din_r[0]&din_r[1];

    //rx_data 将比特数据转换为字节
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            rx_data <= 0;
        end 
        else if(flag && cnt_baud ==2500)begin 
           rx_data[cnt_byte] <= rx_din;
        end 
        else begin 
           rx_data <= rx_data; 
        end 
    end
    //rx_data_vld  当数据停止位等于1,数据有效
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            rx_data_vld <= 0;
        end 
        else if(cnt_byte == 9 )begin 
           rx_data_vld <= flag && cnt_baud ==2700 && rx_data[9] == 1; 
        end 
        else begin
            rx_data_vld <= rx_data_vld;
        end
    end


    assign rx_byte     = rx_data[8:1]; 
    assign rx_byte_vld = rx_data_vld; 


endmodule

uart_tx

`include "param.v"
module uart_tx
(
    input                       clk         ,
    input                       rst_n       ,
    input           [1:0]       baud_sel    ,
    input           [7:0]       tx_byte     ,
    input                       tx_byte_vld ,
    output                      tx_dout     ,
    output                      busy        
);
    //信号定义
    reg             [12:0]      cnt_baud    ;
    wire                        add_cnt_baud;
    wire                        end_cnt_baud;
    reg             [12:0]      baud_num    ;

    reg             [3:0]       cnt_bit     ;
    wire                        add_cnt_bit ;
    wire                        end_cnt_bit ;

    reg                         dout        ;
    reg             [9:0]       tx_data     ;
    reg                         flag        ;

    //计数器
    //波特率计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_baud <= 0;
        end 
        else if(add_cnt_baud)begin 
                if(end_cnt_baud)begin 
                    cnt_baud <= 0;
                end
                else begin 
                    cnt_baud <= cnt_baud + 1;
                end 
        end
       else  begin
           cnt_baud <= cnt_baud;
        end
    end 
    
    assign add_cnt_baud = flag;
    assign end_cnt_baud = add_cnt_baud && cnt_baud == baud_num-1;
    
    //比特计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_bit <= 0;
        end 
        else if(add_cnt_bit)begin 
                if(end_cnt_bit)begin 
                    cnt_bit <= 0;
                end
                else begin 
                    cnt_bit <= cnt_bit + 1;
                end 
        end
       else  begin
           cnt_bit <= cnt_bit;
        end
    end 
    
    assign add_cnt_bit = end_cnt_baud;
    assign end_cnt_bit = add_cnt_bit && cnt_bit == 9;

    //flag   波特率计数器使用标志信号  1:计数器运行 0:计数器停止
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            flag <= 0;
        end 
        else if(tx_byte_vld)begin                       //数据长有效,数据一直发送同一个?
            flag <= 1;
        end 
        else if(cnt_bit==9 && end_cnt_baud)begin 
            flag <= 0;
        end 
    end

    //baud_num  波特率选择    baud_sel:0 ————>9600    1————>19200   2————>38400  3————>115200
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            baud_num <= 0;
        end
        else begin 
            case (baud_sel)
                0 : begin
                    baud_num <=`BAUD_9600; 
                end
                1 : begin
                    baud_num <= `BAUD_19200;
                end
                2 : begin
                    baud_num <= `BAUD_38400;
                end
                3 : begin
                    baud_num <= `BAUD_115200;
                end
                default: begin
                    baud_num <= baud_num;
                end
            endcase
        end 
    end

    //tx_data   添加数据的起始位:0  停止位:  1     发送数据低位-->高位  
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            tx_data <= 0;
        end 
        else if(tx_byte_vld)begin 
            tx_data <= {`STOP_BIT,tx_byte,`START_BIT};
        end 
        else begin 
            tx_data <=tx_data;
        end 
    end

    //输出
    //dout 将字节数据转换为比特输出
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            dout <= 1;
        end 
        else if(flag)begin 
            dout <= tx_data[cnt_bit];
        end 
        else begin 
            dout <= dout;
        end 
    end


    //busy  tx_dout
    assign tx_dout = dout;  //uart tx 数据输出
    assign busy = flag;     //busy 忙标志   1:忙状态    0:空闲状态




endmodule

四、ModelSim仿真

在这里插入图片描述

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值