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

相关推荐
ThreeYear_s16 小时前
电力电子技术学习路径与FPGA/DSP技术结合方向(gemini生成)
学习·fpga开发
奋斗的牛马20 小时前
FPGA—ZYNQ学习spi(六)
单片机·嵌入式硬件·学习·fpga开发·信息与通信
GateWorld1 天前
FPGA核心约束类型与语法
fpga开发
SKYDROID云卓小助手1 天前
无人设备遥控器之数字图传技术
运维·服务器·单片机·嵌入式硬件·fpga开发
Topplyz1 天前
在FPGA中实现频率计方案详解(等精度测量)
fpga开发·fpga·频率计
whik11941 天前
如何测量FPGA管脚的好坏
fpga开发
XINVRY-FPGA1 天前
XC7Z020-1CLG484I Xilinx AMD FPGA Zynq-7000 SoC
arm开发·嵌入式硬件·网络协议·fpga开发·硬件工程·信号处理·fpga
Js_cold2 天前
Verilog宏define
fpga开发·verilog
Shang180989357262 天前
T41LQ 一款高性能、低功耗的系统级芯片(SoC) 适用于各种AIoT应用智能安防、智能家居方案优选T41L
人工智能·驱动开发·嵌入式硬件·fpga开发·信息与通信·信号处理·t41lq
范纹杉想快点毕业2 天前
12个月嵌入式进阶计划ZYNQ 系列芯片嵌入式与硬件系统知识学习全计划(基于国内视频资源)
c语言·arm开发·单片机·嵌入式硬件·学习·fpga开发·音视频