串口接收原理与思路

在这里插入图片描述
在这里插入图片描述
每一次采样应该在每一小段的最中间

##初次设计
源代码:

module uart_byte_rx(
  Clk,
  Reset_n,
  Baud_Set,
  uart_rx,
  Data,
  Rx_Done
    );  
   input  Clk;
 input Reset_n;
  input Baud_Set;
   input uart_rx;
 output reg [7:0] Data;
 output reg Rx_Done;
 
 reg [1:0] uart_rx_r;  //两个D触发器作为边沿检测 
 always @ (posedge Clk)begin
  uart_rx_r[0] <= uart_rx;
  uart_rx_r[1] <=  uart_rx_r[0];
 end
 
 wire pedge_uart_rx;
//  assign pedge_uart_rx =((uart_rx_r[1] == 0) && (uart_rx_r[0] == 1)); [1]是前一个时刻,[0]是新来的一个时刻 D触发器
 assign  pedge_uart_rx =(uart_rx_r == 2'b01);
 wire  nedge_uart_rx;
 // assign   nedge_uart_rx = ((uart_rx_r[1] == 1) && (uart_rx_r[0] == 0));
 assign  nedge_uart_rx =(uart_rx_r == 2'b10);
 
 reg [8:0]  Bps_DR;  //波特率选择器
    always@(*)
        case(Baud_Set)
            0:Bps_DR = 1000000000/9600/16/20 - 1;
            1:Bps_DR = 1000000000/19200/16/20 - 1;
            2:Bps_DR = 1000000000/38400/16/20 - 1;
            3:Bps_DR = 1000000000/57600/16/20 - 1;
            4:Bps_DR = 1000000000/115200/16/20 - 1;
            default:Bps_DR = 1000000000/9600/16/20 - 1;
        endcase
        
 wire bps_clk_16x;
 assign bps_clk_16x = (div_cnt == Bps_DR / 2) ;  //采样时钟
 
 reg RX_EN;
 always @(posedge Clk or negedge Reset_n)
 if(!Reset_n)
  RX_EN <= 0;
  else if (nedge_uart_rx)
   RX_EN <= 1;
   else if ((Rx_Done)|| (sta_bit >= 4))   //接收完或者sta不是正确的起始位
    RX_EN <= 0;
 
 reg [8:0] div_cnt;                  //分频器,分出每一次采样的时间。
  always @(posedge Clk or negedge Reset_n)
 if(!Reset_n)
  div_cnt <= 0;                 //检测到下降沿的时候开始计数
 else if (RX_EN)begin          /*else if (nedge_uart_rx)此语句不成立,因为nedge是一个瞬时的过程,只维持一个时钟周期,
                                  div只能加一次。需要以nedge为起点来使能div,知道数据接收完成或者发现不是起始位的时候再来停止。
                                   所以需要再产生一个使能的电平计数控制信号RX_EN*/
   if(div_cnt == Bps_DR)
   div_cnt <= 0;
  else 
   div_cnt <=  div_cnt + 1'b1;
   end                               //返回上方bps_clk_16x
  else
    div_cnt <= 0; 
    
 reg [7:0] bps_cnt;
 always @(posedge Clk or negedge Reset_n)
 if(!Reset_n)
   bps_cnt <= 0;
else if (RX_EN) begin
   if(bps_clk_16x)begin
     if(bps_cnt == 160)
       bps_cnt <= 0; 
  else 
      bps_cnt <= bps_cnt + 1'b1;     //采样信号来了加一
 end
 else 
      bps_cnt <= bps_cnt;             //采样信号没来保持不变
 end
 else 
    bps_cnt <= 0;
 
 
 //采样数据接收模块
 reg [2:0] r_data [7:0];   // reg with name number    有8个位宽为[2:0]的r_data寄存器。
               // r_data[0][1]  意味着取第零个寄存器的第一位。 
 reg [2:0] sta_bit;
 reg [2:0] sto_bit;
 always @(posedge Clk or negedge Reset_n)
 if(!Reset_n)begin
    sta_bit <= 0;
    sto_bit <= 0;
    r_data[0] <= 0;   //多位宽寄存器数据定义只能一个一个来。
    r_data[1] <= 0;
    r_data[2] <= 0;
    r_data[3] <= 0;
    r_data[4] <= 0;
    r_data[5] <= 0;
    r_data[6] <= 0;
    r_data[7] <= 0;
 end
else if(bps_clk_16x) begin
   case(bps_cnt)
        0 :  begin
        sta_bit <= 0;
    sto_bit <= 0;
    r_data[0] <= 0;   //多位宽寄存器数据定义只能一个一个来。
    r_data[1] <= 0;
    r_data[2] <= 0;
    r_data[3] <= 0;
    r_data[4] <= 0;
    r_data[5] <= 0;
    r_data[6] <= 0;
    r_data[7] <= 0;
 end  /*   5 : sta_bit <=sta_bit + 1'b1;
       6 : sta_bit <=sta_bit + 1'b1;
       7 : sta_bit <=sta_bit + 1'b1;*/
            5,6,7,8,9,10,11 : sta_bit <= sta_bit <=sta_bit + uart_rx;// 从第五位开始计数,累加情况取决于uart_rx给出的状态,若最后 sta_bit数据大于四,则判断为高电平
       // 每一数据采样15次 下一数据的采样开始为16, 有效范围则在21开始。
            21,22,23,24,25,26,27: r_data[0] <= r_data[0] + uart_rx;
            37,38,39,40,41,42,43: r_data[1] <= r_data[1] + uart_rx;
            53,54,55,56,57,58,59: r_data[2] <= r_data[2] + uart_rx;
            69,70,71,72,73,74,75: r_data[3] <= r_data[3] + uart_rx;
            85,86,87,88,89,90,91: r_data[4] <= r_data[4] + uart_rx;
            101,102,103,104,105,106,107: r_data[5] <= r_data[5] + uart_rx;
            117,118,119,120,121,122,123: r_data[6] <= r_data[6] + uart_rx;
            133,134,135,136,137,138,139: r_data[7] <= r_data[7] + uart_rx;
            149,150,151,152,153,154,155: sto_bit <= sto_bit + uart_rx;
            default:;  //什么多不做.
        endcase
    end
       
 always @(posedge Clk or negedge Reset_n)                 //数据状态判定模块
 if(!Reset_n)
       Data <= 0;
    else if ((bps_clk_16x) && (bps_cnt == 159)) begin    // 数据的最后一位,在此之后可输出结果
        Data[0] <=( r_data[0] >= 4)?1'b1:1'b0;
        Data[1] <= (r_data[1] >= 4)?1'b1:1'b0;
        Data[2] <= (r_data[2] >= 4)?1'b1:1'b0;
        Data[3] <= (r_data[3] >= 4)?1'b1:1'b0;
        Data[4] <= (r_data[4] >= 4)?1'b1:1'b0;
        Data[5] <= (r_data[5] >= 4)?1'b1:1'b0;
        Data[6] <= (r_data[6] >= 4)?1'b1:1'b0;
        Data[7] <= (r_data[7] >= 4)?1'b1:1'b0;
end   

always @(posedge Clk or negedge Reset_n)
 if(!Reset_n)
     Rx_Done  <= 0;
else if ((div_cnt == Bps_DR/2) && (bps_cnt == 160))
 Rx_Done <= 1;
else 
 Rx_Done <= 0;
 
endmodule

TB文件:

`timescale 1ns / 1ps

module uart_byte_rx_tb();

   reg Clk;
   reg Reset_n;
   wire [2:0]Baud_Set;
   reg uart_rx;
   wire [7:0]Data; 
   wire Rx_Done;
   
   assign Baud_Set = 4;
   
    uart_byte_rx uart_byte_rx(
        Clk,
        Reset_n,
        Baud_Set,
        uart_rx,
        Data,
        Rx_Done,  
    );
    
    initial Clk = 1;
    always#10 Clk = ~Clk;
    
    initial begin
       Reset_n = 0;
       uart_rx = 1;
       #201;
       Reset_n = 1;
       #200; 
       uart_tx_byte(8'h5a);
       #90000;
       uart_tx_byte(8'ha5);
       #90000;
       uart_tx_byte(8'h86);
       #90000;
       $stop;
    end
    
    task uart_tx_byte;
        input [7:0]tx_data;
        begin
            uart_rx = 1;
            #20;
            uart_rx = 0;
            #8680;
            uart_rx = tx_data[0];
            #8680;
            uart_rx = tx_data[1];
            #8680;
            uart_rx = tx_data[2];
            #8680;
            uart_rx = tx_data[3];
            #8680;
            uart_rx = tx_data[4];
            #8680;
            uart_rx = tx_data[5];
            #8680;
            uart_rx = tx_data[6];
            #8680;
            uart_rx = tx_data[7];
            #8680;
            uart_rx = 1;
            #8680;         
        end
    endtask
    
endmodule

在这里插入图片描述
此处可改写为:
Data[0] <= r_data[0][2];
// Data[1] <= r_data[1][2];
// Data[2] <= r_data[2][2];
// Data[3] <= r_data[3][2];
// Data[4] <= r_data[4][2];
// Data[5] <= r_data[5][2];
// Data[6] <= r_data[6][2];
// Data[7] <= r_data[7][2];

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值