基于FPGA的串口发送(E/FPGACode/uart_tx_new)
一、串口
- 串口简称UART
- 设计的目的是用来发送数据的,因此需要有一个数据输入端口,用来发送这8bit数据。类似于实验中的Ctrl,用来指定亮灭模式
- 支持不同的波特率,所以需要有一个波特率设置端口。类似于计数器实验中的Time
- 如下图所示,本质是把这8位的并行数据通过一根信号线在不同的时刻分别以高低电平一位一位得传出去。并行输入,串行输出
- 以1位的低电平标志串行传输的开始,待8位数据传输完成之后,再以1位的高电平标志传输的结束。
- 数据什么时候发?答:发送开始信号-Send_en
- 一串数据什么时候发送结束?答:发送完成标志信号-Tx_Done
二、串口简易图
uart_tx=起始位+data[7:0]+结束位
三、 问题
module uart_byte_tx(
input [7:0] data,
input Send_en,
input Clk,
input Reset_n,
input [2:0] Baud_set,//假设只支持8种波特率
output reg uart_tx,
output reg Tx_Done
);
reg [17:0] div_cnt;
//计算不同波特率时计数的次数
//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;
always@(*)begin
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
end
//计数基本时间单元
always@(posedge Clk or negedge Reset_n)begin
if(!Reset_n)begin
div_cnt<=0;
end else if(Send_en)begin
if(div_cnt == bps_DR-1) begin
div_cnt<=0;
end else begin
div_cnt<=div_cnt+1'b1;
end
end else
div_cnt<=0;
end
reg [3:0] bps_cnt;
//发送10个段:开始+8数据+结束,一共需要11个clk确定
always@(posedge Clk or negedge Reset_n)begin
if(!Reset_n)begin
bps_cnt<=0;
end else if(Send_en)begin
if(div_cnt == bps_DR-1) begin
if(bps_cnt==11)
bps_cnt<=0;
else
bps_cnt<=bps_cnt+1'b1;
end
end else
bps_cnt<=0;
end
always@(posedge Clk or negedge Reset_n)begin
if(!Reset_n)begin
Tx_Done<=1'b0;
uart_tx<=1'b1;
end else begin
case(bps_cnt)
0:begin uart_tx<=1'b0;Tx_Done<=0;end
1:uart_tx<=data[0];
2:uart_tx<=data[1];
3:uart_tx<=data[2];
4:uart_tx<=data[3];
5:uart_tx<=data[4];
6:uart_tx<=data[5];
7:uart_tx<=data[6];
8:uart_tx<=data[7];
9:uart_tx<=1'b1;
10:begin uart_tx=1'b1;Tx_Done<=1;end
default:uart_tx=1'b1;
endcase
end
end
endmodule
1、当Send_en从0变成1时,代表开始传递数据。uart_tx初始为1,所以当send_en上升沿时,uart_tx应该同时变成0,代表传输START(低电平)位。
但是由图片可知,uart_tx大概早了将近1位的时间就将其拉为低电平。
- 分析:由代码可知,当bps_cnt=0时,将uart_tx=0;
- 解决方法:将case(bps_cnt)改成从1-11.
改完之后的波形图如上图所示,当bps_cnt=1时,才将uart_tx=0,传输开始位。
2、两个蓝色的marker标志在这个空闲时间中,是让uart_tx一直保持为1。但是这个有必要吗?如何进行更改?
- 分析:这两个marker是因为当Send_en为1时,才开始计时,当div_cnt == bps_DR-1,即div_cnt计满一次,bps_cnt才+1.所以就相当于多计了一个bps_cnt.
if(div_cnt == bps_DR-1) begin
if(bps_cnt==11)
bps_cnt<=0;
else
bps_cnt<=bps_cnt+1'b1;
end
- 修改:当div_cnt=1时,就进行+1.
if(div_cnt == 1) begin
if(bps_cnt==11)
bps_cnt<=0;
else
bps_cnt<=bps_cnt+1'b1;
end
四、 串口发送数据任务
使用前面设计的串口发送模块,设计一个数据发送器,每10ms以115200的波特率发送一个数据,每次发送的数据比前一个数据大一(计数器)
问题一
//每隔10ms发送一个数据
always @(posedge Clk or negedge Reset_n) begin
if (!Reset_n) begin
counter<=0;
end
else if (counter == 500000-1) begin
counter<=0;
end else
counter<=counter+1;
end
always @(posedge Clk or negedge Reset_n) begin
if (!Reset_n) begin
Send_en<=0;
end
else if (counter==1) begin
Send_en<=1;
end else if(Tx_Done) begin
Send_en<=0;
end
end
always @(posedge Tx_Done or negedge Reset_n) begin
if (!Reset_n) begin
data<=0;
end else begin
data <= data+1'b1;
end
end
波形图:1、Tx_Done一直为1,导致poedeg Tx_Done检测不到,所以data无法进行自加
2、继续分析,Tx_Done什么时候0->1,1->0
看E://uart_byte_tx,当bps_cnt=1时,Tx_Done=1,当bps_cnt=11时,Tx_Done=1。
当Tx_Done=1时,Send_En就会变成0.此时bps_cnt就不会再+1.由此成了一个死循环.
修改:可以从波形图看到,bps_cnt是从0->a,然后就一直持续为0.刚好我们前面有一个为0的状态位没有用到。此时就将bps_cnt=0时,
问题二:串口波形图的时序要求,Tx_Done从3个节拍改为1个节拍,所以不能使用posedge Tx_Done
分析:为什么是3个周期?
当bps_cnt=11时,Tx_Done=1.此时,Send_En从1->0.但在下一个节拍才能变为0(非阻塞赋值)。再到下一个节拍才能知晓已经为0,此时bps_cnt才从11变成0.当bps_cnt=0时,再过一个节拍Tx_Done=0.
修改:
always@(posedge Clk or negedge Reset_n)begin
if(!Reset_n)begin
Tx_Done<=1'b0;
uart_tx<=1'b1;
end else begin
case(bps_cnt)
0:Tx_Done<=0;
1:uart_tx<=1'b0;
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'b1;
11:uart_tx=1'b1;
default:uart_tx=1'b1;
endcase
end
end
always @(posedge Clk or negedge Reset_n)begin
if(!Reset_n)
Tx_Done<=0;
else if((bps_cnt==10)&&(bps_clk==1))
Tx_Done<=1;
else
Tx_Done<=0;
end
五、板级编译
最后上板子调试,发现一直接收的是00,后看了一篇博客发现是在不同的always块中对同一个信号进行赋值。这是不允许的!!!!!
这是那篇博客/提问链接:https://ask.csdn.net/questions/7737125文章来源:https://www.toymoban.com/news/detail-614831.html
六、 运行成功
串口之数据传输文章来源地址https://www.toymoban.com/news/detail-614831.html
到了这里,关于基于FPGA的串口发送的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!