• UART中接收程序的理解

    2006年04月20日

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://mathon.blogbus.com/logs/2308531.html

    uart接收程序中的问题

    module async_receiver(clk, RxD, RxD_data_ready, RxD_data, RxD_endofpacket, RxD_idle);
    input clk, RxD;
    output RxD_data_ready;  // onc clock pulse when RxD_data is valid
    output [7:0] RxD_data;

    parameter ClkFrequency = 100000000; // 25MHz
    parameter Baud = 9600;//波特率

    // We also detect if a gap occurs in the received stream of characters
    // That can be useful if multiple characters are sent in burst
    //  so that multiple characters can be treated as a "packet"
    output RxD_endofpacket;  // one clock pulse, when no more data is received (RxD_idle is going high)
    output RxD_idle;  // no data is being received

    // Baud generator (we use 8 times oversampling)
    parameter Baud8 = Baud*8;// 波特率时钟的8倍
    parameter Baud8GeneratorAccWidth = 16;
    parameter Baud8GeneratorInc = ((Baud8<<(Baud8GeneratorAccWidth-7))+(ClkFrequency>>8))/(ClkFrequency>>7);
    reg [Baud8GeneratorAccWidth:0] Baud8GeneratorAcc;
    always @(posedge clk) Baud8GeneratorAcc <= Baud8GeneratorAcc[Baud8GeneratorAccWidth-1:0] + Baud8GeneratorInc;
    wire Baud8Tick = Baud8GeneratorAcc[Baud8GeneratorAccWidth];

    ////////////////////////////
    reg [1:0] RxD_sync_inv;
    always @(posedge clk) if(Baud8Tick) RxD_sync_inv <= {RxD_sync_inv[0], ~RxD};
    // we invert RxD, so that the idle becomes "0", to prevent a phantom character to be received at startup

    reg [1:0] RxD_cnt_inv;
    reg RxD_bit_inv;

    always @(posedge clk)
    if(Baud8Tick)
    begin
      if( RxD_sync_inv[1] && RxD_cnt_inv!=2'b11) RxD_cnt_inv <= RxD_cnt_inv + 1;
      else
      if(~RxD_sync_inv[1] && RxD_cnt_inv!=2'b00) RxD_cnt_inv <= RxD_cnt_inv - 1;

      if(RxD_cnt_inv==2'b00) RxD_bit_inv <= 0;
      else
      if(RxD_cnt_inv==2'b11) RxD_bit_inv <= 1;
    end

    reg [3:0] state;
    reg [3:0] bit_spacing;

    // "next_bit" controls when the data sampling occurs
    // depending on how noisy the RxD is, different values might work better
    // with a clean connection, values from 8 to 11 work
    wire next_bit = (bit_spacing==10);

    always @(posedge clk)
    if(state==0)
      bit_spacing <= 0;
    else
    if(Baud8Tick)
      bit_spacing <= {bit_spacing[2:0] + 1} | {bit_spacing[3], 3'b000};

    always @(posedge clk)
    if(Baud8Tick)
    case(state)
      4'b0000: if(RxD_bit_inv) state <= 4'b1000;  // start bit found?
      4'b1000: if(next_bit) state <= 4'b1001;  // bit 0
      4'b1001: if(next_bit) state <= 4'b1010;  // bit 1
      4'b1010: if(next_bit) state <= 4'b1011;  // bit 2
      4'b1011: if(next_bit) state <= 4'b1100;  // bit 3
      4'b1100: if(next_bit) state <= 4'b1101;  // bit 4
      4'b1101: if(next_bit) state <= 4'b1110;  // bit 5
      4'b1110: if(next_bit) state <= 4'b1111;  // bit 6
      4'b1111: if(next_bit) state <= 4'b0001;  // bit 7
      4'b0001: if(next_bit) state <= 4'b0000;  // stop bit
      default: state <= 4'b0000;
    endcase

    reg [7:0] RxD_data;
    always @(posedge clk)
    if(Baud8Tick && next_bit && state[3]) RxD_data <= {~RxD_bit_inv, RxD_data[7:1]};

    reg RxD_data_ready, RxD_data_error;
    always @(posedge clk)
    begin
      RxD_data_ready <= (Baud8Tick && next_bit && state==4'b0001 && ~RxD_bit_inv);  // ready only if the stop bit is received
      RxD_data_error <= (Baud8Tick && next_bit && state==4'b0001 &&  RxD_bit_inv);  // error if the stop bit is not received
    end

    reg [4:0] gap_count;
    always @(posedge clk)
    if (state!=0) gap_count<=0;
    else if(Baud8Tick & ~gap_count[4]) gap_count <= gap_count + 1;
    assign RxD_idle = gap_count[4];
    reg RxD_endofpacket;
    always @(posedge clk) RxD_endofpacket <= Baud8Tick & (gap_count==15);

    endmodule

    上面是原程序,下面是对划线部分的理解

    第二个划线的部分你可以单独仿真一下,是一个8计数器,计数范围是1000到1111,10二进制1010,是计数器的第3个时钟的计数。可以看出,接收一个数据位是用了8个baud8tick时钟,在第3个baud8tick时钟到来的时候对数据位进行采样。这样是为了能够在一个数据位宽度的中间对数据采样。
    下面的图看看吧 , 希望能理解
                                                                         一个数据位8个baud8tick
                                                               1                        3                                                              8                                                                                             ——     ——     ——     ——     ——     ——     ——     ——
                                 计数器的值:      1000   1001     1010    1011    1100   1101    1110    1111
                                   next-bit             ____________|TTTT|____________________________                          

    大概就是这个意思,其实如果把10改为11的话,可能更加好一些

    但是为什么bit_spacing[3]在0000计数到1111以后,高位就保持在“1”不动,我也就不太清楚了,高手可以分析一下

    还有  这个程序的波特率产生的部分我一直没有搞懂。

    还有,在state=0时,bit_spacing是从0000计数,在计数到1111以后,计数器的值就从1000到1111开始计数了。也就是说,bit_spacing是开始的16个时钟是0000到1111,以后就是一个8计数器了,计数范围从1000到1111
    至于state=0开始计数时,为什么要先计数16个时钟?这个我还没有完全理解,估计是跟起始位的检测相关吧。

    刚做了一个uart的fpga实现,今天看了这个接收的程序,觉得自己写的还是不好。
    没有进行校验,起始位和停止位的处理也没有这么完善
    不过还好,可以运行了


    收藏到:Del.icio.us




    评论

  • 遇见就是缘分!很高兴走进你的BLOG,看到你用心布置的小屋,觉得很不错呢!偶在这里给你介绍一个播放器,可以自由选择歌曲哦!添加了播放器后,我相信你的小屋会更加漂亮的,现在就让我来教你吧!!



    首先在www.koook.com申请号后登陆博客,在会员中心选择其他功能中的“我的音乐盒”,在音乐盒中选择了你喜欢的歌曲后,生成代码,并复制代码,那么,播放器的代码你就获得了,下面是添加代码。



    1.登陆BLOGBUS后,全部功能中点击参数设置

    2.在弹出列表中点击BLOG设置

    3.在自动刷新的页面下方的自定义HTML框内加入你复制的代码

    4.此时转到你的BLOG页面已经可以看到播放器了

    欢迎到我的小屋和我沟通一下哦……小屋地址:http://space.msn.koook.com

发表评论

您将收到博主的回复邮件
记住我