UART串口verilog hdl实现(3)接收模块

波特率模块和发送模块都没问题以后,就可以开始编写接收模块的代码了。
其中:
  I_clk是系统时钟;
  I_rst_n是系统复位;
  I_rx_start是开始发送信号,当I_rx_start一直为高电平时,接收模块检测到有数据就会接收;
  I_bps_rx_clk是接收模块波特率时钟信号,当检测到I_bps_rx_clk为高的时候就接收1个bit;
  I_rs232_rx是串行的bit数据流;
  O_para_data[7:0]是并行的8-bit数据;
  O_bps_rx_clk_en是发射波特率时钟启动信号,当它为1是波特率产生模块才能产生接收模块的波特率时钟;
  O_rx_done是接收1字节数据完成的标志位,当一个字节接收完毕以后,O_rx_done产生一个高脉冲。
  接收模块完整代码如下:

module uart_rxd
(
    input       I_clk       ,//系统50MHz时钟
    input       I_rst_n     ,//系统全局复位
    input       I_rx_start  ,//接收使能信号
    input       I_bps_rx_clk,//接收波特率时钟
    input       I_rs232_rxd ,//接收的串行数据,硬件上与串口相连
    output  reg o_bps_rx_clk_en,//波特率时钟使能信号
    output  reg o_rx_done,//接收完成标志
    output  reg [7:0] o_para_data//接收到的8 bit并行数据            
);

reg     R_rs232_rx_reg0 ;
reg     R_rs232_rx_reg1 ;
reg     R_rs232_rx_reg2 ;
reg     R_rs232_rx_reg3 ;
reg     R_receiving     ;

reg [3:0] R_state        ;
reg [7:0] R_para_data_reg;

wire    w_rs232_rxd_neg ;


// 功能:把 I_rs232_rxd 打的前两拍,是为了消除亚稳态
//          把 I_rs232_rxd 打的后两拍,是为了产生下降沿标志位

always  @(posedge I_clk or negedge I_rst_n)
begin
        if(!I_rst_n)
            begin
                R_rs232_rx_reg0 <= 1'b0;
                R_rs232_rx_reg1 <= 1'b0;
                R_rs232_rx_reg2 <= 1'b0;
                R_rs232_rx_reg3 <= 1'b0;    
            end
        else
            begin
                R_rs232_rx_reg0 <= I_rs232_rxd  ;
                R_rs232_rx_reg1 <= R_rs232_rx_reg0;
                R_rs232_rx_reg2 <= R_rs232_rx_reg1;
                R_rs232_rx_reg3 <= R_rs232_rx_reg2;        
            end           
end

//产生 I_rs232_rxd 信号的下降沿标志位
assign w_rs232_rxd_neg  =   (~R_rs232_rx_reg2)  &   R_rs232_rx_reg3;


// 功能:产生发送信号R_receiving

always  @(posedge I_clk or  negedge I_rst_n)
begin
        if(!I_rst_n)
            R_receiving     <=  1'b0;
         else   if(o_rx_done)
            R_receiving     <=  1'b0;
         else   if(I_rx_start   &&  w_rs232_rxd_neg)
            R_receiving     <=  1'b1;
end


// 功能:用状态机把串行的输入数据接收,并转化为并行数据输出

always  @(posedge   I_clk   or  negedge I_rst_n)
begin
        if(!I_rst_n)
            begin
                o_rx_done   <=  1'b0;
                R_state     <=  4'd0;
                R_para_data_reg <= 8'd0;
                o_bps_rx_clk_en <= 1'b0;
            end
         else   if(R_receiving)
            begin
                o_bps_rx_clk_en <= 1'b1 ; // 打开波特率时钟使能信号
                if(I_bps_rx_clk)
                    begin
                        case(R_state)
                            4'd0://接收起始位,但不保存
                                begin
                                    R_para_data_reg     <=  8'd0;
                                    o_rx_done           <=  1'b0;
                                    R_state             <=  R_state +   1'b1;    
                                end
                            4'd1:// 接收第0位,保存到R_para_data_reg[0]
                                begin
                                    R_para_data_reg[0]  <=  I_rs232_rxd;
                                    o_rx_done           <=  1'b0;
                                    R_state             <=  R_state +   1'b1; 
                                end
                            4'd2:// 接收第1位,保存到R_para_data_reg[1]
                                begin
                                    R_para_data_reg[1]  <=  I_rs232_rxd;
                                    o_rx_done           <=  1'b0;
                                    R_state             <=  R_state +   1'b1; 
                                end
                            4'd3:// 接收第2位,保存到R_para_data_reg[2]
                                begin
                                    R_para_data_reg[2]  <=  I_rs232_rxd;
                                    o_rx_done           <=  1'b0;
                                    R_state             <=  R_state +   1'b1; 
                                end
                            4'd4:// 接收第3位,保存到R_para_data_reg[3]
                                begin
                                    R_para_data_reg[3]  <=  I_rs232_rxd;
                                    o_rx_done           <=  1'b0;
                                    R_state             <=  R_state +   1'b1; 
                                end
                            4'd5:// 接收第4位,保存到R_para_data_reg[4]
                                begin
                                    R_para_data_reg[4]  <=  I_rs232_rxd;
                                    o_rx_done           <=  1'b0;
                                    R_state             <=  R_state +   1'b1; 
                                end
                            4'd6:// 接收第5位,保存到R_para_data_reg[5]
                                begin
                                    R_para_data_reg[5]  <=  I_rs232_rxd;
                                    o_rx_done           <=  1'b0;
                                    R_state             <=  R_state +   1'b1; 
                                end
                            4'd7:// 接收第6位,保存到R_para_data_reg[6]
                                begin
                                    R_para_data_reg[6]  <=  I_rs232_rxd;
                                    o_rx_done           <=  1'b0;
                                    R_state             <=  R_state +   1'b1; 
                                end
                            4'd8:// 接收第7位,保存到R_para_data_reg[7]
                                begin
                                    R_para_data_reg[7]  <=  I_rs232_rxd;
                                    o_rx_done           <=  1'b0;
                                    R_state             <=  R_state +   1'b1; 
                                end
                            4'd9:// 接收停止位,但不保存,并把R_para_data_reg给输出
                                begin
                                    o_para_data         <=  R_para_data_reg;
                                    o_rx_done           <=  1'b1;
                                    R_state             <=  4'd0; 
                                end
                            default :R_state    <=  4'd0;                                
                        endcase    
                    end
            end 
         else
            begin
                o_rx_done           <= 1'b0 ;
                R_state             <= 4'd0 ;
                R_para_data_reg     <= 8'd0 ;
                o_bps_rx_clk_en     <= 1'b0 ; // 接收完毕以后关闭波特率时钟使能信号            
            end
               
