一、设计思路
模块框图:
div_cnt:产生波特率时钟
bps_cnt:对波特率时钟进行计数
二、设计目标
实现8位数据的传输,数据由外部输入。
三、UART.v文件设计
module UART(
send_en,
data_byte,
baud_set,
clk,
reset_n,
uart_tx,
tx_done,
uart_state
);
input send_en;
input [7:0]data_byte;
input [2:0]baud_set;
input clk;
input reset_n;
output reg uart_tx;
output reg tx_done;
output uart_state;
reg [17:0]div_cnt;//定义一个基本计数器
reg [17:0]bps_DR;
wire bps_clk;
assign bps_clk =(div_cnt == 1);
//根据不同的波特率设置基本计数器不同的最大值
always@( posedge clk or negedge reset_n)begin
if(!reset_n)
bps_DR <= 16'd5208;
else case(baud_set)
3'b000:bps_DR <= 16'd5208;
3'b001:bps_DR <= 16'd2604;
3'b010:bps_DR <= 16'd1302;
3'b011:bps_DR <= 16'd868;
3'b100:bps_DR <= 16'd434;
default:bps_DR <= 16'd5208;
endcase
end
//设置基本计数器,就是一个单元的计数器
always@( posedge clk or negedge reset_n)begin
if(!reset_n)
div_cnt <= 16'd0;
else if(send_en)begin
if(div_cnt == bps_DR-1)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt+1'b1;
end
else
div_cnt <= 16'd0;
end
reg [3:0]bps_cnt;
//相当于加入计数器2,当基本计数器满一次,bps_cnt开始计数一次,然后总共需要10个状态,因此需要四位
//(div_cnt == 1),之所以写成1,因为状态从0001开始变化,因此需要是0状态保持的时间短一点
always@( posedge clk or negedge reset_n)begin
if(!reset_n)
bps_cnt <= 16'd0;
else if(send_en)begin
if(div_cnt == 1)begin
if(bps_cnt == 4'b1011)
bps_cnt <= 16'd0;
else
bps_cnt <= bps_cnt+1'b1;
end
end
else
bps_cnt <= 16'd0;
end
//用bps_cnt的状态来对应输出,相当于多选一数据选择器
always@( posedge clk or negedge reset_n)begin
if(!reset_n)begin
uart_tx <= 1'b1;
tx_done <= 1'b0;
end
else case(bps_cnt)
4'b0001:begin uart_tx <= 1'b0; tx_done <= 1'b0;end
4'b0010:uart_tx <= data_byte[0];
4'b0011:uart_tx <= data_byte[1];
4'b0100:uart_tx <= data_byte[2];
4'b0101:uart_tx <= data_byte[3];
4'b0110:uart_tx <= data_byte[4];
4'b0111:uart_tx <= data_byte[5];
4'b1000:uart_tx <= data_byte[6];
4'b1001:uart_tx <= data_byte[7];
4'b1010:uart_tx <= 1'b1;
4'b1011:begin uart_tx <= 1'b1; tx_done <= 1'b1;end
default:uart_tx <= 1'b1;
endcase
end
endmodule
四、UART_tb.v文件代码
`timescale 1ns / 1ns
module UART_tb;
reg clk;
reg send_en;
reg [2:0]baud_set;
reg reset_n;
reg [7:0]data_byte;
wire uart_tx;
wire tx_done;
wire uart_state;
UART UART_tx(
.send_en(send_en),
.data_byte(data_byte),
.baud_set(baud_set),
.clk(clk),
.reset_n(reset_n),
.uart_tx(uart_tx),
.tx_done(tx_done),
.uart_state(uart_state)
);
initial clk=1;
always #10 clk=~clk;
initial begin
data_byte=0;
reset_n=0;
send_en=0;
baud_set=4'b0100;
#201;
#100;
reset_n=~reset_n;
data_byte=8'b1010_1101;
send_en=1;
#20;
@(posedge tx_done);
send_en=0;
#20000;
data_byte=8'b1110_1001;
send_en=1;
#20;
@(posedge tx_done);
send_en=0;
#20000;
$stop;
end
endmodule
五、仿真波形
由波形可知,数据从bps_cnt为1时开始传输,即开始传输起始位,此时send_en也为高电平,当停止位传输结束,send_en变成低电平,UART_tx此时在空闲状态变成高电平,同时波特率也对应设置的115200,传输数据正确。