一、UART基本概念
UART(Universal Asynchronous Receiver/Transmitter)是一种异步串行通信协议,采用单工或半双工模式,通过两根信号线(TX发送、RX接收)实现数据传输。其核心规则包括:
- 波特率:传输速率,如9600、115200等,收发双方需严格同步。
- 数据帧格式:
- 起始位:1位逻辑0,标志传输开始
- 数据位:5-8位(通常为8位),从低位到高位发送
- 校验位:1位奇偶校验(可选)
- 停止位:1/1.5/2位逻辑1,标志传输结束
- 空闲位:持续高电平
-
分频系数
公式: 分频系数=系统时钟频率 / 波特率
二、FPGA实现
module uart_byte_tx(
clk,
rst,
Data,
send_en,
Baud_set,
uart_tx,
Tx_done
);
input clk,rst;
input [7:0]Data;
input [2:0]Baud_set;
input send_en;
output reg uart_tx;
output reg Tx_done;
//Baud_set=0 波特率=9600
// 1 19200
// 2 38400
// 3 57600
// 4 115200
reg [17:0]div_counter;
reg [17:0]bps_DR;
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
always@(posedge clk,negedge rst)
begin
if (!rst)
div_counter<=0;
else if (send_en==1)begin //send_en高电平开始计数
if(div_counter==bps_DR-1)
div_counter<=0;
else
div_counter<=div_counter+1;
end
end
reg [3:0]bps_cnt;
always@(posedge clk,negedge rst) //定义大计数器11位的
begin
if (!rst)
bps_cnt<=0;
else if(send_en)
begin
if (div_counter==bps_DR-1)
begin
if(bps_cnt==10)
bps_cnt<=0;
else
bps_cnt<=bps_cnt+1;
end
end
else
bps_cnt<=0;
end
always@(posedge clk,negedge rst)
if(!rst)
begin
uart_tx<=1;
Tx_done<=0;
end
else
begin
case(bps_cnt)
0:begin uart_tx<=0;Tx_done<=0; end //Tx_done置为0
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;
10:begin uart_tx<=1;Tx_done<=1;end //uart_tx默认是保持高电平的
default:uart_tx<=1;
endcase
end
endmodule
仿真验证代码
`timescale 1ns / 1ns
module uart_byte_tx_tb();
reg clk,rst;
reg [7:0]Data;
reg [2:0]Baud_set;
reg send_en;
wire uart_tx;
wire Tx_done;
uart_byte_tx uart_byte_tx(
.clk(clk),
.rst(rst),
.Data(Data),
.send_en(send_en),
.Baud_set(Baud_set),
.uart_tx(uart_tx),
.Tx_done(Tx_done)
);
initial clk=1;
always #10 clk=~clk;
initial begin
rst=0;
Data=0;
send_en=0;
Baud_set=4;
#201;
rst=1;
#100;
Data=8'h57;
send_en=1;
#20;
@(posedge Tx_done);
send_en=0;
#20000;
Data=8'h75;
send_en=1;
#20;
@(posedge Tx_done);
#20000;
send_en=0;
$stop;
end
endmodule
但此时有一些问题,在uart_tx在空闲状态应该是高电平。
放大会发现此时uart_tx变为零是因为bps_cnt等于0导致的。因为下列语句导致的
case(bps_cnt)
0:begin uart_tx<=0;Tx_done<=0; end //Tx_done置为0
1:uart_tx<=Data[0];
经过调试后:波形符合理论结果
调试后的代码如下:
module uart_byte_tx(
clk,
rst,
Data,
send_en,
Baud_set,
uart_tx,
Tx_done
);
input clk,rst;
input [7:0]Data;
input [2:0]Baud_set;
input send_en;
output reg uart_tx;
output reg Tx_done;
//Baud_set=0 波特率=9600
// 1 19200
// 2 38400
// 3 57600
// 4 115200
reg [17:0]div_counter;
reg [17:0]bps_DR;
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
always@(posedge clk,negedge rst)
begin
if (!rst)
div_counter<=0;
else if (send_en==1)begin //send_en高电平开始计数
if(div_counter==bps_DR-1)
div_counter<=0;
else
div_counter<=div_counter+1;
end
else
div_counter<=0;
end
reg [3:0]bps_cnt;
always@(posedge clk,negedge rst) //定义大计数器11位的
begin
if (!rst)
bps_cnt<=0;
else if(send_en)
begin
if (div_counter==1)
begin
if(bps_cnt==11)
bps_cnt<=0;
else
bps_cnt<=bps_cnt+1;
end
end
else
bps_cnt<=0;
end
always@(posedge clk,negedge rst)
if(!rst)
begin
uart_tx<=1;
Tx_done<=0;
end
else
begin
case(bps_cnt)
1:begin uart_tx<=0;Tx_done<=0; end //Tx_done置为0
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;end //uart_tx默认是保持高电平的
default:uart_tx<=1;
endcase
end
endmodule
三、设计一个数据发送器每10ms以115200的波特率发送给数据,每次发送的数据比之前遥感数据大1
底层模块:
module uart_byte_tx(
clk,
rst,
Data,
send_en,
Baud_set,
uart_tx,
Tx_done
);
input clk,rst;
input [7:0]Data;
input [2:0]Baud_set;
input send_en;
output reg uart_tx;
output reg Tx_done;
reg [17:0]div_counter;
reg [17:0]bps_DR;
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;
assign bps_clk=(div_counter==1);
always@(posedge clk,negedge rst)
begin
if (!rst)
div_counter<=0;
else if (send_en==1)begin //send_en高电平开始计数
if(div_counter==bps_DR-1)
div_counter<=0;
else
div_counter<=div_counter+1;
end
else
div_counter<=0;
end
reg [3:0]bps_cnt;
always@(posedge clk,negedge rst) //定义大计数器11位的
begin
if (!rst)
bps_cnt<=0;
else if(send_en)
begin
if (div_counter==1)
begin
if(bps_cnt==11)
bps_cnt<=0;
else
bps_cnt<=bps_cnt+1;
end
end
else
bps_cnt<=0;
end
always@(posedge clk,negedge rst)
if(!rst)
uart_tx<=1; //默认为高电平输出
else
begin
case(bps_cnt)
1:uart_tx<=0; //Tx_done置为0
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:uart_tx<=1; //uart_tx默认是保持高电平的
default:uart_tx<=1;
endcase
end
always@(posedge clk,negedge rst)
if(!rst)
Tx_done<=0;
else if((bps_clk==1)&&(bps_cnt==10))
Tx_done<=1;
else
Tx_done<=0;
endmodule
顶层模块:
module uart_tx_test(
clk,
rst,
uart_tx
);
input clk;
input rst;
output uart_tx;
reg send_en;
reg [7:0]Data;
uart_byte_tx uart_byte_tx(
.clk(clk),
.rst(rst),
.Data(Data),
.send_en(send_en),
.Baud_set(3'd4), //波特率为11520
.uart_tx(uart_tx),
.Tx_done(Tx_done)
);
reg [18:0]counter;
always@(posedge clk,negedge rst)
begin
if (!rst)
counter<=0;
else if (counter==499999) //10ms
counter<=0;
else
counter<=counter+1;
end
always@(posedge clk,negedge rst)
if(!rst)
send_en<=0;
else if (counter==1)
send_en<=1;
else if(Tx_done)
send_en<=0;
always@(posedge clk,negedge rst)
if(!rst) Data<=0;
else if(Tx_done)
Data<=Data+1;
endmodule
仿真测试代码
`timescale 1ns / 1ps
module uart_tx_test_tb(
);
reg clk,rst;
wire uart_tx;
uart_tx_test uart_tx_test(
.clk(clk),
.rst(rst),
.uart_tx(uart_tx)
);
initial clk=1;
always #10 clk=~clk;
initial begin
rst=0;
#201;
rst=1;
#50000000;
$stop;
end
endmodule
放大
做到了每10ms发送一次数据,且Data逐次+1