-
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实现,今天看了这个接收的程序,觉得自己写的还是不好。
没有进行校验,起始位和停止位的处理也没有这么完善
不过还好,可以运行了随机文章:
FPGA验证简介 2006年04月20日异步FIFO结构及FPGA设计 2006年03月19日指针:我眼中的指针--学习指针不可少的好文章 2006年05月08日十进制与其他进制(2-9进制)的相互转换 (C语言) 2006年03月16日verilog代码编写规范 2006年03月13日
收藏到:Del.icio.us






评论
首先在www.koook.com申请号后登陆博客,在会员中心选择其他功能中的“我的音乐盒”,在音乐盒中选择了你喜欢的歌曲后,生成代码,并复制代码,那么,播放器的代码你就获得了,下面是添加代码。
1.登陆BLOGBUS后,全部功能中点击参数设置
2.在弹出列表中点击BLOG设置
3.在自动刷新的页面下方的自定义HTML框内加入你复制的代码
4.此时转到你的BLOG页面已经可以看到播放器了
欢迎到我的小屋和我沟通一下哦……小屋地址:http://space.msn.koook.com