end

endmodule

顶层模块的代码如下:

module uart_top
(
    input             I_clk           , // 系统50MHz时钟
    input             I_rst_n         , // 系统全局复位
    output    [3:0]   O_led_out       ,
    output            O_rs232_txd       // 发送的串行数据,在硬件上与串口相连
);

wire            W_bps_tx_clk                 ;
wire            W_bps_tx_clk_en              ;
wire            W_bps_rx_clk                 ;
wire            W_bps_rx_clk_en              ;
wire            W_tx_start                   ;
wire            W_tx_done                    ;
wire            W_rx_done                    ;
wire  [7:0]     W_para_data                  ;
wire  [7:0]     W_rx_para_data               ;

reg   [7:0]     R_data_reg                   ;
reg   [31:0]    R_cnt_1s                     ;
reg             R_tx_start_reg               ;

assign W_tx_start     =    R_tx_start_reg      ;
assign W_para_data    =    R_data_reg          ;
assign O_led_out      =    W_rx_para_data[3:0];

/
// 产生要发送的数据
/
always @(posedge I_clk or negedge I_rst_n)
begin
     if(!I_rst_n)
        begin
             R_cnt_1s         <= 31'd0     ;
             R_data_reg       <= 8'd0      ;
             R_tx_start_reg   <= 1'b0      ;
        end
     else if(R_cnt_1s == 31'd5000)
        begin
             R_cnt_1s         <= 31'd0                 ;
             R_data_reg       <= R_data_reg + 1'b1     ;
             R_tx_start_reg   <= 1'b1                  ;
        end
     else
        begin
          R_cnt_1s           <= R_cnt_1s + 1'b1     ;
          R_tx_start_reg     <= 1'b0                ;
        end
end

uart_txd U_uart_txd
(
    .I_clk               (I_clk                 ), // 系统50MHz时钟
    .I_rst_n             (I_rst_n               ), // 系统全局复位
    .I_tx_start          (W_tx_start            ), // 发送使能信号
    .I_bps_tx_clk        (W_bps_tx_clk          ), // 波特率时钟
    .I_para_data         (W_para_data           ), // 要发送的并行数据
    .o_rs232_txd         (O_rs232_txd           ), // 发送的串行数据,在硬件上与串口相连
    .o_bps_tx_clk_en     (W_bps_tx_clk_en       ), // 波特率时钟使能信号
    .o_tx_done           (W_tx_done             )  // 发送完成的标志
);

baudrate_gen U_baudrate_gen
(
    .I_clk              (I_clk              ), // 系统50MHz时钟
    .I_rst_n            (I_rst_n            ), // 系统全局复位
    .I_bps_tx_clk_en    (W_bps_tx_clk_en    ), // 串口发送模块波特率时钟使能信号
    .I_bps_rx_clk_en    (W_bps_rx_clk_en    ), // 串口接收模块波特率时钟使能信号
    .O_bps_tx_clk       (W_bps_tx_clk       ), // 发送模块波特率产生时钟
    .O_bps_rx_clk       (W_bps_rx_clk       )  // 接收模块波特率产生时钟
);

uart_rxd U_uart_rxd
(
    .I_clk              (I_clk              ), // 系统50MHz时钟
    .I_rst_n            (I_rst_n            ), // 系统全局复位
    .I_rx_start         (1'b1               ), // 接收使能信号
    .I_bps_rx_clk       (W_bps_rx_clk       ), // 接收波特率时钟
    .I_rs232_rxd        (O_rs232_txd        ), // 接收的串行数据,在硬件上与串口相连  
    .o_bps_rx_clk_en    (W_bps_rx_clk_en    ), // 波特率时钟使能信号
    .o_rx_done          (W_rx_done          ), // 接收完成标志
    .o_para_data        (W_rx_para_data     )  // 接收到的8-bit并行数据
);

endmodule

testbench文件

`timescale 1ns / 1ps
module tb_uart();
        reg I_clk,I_rst_n;
        wire [3:0]  O_led_out;
        wire o_rs232_txd;
        
initial begin
        I_clk =0;
        I_rst_n=0;
        #200  I_rst_n=1;
        
end
always #10 I_clk <= ~I_clk;
uart_top    tb_uart_top_inst
(
    .I_clk           (I_clk), 
    .I_rst_n         (I_rst_n),
    .O_led_out       (O_led_out),
    .O_rs232_txd     (O_rs232_txd)
);
endmodule

仿真图如图所示
在这里插入图片描述

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值