目录
一、UART串口协议时序图
概括:起始位0 + 8位数据位 + 停止位1(空闲状态输出高电平)
每一位输出时间=1s/波特率(波特率为一秒发送数据个数)

二、Verilog 实现
(1)设计要求
1.可设置波特率(115200、9600等等)
2.起始位0 + 8位数据位 + 停止位1(空闲状态输出高电平)
3.无校验位
(2)设计模块
`timescale 1ns / 1ps
module uart_tx(//串口数据发送模块,可设置波特率,串行输出
input wire clk, //50MHz 20ns
input wire rst_n,
input wire tx_start, //开始发送标志信号
input wire [7:0] data, //待发送数据
input wire [2:0] baud_rate, //设置波特率
output reg tx, //串行数据输出
output reg tx_done //发送结束标志信号
);
reg tx_en = 1'b0; //发送使能信号
reg [7:0] data_reg = 8'b0; //待发送数据寄存器
reg [3:0] data_bit = 4'd0; //计数当前输出位数
reg [17:0]count = 18'd1;//分频计数
reg [17:0]count_max = 18'd1;//分频计数上限,18位由波特率300算出(1s/300/20ns=166666个clk周期)
always@(posedge clk or negedge rst_n) begin //收到开始发送信号高电平脉冲,将待发送数据存入寄存器(避免信号中途有误)
if(!rst_n)
data_reg <= 8'b0;
else if(tx_start)
data_reg <= data;
else
data_reg <= data_reg;
end
always@(posedge clk or negedge rst_n) begin //发送使能信号
if(!rst_n)
tx_en <= 1'b0;
else if(tx_start)
tx_en <= 1'b1;//收到开始发送标志位高电平脉冲,发送使能信号置1
else if(tx_done)
tx_en <= 1'b0;//收到发送结束标志位高电平脉冲,发送使能信号置0
end
always@(*) begin //根据波特率设置波特率分频器计数上限
if(!rst_n)
count_max <= 18'd434;//默认波特率=115200
else begin
case(baud_rate)
3'b000: count_max <= 18'd434; //115200
3'b001: count_max <= 18'd868; //57600
3'b010: count_max <= 18'd1302; //38400
3'b011: count_max <= 18'd2604; //19200
3'b100: count_max <= 18'd5208; //9600
3'b101: count_max <= 18'd20833; //2400
3'b110: count_max <= 18'd41666; //1200
3'b111: count_max <= 18'd166666;//300
default: count_max <= 18'd434;
endcase
end
end
always@(posedge clk or negedge rst_n) begin //波特率分频器(tx_en使能),计满一次发送一位
if(!rst_n || !tx_en)//复位或未使能
count <= 18'd1;
else if(tx_en)begin
if(count == count_max)
count <= 18'd1;
else
count <= count + 18'd1;
end
end
always@(posedge clk or negedge rst_n) begin //位计数器,对应当前发送的位数
if(!rst_n)
data_bit <= 4'd0;//1-10为有效状态
else if(count == count_max)begin//计满一次
if(data_bit == 4'd9)
data_bit <= 4'd0;
else
data_bit <= data_bit + 4'd1;
end
end
always@(*) begin //串行发送数据(空闲高电平,起始位0,从低位发送,停止位1)
if(!rst_n || !tx_en)
tx <= 1'b1; //复位或未使能为空闲高电平
else begin
case(data_bit)
0: tx <= 1'b0;//起始位0
1: tx <= data_reg[0];
2: tx <= data_reg[1];
3: tx <= data_reg[2];
4: tx <= data_reg[3];
5: tx <= data_reg[4];
6: tx <= data_reg[5];
7: tx <= data_reg[6];
8: tx <= data_reg[7];
9: tx <= 1'b1;//停止位1
default: tx <= 1'b1;
endcase
end
end
always@(*) begin //结束发送标志信号
if(!rst_n)
tx_done <= 1'b0;
else if(data_bit == 9 && count == count_max)//停止位输出结束时
tx_done <= 1'b1;
else
tx_done <= 1'b0;
end
endmodule
(3)测试模块
以波特率115200发送两次信息,第一次发送01011011,第二次发送01111110
`timescale 1ns / 1ps
module uart_tx_tb();
reg clk_tb; //clk为 50MHz 20ns
reg rst_n_tb;
reg tx_start_tb; //发送开始标志位信号
reg [7:0] data_tb; //待发送数据
reg [2:0] baud_rate_tb; //设置波特率
wire tx_tb; //串行数据输出
wire tx_done_tb; //发送完成标志位信号
always #10 clk_tb =~clk_tb;
initial begin
clk_tb = 1'b0;
rst_n_tb = 1'b0;
#15;
rst_n_tb = 1'b1;
data_tb[7:0] = 8'b0101_1011;
baud_rate_tb[2:0] = 3'b000;//baud rate = 115200
tx_start_tb = 1'b1;
#20
tx_start_tb = 1'b0;
#100000;
data_tb[7:0] = 8'b0111_1110;
tx_start_tb = 1'b1;
#20
tx_start_tb = 1'b0;
#100000;
$finish;
end
uart_tx uart_tx(
.clk (clk_tb),
.rst_n (rst_n_tb),
.baud_rate (baud_rate_tb),
.tx_start (tx_start_tb),
.data (data_tb),
.tx (tx_tb),
.tx_done (tx_done_tb)
);
endmodule
(4)仿真波形
完整波形如图所示:测试中共发送两次信息,波特率经测量为正确,同时 tx 两次发送数据结果格式与内容无误,空闲状态均为高电平。最后发送结束标志位tx_done有一个高电平。

UART串口协议Verilog实现与仿真
7609

被折叠的 条评论
为什么被折叠?



