FPGA-结合协议时序实现UART收发器(三):串口接收模块uart_rx

FPGA-结合协议时序实现UART收发器(三):串口接收模块uart_rx

串口接收模块uart_rx的功能实现


文章目录


一、功能实现

对照代码,串口接收模块uart_rx实现功能包括:

  • r_cnt计数信号,计数数据
  • ro_user_rx_data 寄存用户接收数据,采用移位拼接方式依次获取数据
  • ro_user_rx_valid 用户接受有效,通过判断是否接收完毕来赋值valid
  • r_rx_check 校验位,采用异或方法

二、uart_rx代码

c 复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/09/09 13:14:22
// Design Name: 
// Module Name: uart_rx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_rx#(
    //串口可调参数
    parameter    P_SYSTEM_CLK        = 50_000_000,    
    parameter    P_UART_BUADRATE    = 9600,
    parameter    P_UART_DATA_WIDTH  = 8,
    parameter    P_UART_STOP_WIDTH  = 1,
    parameter    P_UART_CHECK       = 0 //0未开启校验位,1奇校验,2偶校验
)( 
    //串口驱动输入输出
    input   i_clk   ,
    input   i_rst   ,
    
    input   i_uart_rx,


    output  [P_UART_DATA_WIDTH - 1 : 0] o_user_rx_data  ,//用户输入数据,作为驱动的输出,即先经过驱动输出再输入到用户
    output                              o_user_rx_valid 

);


reg         [P_UART_DATA_WIDTH - 1 : 0]     ro_user_rx_data;
reg                                         ro_user_rx_valid;
reg         [1:0]                           r_uart_rx;
reg         [15:0]                          r_cnt;   
reg                                         r_rx_check;


assign      o_user_rx_data = ro_user_rx_data;
assign      o_user_rx_valid = ro_user_rx_valid;


//处理打两拍情况,即取延迟一个周期的数
//使用时钟动态纠正,此处打两拍没用到
always @(posedge i_clk or posedge i_rst)
begin
    if(i_clk)
        r_uart_rx <= 2'b11;
    else
        r_uart_rx <= {r_uart_rx[0] , i_uart_rx};//r_uart_rx[1]就是打两拍的信号,即先读低位再往左移位
    
end



//处理r_cnt计数信号
always @(posedge i_clk or posedge i_rst) 
begin
    if(i_rst)//初始值
        r_cnt <= 'd0;
    else if(r_cnt == 3 + P_UART_DATA_WIDTH - 3 && P_UART_CHECK == 0)//与uart_tx中同理
        r_cnt <= 'd0;
    else if(r_cnt == 3 + P_UART_DATA_WIDTH - 2 && P_UART_CHECK > 0)
        r_cnt <= 'd0;
    else if(r_uart_rx[1] == 0 || r_cnt > 0)//打两拍r_uart_rx[1] == 0时为起始位即开始计数,或者已经开始计数了
        r_cnt <= r_cnt + 1;//可以计数
    else//保持
        r_cnt <= r_cnt;
end

//处理用户接受数据ro_user_rx_data
always @(posedge i_clk or posedge i_rst)
begin
    if (i_rst)
        ro_user_rx_data <= 'd0;
    else if(r_cnt > 0 && r_cnt <= P_UART_DATA_WIDTH)//r_cnt判断到数据位结束,此时r_cnt ==1 + P_UART_DATA_WIDTH -1,即r_cnt==起始位+数据位-1
        ro_user_rx_data <= {i_uart_rx , ro_user_rx_data[P_UART_DATA_WIDTH - 1 : 1]};//uart先发低位再发高位,即先从高位接收新数据然后向低位移位
        //ro_user_rx_data <= {r_uart_rx[1] , ro_user_rx_data[P_UART_DATA_WIDTH - 1 : 1]};//r_uart_rx[1]为打两拍信号
    else
        ro_user_rx_data <= ro_user_rx_data;
end


//处理用户接收握手ro_user_rx_valid
//i_uart_rx == ~r_rx_check 与 i_uart_rx == r_rx_check不理解可举例说明
//当数据为1001时,进行逐位运算后r_rx_check==0,奇校验时,校验位此时应该为1,即!r_rx_check
//当数据为0001时,进行逐位运算后r_rx_check==1,奇校验时,校验位此时应该为0,即!r_rx_check
//故奇校验时,i_uart_rx == !r_rx_check
//偶校验同理举例
always @(posedge i_clk or posedge i_rst)
begin
    if(i_rst)
        ro_user_rx_valid <= 'd0;
    else if(r_cnt == 3 + P_UART_DATA_WIDTH - 3 && P_UART_CHECK == 0)//计数完毕,没有开启校验位情况,与uart_tx中同理
        ro_user_rx_valid <= 'd1;
    else if(r_cnt == 3 + P_UART_DATA_WIDTH - 2 && P_UART_CHECK == 1 && i_uart_rx == !r_rx_check)//计数完毕,有开启校验位情况,r_cnt此时为校验位的位置,开启奇校验并且i_uart_rx确实为奇校验
        ro_user_rx_valid <= 'd1;
    else if(r_cnt == 3 + P_UART_DATA_WIDTH - 2 && P_UART_CHECK == 2 && i_uart_rx == r_rx_check)//计数完毕,有开启校验位情况,r_cnt此时为校验位的位置,开启奇校验并且i_uart_rx确实为奇校验
        ro_user_rx_valid <= 'd1;    
    else
        ro_user_rx_valid <= 'd0;//其他情况都是0
end


//处理判断接收的校验位,r_rx_check
always @(posedge i_clk or posedge i_rst)
begin
    if(i_rst)
        r_rx_check <= 'd0;
    else if (r_cnt > 0 && r_cnt <= P_UART_DATA_WIDTH)//r_cnt计数到数据位结束
        r_rx_check <= r_rx_check ^ i_uart_rx;//对i_uart_rx接收的数据依次进行异或运算,用来判断校验位使用,异或判断接收的数据里1的个数是奇数还是偶数
    else
        r_rx_check <= 'd0;
end



endmodule

总结

串口接收模块uart_rx实现,涉及计数器,移位拼接依次获取数据,握手有效判断,判断是否数据接收完毕,校验位计算等功能实现,具体可对照代码详细注释。

相关推荐
2202_754421543 分钟前
一个计算频率的模块
驱动开发·fpga开发
小灰灰的FPGA1 小时前
低速接口项目之串口Uart开发(七)——如何在FPGA项目中实现自适应波特率串口功能
fpga开发
fei_sun20 小时前
【Verilog】第一章作业
fpga开发·verilog
深圳市雷龙发展有限公司longsto21 小时前
基于FPGA(现场可编程门阵列)的SD NAND图片显示系统是一个复杂的项目,它涉及硬件设计、FPGA编程、SD卡接口、NAND闪存控制以及图像显示等多个方面
fpga开发
9527华安1 天前
FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持
网络·fpga开发·udp·音视频·xdma·pcie3.0·万兆网
able陈1 天前
为什么verilog中递归函数需要定义为automatic?
fpga开发
fei_sun1 天前
【Verilog】第二章作业
fpga开发·verilog
碎碎思1 天前
如何使用 Vivado 从源码构建 Infinite-ISP FPGA 项目
fpga开发·接口隔离原则
江山如画,佳人北望1 天前
fpga-状态机的设计及应用
fpga开发
晓晓暮雨潇潇1 天前
Xilinx IP核(3)XADC IP核
fpga开发·vivado·xadc·ip核