Verilog从uart端口接收数据


module uart_recv(
    input			  sys_clk,                  //系统时钟
    input             sys_rst_n,                //系统复位,低电平有效
    
    input             uart_rxd,                 //UART接收端口
    output  reg       uart_done,                //接收一帧数据完成标志信号
    output  reg [7:0] uart_data                 //接收的数据
    );
    
//parameter define
parameter  CLK_FREQ = 50000000;                 //系统时钟频率
parameter  UART_BPS = 9600;                     //串口波特率
localparam BPS_CNT  = CLK_FREQ/UART_BPS;        //为得到指定波特率,
                                                //需要对系统时钟计数BPS_CNT次
//reg define
reg        uart_rxd_d0;
reg        uart_rxd_d1;
reg [15:0] clk_cnt;                             //系统时钟计数器
reg [ 3:0] rx_cnt;                              //接收数据计数器
reg        rx_flag;                             //接收过程标志信号
reg [ 7:0] rxdata;                              //接收数据寄存器

//wire define
wire       start_flag;

//*****************************************************
//**                    main code
//*****************************************************
//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    

//对UART接收端口的数据延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin 
    if (!sys_rst_n) begin 
        uart_rxd_d0 <= 1'b0;
        uart_rxd_d1 <= 1'b0;          
    end
    else begin
        uart_rxd_d0  <= uart_rxd;                   
        uart_rxd_d1  <= uart_rxd_d0;
    end   
end

//当脉冲信号start_flag到达时,进入接收过程           
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                                  
        rx_flag <= 1'b0;
    else begin
        if(start_flag)                          //检测到起始位
            rx_flag <= 1'b1; //reg [ 3:0] rx_cnt接收数据计数器 进入接收过程,标志位rx_flag拉高
        else if((rx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))
            rx_flag <= 1'b0;                    //计数到停止位中间时,停止接收过程
        else
            rx_flag <= rx_flag;
    end
end

//进入接收过程后,启动系统时钟计数器与接收数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin                             
        clk_cnt <= 16'd0;                                  
        rx_cnt  <= 4'd0;
    end                                                      
    else if ( rx_flag ) begin                   //处于接收过程
            if (clk_cnt < BPS_CNT - 1) begin
                clk_cnt <= clk_cnt + 1'b1;
                rx_cnt  <= rx_cnt;
            end
            else begin
                clk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零
                rx_cnt  <= rx_cnt + 1'b1;       //此时接收数据计数器加1
            end
        end
    else begin                              //接收过程结束,计数器清零
        clk_cnt <= 16'd0;
        rx_cnt  <= 4'd0;
    end
end

//根据接收数据计数器来寄存uart接收端口数据
always @(posedge sys_clk or negedge sys_rst_n) begin 
    if ( !sys_rst_n)  
        rxdata <= 8'd0;                                     
    else if(rx_flag)//reg [ 3:0] rx_cnt;/接收数据计数器
                    //系统处于接收过程
        if (clk_cnt == BPS_CNT/2) begin         //判断系统时钟计数器计数到数据位中间
            case ( rx_cnt )
             4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位
             4'd2 : rxdata[1] <= uart_rxd_d1;
             4'd3 : rxdata[2] <= uart_rxd_d1;
             4'd4 : rxdata[3] <= uart_rxd_d1;
             4'd5 : rxdata[4] <= uart_rxd_d1;
             4'd6 : rxdata[5] <= uart_rxd_d1;
             4'd7 : rxdata[6] <= uart_rxd_d1;
             4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位
             default:;                                    
            endcase
        end
        else 
            rxdata <= rxdata;
    else
        rxdata <= 8'd0;
end

