小梅哥的FPGA教学视频跟学记录2
1.通信原理
网上关于串口通信原理已经写得很详细,在此不做赘述
以下是本次实验所用到通信方式
从图中可以看到发送一个八位数据需要保持十个周期(多加一个起始位和一个停止位),那么这里在逻辑设计文件里就要注意如何能够保持十个完整的周期。
2.
design 文件代码:
Send_en; //发送数据的使能信号
Tx_Done; //标志数据发送完成
bps_clk; //作为周期计数的触发信号
div_cnt; //基本计数器,一个周期
bps_cnt; //用于计数发送数据位数(需要能够保持完成的是10个周期),所以在bps_cnt=11时才清零,如果等于10就清零,那么只有很短时间的时间发送停止位,达不到预期效果。
大家也可能疑惑从0开始计数,计到11不就12个周期了吗?
这里是因为开始发送完停止位bps_cnt就清零,如果没有新的数据bps_cnt会保持等于0的状态,此时的uart_tx应该为case语句的default状态;所以case语句从1开始赋值。1为起始位,2为Data[0],9为Data[7],10为停止位,11发送Tx_Done标志数据发送完成。此时即使11不能保持一个完整周期也无所谓,数据已经发送完毕。
module uart_byte_tx(
Data,
Send_en,
Clk,
Reset_n,
Baud_set,
uart_tx,
Tx_Done
);
input [7:0] Data;
input Send_en;
input Clk;
input Reset_n;
input [2:0] Baud_set;
output reg uart_tx;
output reg Tx_Done;
//最小时间单元 1s/115200=8680(每一位需要的时间)
/*8680/20=434(传输一个数据需要计数434)
比特率:是指每秒传送的比特(bit)数。
单位为 bps(Bit Per Second),比特率越高,每秒传送数据就越多。
波特率:表示每秒钟传送码元符号的个数,是衡量数据传送速率的指标。
在信息传输通道中,携带数据信息的信号单元叫码元,每秒钟通过信道传输的码元数
称为码元传输速率,简称波特率。
*/
//Baud_set = 0: 就让波特率=9600
//Baud_set = 1: 就让波特率=19200
//Baud_set = 2: 就让波特率=38400
//Baud_set = 3: 就让波特率=57600
//Baud_set = 4: 就让波特率=115200
reg [17:0]bps_DR; //18位是最低波特率300对应算出的计数器需要最多位
always@(*)
case(Baud_set)
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
wire bps_clk;
reg [17:0] div_cnt;//计数器,一个周期
assign bps_clk = ( div_cnt==bps_DR-1);
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(Send_en) begin
if(div_cnt==bps_DR-1)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'b1;
end
reg [17:0] bps_cnt; //用于计数发送数据位数
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
bps_cnt <= 0;
else if(Send_en) begin
if (bps_clk)begin
if(bps_cnt == 11) //十位数据要保证十个周期,相当于十段线段,需要十一个点
bps_cnt <= 0;
else
bps_cnt <= bps_cnt + 1'b1;
end
end
else
bps_cnt <= 0;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n) begin
uart_tx <=1'b1;
Tx_Done <= 0;
end
else begin
case(bps_cnt)
1:begin uart_tx<=0;Tx_Done <=1'b0; end
2:uart_tx <= Data[0];
3:uart_tx <= Data[1];
4:uart_tx <= Data[2];
5:uart_tx <= Data[3];
6:uart_tx <= Data[4];
7:uart_tx <= Data[5];
8:uart_tx <= Data[6];
9:uart_tx <= Data[7];
10:uart_tx <= 1;
11:begin uart_tx <= 1;Tx_Done <= 1'b1; end
default:begin uart_tx<=1;Tx_Done <=1'b0; end
endcase
end
endmodule
bps_DR的计算:
tb文件代码:
module uart_byter_tx_tb();
reg [7:0]Data ;
reg Send_en ;
reg Clk ;
reg Reset_n ;
reg [2:0] Baud_set;
wire uart_tx;
wire Tx_Done ;
uart_byte_tx uart_byte_tx(
.Data (Data),
.Send_en (Send_en),
.Clk (Clk),
.Reset_n (Reset_n),
.Baud_set (Baud_set),
.uart_tx (uart_tx),
.Tx_Done (Tx_Done)
);
initial Clk =1;
always#10 Clk=~Clk;
initial begin
Reset_n=0;
Data=0;
Baud_set=4;
Send_en=0;
#201;
#100;
Reset_n=1;
Data=8'h57;
Send_en=1;
@(posedge Tx_Done); //阻塞语句,直到Tx_Done=1才进去下一句,否则一直在此死循环
Send_en=0;
#2000;
Data=8'h75;
Send_en=1;
@(posedge Tx_Done); //阻塞语句,直到Tx_Done=1才进去下一句,否则一直在此死循环
Send_en=0;
$stop;
end
endmodule
仿真结果如下:可以看到bps_cnt如预期计数,从2-9对应的uart_tx的电平对应Data[7:0](注意先发送低位),其中可以看到bps_cnt的“11”周期较短,也成功发送Tx_Done。
。