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实现,涉及计数器,移位拼接依次获取数据,握手有效判断,判断是否数据接收完毕,校验位计算等功能实现,具体可对照代码详细注释。

相关推荐
星夜离尘561 小时前
UART偶发乱码:波特率分频误差之外,还要算采样漂移
fpga开发·uart
hexiaoyan82710 小时前
271-基于JFM7VX690T36 的四路40Gbps的PCIeX8 全国产化卡
fpga开发·软件无线电处理平台·硬件加速器·jfm7vx690t36·全国产化卡·7vx690t36
Terasic友晶科技21 小时前
答疑解惑|Agilex 5如何指定Boot Core及设定Core的运行频率?
fpga开发·hps·terasic·cortex-a55·cortex-a76·boot core
辰丁电子1 天前
allegro入门教程-菜单栏Route
fpga开发·pcb工艺·pcb·layout·allegro软件
吉他英雄一里1 天前
FPGA工具篇--ILA
fpga开发
鸥梨菌Honevid1 天前
UVM sequence-driver 通信模型(详细讲解)
fpga开发
博览鸿蒙1 天前
数字芯片设计实战路线:硬件工程师的 FPGA
fpga开发
zhutier-1 天前
Vivado+Artix7+W25Q128JVEIQ FPGA固化程序到FLASH里面教程
fpga开发
hexiaoyan8271 天前
FMC 子卡设计原理图:154-基于FMC 八路SFP+万兆光纤子卡
fpga开发·光纤收发·fmc 子卡·万兆光纤子卡·sfp+万兆光纤
北京青翼科技2 天前
青翼基于PCIe总线架构的4路HD-SDI/3G-SDI视频图像模拟源丨图像处理
fpga开发·图像模拟源·fpga开发板·pcie板卡