//数据接收完毕后给出标志信号并寄存输出接收到的数据
always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n) begin
        uart_data <= 8'd0;                               
        uart_done <= 1'b0;
    end
    else if(rx_cnt == 4'd9) begin               //接收数据计数器计数到停止位时           
        uart_data <= rxdata;                    //寄存输出接收到的数据
        uart_done <= 1'b1;                      //并将接收完成标志位拉高
    end
    else begin
        uart_data <= 8'd0;                                   
        uart_done <= 1'b0; 
    end    
end

endmodule	

第87行, if (clk_cnt == BPS_CNT/2) begin ,为什么要到每个数据的中间位置接收数据呢?原子哥给出的说法是每一位的数据中间位置数据最稳定
在这里插入图片描述存疑,日后查书籍解释之。

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 使用Verilog语言来实现UART,需要实现以下几个步骤:1.定义UART的基本参数,如波特率;2.编写UART的模块,包括接收和发送模块;3.实现接收和发送模块之间的控制逻辑;4.编写驱动程序,控制UART进行数据传输。 ### 回答2: 使用Verilog实现UART(Universal Asynchronous Receiver/Transmitter)通信的过程如下: 1. 定义模块:首先,在Verilog中定义一个顶层模块,用于包含UART的发送和接收功能。模块定义包括输入和输出端口以及内部信号。 2. 定义时钟信号:UART通信需要时钟信号来同步数据传输。因此,在模块中定义一个时钟输入端口。 3. 定义输入和输出:UART通信包括数据输入端口(用于发送数据)和数据输出端口(用于接收数据)。这些输入和输出端口的大小取决于UART通信的数据位数。 4. 定义波特率:UART通信采用固定的波特率来控制数据传输速度。因此,需要定义一个波特率参数,并根据波特率来生成时钟分频信号。 5. 发送数据:使用Verilog语言的组合逻辑或时序逻辑语句,在适当的时机将数据发送到UART的发送端口。这可以通过异步发送来实现,也可以通过时钟边沿控制来实现。 6. 接收数据:类似地,使用Verilog语言的组合逻辑或时序逻辑语句,在适当的时机从UART的接收端口读取数据。同样,可以通过异步接收来实现,也可以通过时钟边沿控制来实现。 7. 生成时钟分频信号:根据定义的波特率参数和输入的时钟信号,生成时钟分频信号以控制数据传输速度。 8. 编写测试程序:最后,编写测试程序来验证UART的发送和接收功能是否正常工作。用户可以自定义发送的数据,然后验证接收端是否正确接收到数据。 总之,使用Verilog实现UART通信涉及定义模块、时钟信号、输入和输出接口、波特率参数、发送和接收数据的逻辑以及测试程序等步骤。通过这些步骤,可以实现一个功能完整的UART通信模块。 ### 回答3: 使用Verilog实现UART(Universal Asynchronous Receiver/Transmitter)可以实现串行通信协议,在数字电路中用于将数据从并行格式转换为串行格式,或者从串行格式转换为并行格式。 首先,我们需要定义UART模块的输入输出接口。一个常见的UART模块通常包括一个输入接口(clk,rst,data_in,start)和一个输出接口(data_out,tx_busy)。 输入接口中的clk是时钟信号,用于同步数据传输;rst是复位信号,用于清除模块的状态;data_in是输入数据信号,start是开始传输的信号。 输出接口中的data_out是输出数据信号,tx_busy用于指示当前线路是否正在传输数据。 其次,我们需要设计UART模块内部的状态机,用于控制数据的发送和接收。状态机通常包括四个状态:空闲状态、开始位状态、数据位状态和停止位状态。 在空闲状态下,当检测到start信号为高电平时,状态机切换到开始位状态,发送一个起始位。 在开始位状态下,状态机等待一个时钟周期,然后根据输入信号data_in的值发送数据位。 在数据位状态下,状态机重复上述过程,直到所有数据位都被发送完。 在停止位状态下,状态机发送一个停止位,并将状态机切换到空闲状态。 最后,我们需要实现数据的发送和接收逻辑。发送逻辑包括:根据状态机的状态选择要发送的数据位,在每个时钟周期结束后将数据位移动到右边一个位置。 接收逻辑包括:检测到开始位之后,等待一个半个时钟周期,然后开始接收数据位;在每个时钟周期结束后,将数据位移动到左边一个位置。 综上所述,通过使用Verilog来实现UART,我们可以设计和实现一个数字电路模块,可以将数据从并行格式转换为串行格式,或者从串行格式转换为并行格式。这样可以实现计算机和外部设备之间的通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值