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

相关推荐
DS小龙哥11 小时前
基于Zynq FPGA的雷龙SD NAND存储芯片性能测试
fpga开发·sd nand·雷龙·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
上理考研周导师20 小时前
第二章 虚拟仪器及其构成原理
fpga开发
FPGA技术实战1 天前
《探索Zynq MPSoC》学习笔记(二)
fpga开发·mpsoc
bigbig猩猩1 天前
FPGA(现场可编程门阵列)的时序分析
fpga开发
Terasic友晶科技2 天前
第2篇 使用Intel FPGA Monitor Program创建基于ARM处理器的汇编或C语言工程<二>
fpga开发·汇编语言和c语言
码农阿豪2 天前
基于Zynq FPGA对雷龙SD NAND的测试
fpga开发·sd nand·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
江山如画,佳人北望2 天前
EDA技术简介
fpga开发
淘晶驰AK2 天前
电子设计竞赛准备经历分享
嵌入式硬件·fpga开发
最好有梦想~2 天前
FPGA时序分析和约束学习笔记(4、IO传输模型)
笔记·学习·fpga开发