实验的关键点:
1、串口通信模块设计的目的是用来发送数据的,因此需要有一个数据输入端口。
2、串口通信,支持不同的波特率,所以需要有一个波特率设置端口。
3、串口通信的本质就是将 8 位的并行数据通过一根信号线,在不同的时刻传输并行数据的不同位,通过多个时刻,最终将8位并行数据全部传出。
4、串口通信以 1 位的低电平标志串行传输的开始,待 8 位数据传输完成之后,再以 1 位的高电平标志传输的结束。
5、控制信号,控制并转串模块什么时候开始工作。send_en
6、发送完成标志信号。tx_done
框图:
Baud_set的位数跟支持波特率的种类数量有关,这里表示支持8种波特率。
UART发送一个字节时序图:
1 bit起始位,8 bit数据位,1 bit停止位。
bps_clk:波特率时钟,自己定义的内部程序参考。每个bps_clk的宽度是一个系统时钟周期,每当bps_clk编程高电平时,让uart_tx的值更新一次。
按照一个完整的字节包括 1 位起始位、 8 位数据位、 1 位停止位即总共十位数据来算,要想完整的实现这是个数据的发送,就需要11个波特率时钟脉冲,第 1 个脉冲标记一次传输的起始,第 11 个脉冲标记一次传输的结束。
代码如下:
module uart_byte_tx(
clk, reset_n, data_in, send_en, baud_set,
uart_tx, tx_done
);
input clk;
input reset_n;
input [7:0] data_in;
input send_en;
input [2:0] baud_set;
output reg uart_tx;
output reg tx_done;
/*
buad_set = 0,波特率 = 9600;
buad_set = 1,波特率 = 19200;
buad_set = 2,波特率 = 38400;
buad_set = 3,波特率 = 57600;
baud_set = 4,波特率 = 115200;
*/
reg [17:0] bps_DR; //根据波特率的值来设置bps_DR的值
reg [17:0] div_cnt; //分频得到一个基本的时钟
reg [3:0] bps_cnt; //计数传输数据的位数
wire bps_clk;
assign bps_clk = (div_cnt == 1);
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 or negedge reset_n)begin
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
else div_cnt <= 0;
end
always@(posedge clk or negedge reset_n)begin
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;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)begin
//空闲的时候使uart_tx为高电平,确保开始传输时,uart_tx是由1变成0的
uart_tx <= 1'b1;
tx_done <= 1'b0;//只有在完成传输的那一瞬间为1,其他时间都为0
end
else begin
case(bps_cnt)
1: begin uart_tx <= 0;tx_done <= 1'b0;end
2: uart_tx <= data_in[0];
3: uart_tx <= data_in[1];
4: uart_tx <= data_in[2];
5: uart_tx <= data_in[3];
6: uart_tx <= data_in[4];
7: uart_tx <= data_in[5];
8: uart_tx <= data_in[6];
9: uart_tx <= data_in[7];
10: uart_tx <= 1;
11:begin uart_tx <= 1; tx_done <= 1'b1; end//停止位要保持一个脉冲的时间
default:uart_tx <= 1;
endcase
end
end
endmodule