串口发送模块
前言:参考了小梅哥FPGA Xilinx教程哦!!!
一丶 简介
- Uart实际上就是将并行数据转换成串行数据进行传输。
- Uart是一种异步收发传输器,是双全工传输和接受。
- RS232,RS449,RS423等是各种Uart的接口标准和总线标准。
- 通常使用RXD为接受数据,TXD为发送数据。
二丶关键部分
- Uart设置包括数据位数,波特率大小,奇偶校验类型,停止位数。
- 常见的配置为8N1(8个数据位,无奇偶校验,1个停止位)。
需要使用11个脉冲来描述这个过程最为准确。 - 可以描述成:当第一个脉冲到来时,表示START,信号从高拉低,等待第二个脉冲来时,Bit0—Bit7以此传输,而后第十个脉冲到来时,表示传输结束,STOP位到来,信号拉高,并且要使得拉高时间在一个周期,即在第十个脉冲与第十一个脉冲之间都要保持高。
三丶设计
- 串口发送模块可以看成如下:
//波特率的选取
always@(*)
case(baud)
0:bps_DR = 1000000000/9600/20;
1:bps_DR = 1000000000/19200/20;
2:bps_DR = 1000000000/38400/20;
3:bps_DR = 1000000000/57600/20;
4:bps_DR = 1000000000/115200/20;
default: bps_DR = 1000000000/9600/20;
endcase
使用115200来传输1bit数据所需的时间为:1/115200 = t1 ,而FPGA的时钟为50MHz,周期为20ns,所以要计数到 t1 就需要 t1/20ns 化成秒表示即:10_0000_0000/9600/20 .
reg[17:0] div_cnt;
always@(posedge clk or negedge rst)begin
if(!rst) div_cnt <= 0;
else if(en) begin
if(div_cnt == bps_DR - 1) div_cnt <= 0;
else div_cnt <= div_cnt + 1'b1;
end
else div_cnt <= 0;
end
div_cnt 成为波特率时钟,当计数到传输1bit数据所需次数时,div_cnt + 1;
reg[3:0] bps_cnt;
always@(posedge clk or negedge rst)begin
if(!rst) bps_cnt <= 0;
else if(en)begin
if(div_cnt == 1) begin
if(bps_cnt == 11)bps_cnt <= 0;
else bps_cnt <= bps_cnt + 1'b1;
end
end
else bps_cnt <= 0;
end
bps_cnt用于记录当前处于什么状态,故只需当div_cnt = 1时,表示进入新状态时,bps_cnt+1,最多11个脉冲,11个状态。
always@(posedge clk or negedge rst)begin
if(!rst)tx <= 1;
else begin
case(bps_cnt)
1: tx <= 0;
2: tx <= rdata[0];
3: tx <= rdata[1];
4: tx <= rdata[2];
5: tx <= rdata[3];
6: tx <= rdata[4];
7: tx <= rdata[5];
8: tx <= rdata[6];
9: tx <= rdata[7];
10: tx <= 1;
11: tx <= 1;
default: tx <= 1;
endcase
end
end
always@(posedge clk or negedge rst)begin
if(!rst)done <= 0;
else if((bps_cnt == 10)&&(div_cnt == 1)) done <= 1;
else done <= 0;
end
传输完成的标志done:在计数到第十脉冲发出done信号,使用bps_cnt = 10 && div_cnt = 1来确保一达到第十脉冲就传输done。
reg en;
always@(posedge clk or negedge rst)begin
if(!rst)en <= 0;
else if(send_go) en <= 1;
else if(done) en <= 0;
end
传输开始的标志en:en持续时间是从start开始到最后一个bit传输结束。