小梅哥Xilinx FPGA学习笔记12—uart串口接收设计优化

问题

基于上一节uart串口接收逻辑的内容,还存在一点缺陷,需要设计优化后才能应用于实际项目中。:

由于在不同的数据收发系统之间,uart控制器工作的时钟频率有差异,时钟自身的频率误差也不一样,可能数据传输时间略小于接收时间,导致数据的收发时刻有轻微的错位(详见下方示意图)。若两轮数据发送的时间间隔很短,刚发完第一轮数据就又立刻发送第二轮数据,就可能导致第二轮数据的接受失败。

解决方法

在stop停止位提前结束,只使用0.5位的时间,为发送器提供0.5位的容错时间,提前回到空闲态,等待新一轮数据的接收

设计代码修改

将停止位的采样时间也均改为中点处,即bit_cnt=9,且波特分频计数器计数到一半 = MCNT_BAUD/2

原代码:

修改后:

完整设计代码

`timescale 1ns / 1ps

    module uart_byte_rx(
    Clk,
    Reset_n,
    uart_rx,
    Data,
    Rx_Done
        );
        
    input Clk;
    input Reset_n;
    input  uart_rx;
    output reg [7:0]Data;
    output reg Rx_Done;
    
    reg [29:0]baud_div_count;
    reg [3:0]bit_cnt;
    reg En;
    wire w_Rx_Done;
    reg r_uart_rx;//D触发器
    wire nedge_uart_rx; 
    reg dff0_uart_rx , dff1_uart_rx;
    
    reg [7:0]r_Data; //八位寄存器,用于临时寄存8位uart_data,待8位数据全部接收完毕后,再从该寄存器中一起输出
    
    parameter BAUD = 9600;
    parameter CLOCK_FREQ = 50_000_000;
    parameter MCNT_BAUD = CLOCK_FREQ / BAUD - 1;
    
     //波特分频计数器
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
    baud_div_count <= 0;
    else if(En)begin   //使能端有效
        if(baud_div_count ==  MCNT_BAUD)
            baud_div_count <= 0;
        else
            baud_div_count <= baud_div_count + 1'd1;
    end
    else     //使能端无效
         baud_div_count <= 0;
         
    //下降沿检测逻辑 
      always@(posedge Clk)     
         dff0_uart_rx <=  uart_rx;
        
      always@(posedge Clk)   
         dff1_uart_rx <=  dff0_uart_rx;
        
     always@(posedge Clk)      
        r_uart_rx <=  dff1_uart_rx;

    assign nedge_uart_rx = (dff1_uart_rx == 0) && (r_uart_rx == 1);        
     
  //使能信号逻辑     注意:毛刺干扰也不能计数
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        En <= 0;
    else if(nedge_uart_rx)
        En <= 1;
    else if((bit_cnt == 9)&&(baud_div_count ==  MCNT_BAUD/2)) //10位数据接收完成
        En <= 0;
    else if((bit_cnt == 0)&&(baud_div_count ==  MCNT_BAUD/2)&&(dff1_uart_rx == 1)) //起始时有毛刺   
        En <= 0;    
         

  //位计数器  
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        bit_cnt <= 0;      
    else if((baud_div_count == MCNT_BAUD/2) && (bit_cnt == 9))
        bit_cnt <= 0;
    else if(baud_div_count == MCNT_BAUD) //bit_cnt不等于9时能计满,需自加
        bit_cnt <= bit_cnt + 1'd1;
    
    

    //接收完毕停止计数
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
    En <= 0;
    else if(((bit_cnt == 9)&&(baud_div_count == MCNT_BAUD)))
    En <= 1;
    
    //数据位接收逻辑(串转并)
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Data <= 8'd0;
    else if(baud_div_count == MCNT_BAUD/2)begin  //中点处采样
        case(bit_cnt)
            1:r_Data[0] <= dff1_uart_rx;
            2:r_Data[1] <= dff1_uart_rx; 
            3:r_Data[2] <= dff1_uart_rx;
            4:r_Data[3] <= dff1_uart_rx;
            5:r_Data[4] <= dff1_uart_rx;
            6:r_Data[5] <= dff1_uart_rx;
            7:r_Data[6] <= dff1_uart_rx;
            8:r_Data[7] <= dff1_uart_rx;
            default:r_Data <= r_Data;
    endcase  
   end
     
     // 接收完成标志信号
     assign w_Rx_Done = (bit_cnt == 9)&&(baud_div_count == MCNT_BAUD/2);
     
     always@(posedge Clk)
     Rx_Done <= w_Rx_Done; 
    
     always@(posedge Clk)
        if(w_Rx_Done) 
            Data <= r_Data;
     
endmodule

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值