UART协议的详细介绍,请点击此处UART的详解
UART发送模块大致有以下几个行为:
【1】数据未开始传输(复位状态reset=1)
【2】数据即将开始传输(电路处于空闲状态,但数据传输信号有效,即~tx_busy & new_tx_data)
【3】数据正在开始传输,时钟信号ce_16未计满16次,即未产生ce_1信号(每产生一次ce_1信号,移位科寄存器要移位一次)
【4】数据正在开始传输,时钟信号ce_16计满16次,产生ce_1信号,移位寄存器内的数据,循环右移一位,并将此bit送到串行输出端进行串行输出
【5】随着ce_1信号不断产生,数据不断移位传输,当bit计数计数器bit_count(用来计数已传输完成的数据bit)计满九次(已传输包括开始位,8个数据位)。
【6】当ce_16信号再次产生时,bit_count计数满10位,停止位传输完成,预示着一个字符的数据已经传输完成。电路重新恢复到空闲状态(!tx_busy)。
下面给出UART发送模块的verilog实现:
// uart transmit module
module uart_tx
(
clock,
reset,
ce_16,
tx_data,
new_tx_data,
ser_out,
tx_busy
);
input clock;
input reset;
input ce_16; //波特率时钟信号
input [7:0] tx_data; // 待传输数据
input new_tx_data; // 断言,表示有一个新的数据字节要传输
output ser_out; // 串行数据输出
output tx_busy; // 数据正在传输
// internal wires
wire ce_1; // clock enable at bit rate(产生一个脉冲则数据传输完一位)
// internal registers
reg ser_out;
reg tx_busy;
reg [3:0] count16; //产生ce_1脉冲信号的计数器
reg [3:0] bit_count; //计数已传输数据bit的个数
reg [8:0] data_buf; //移位寄存器,存储即将传输的数据
//模块一.ce_1脉冲的产生,脉冲c计数器,16个ce_16得到1个ce_1
always @ (posedge clock or posedge reset)
begin
if (reset)
count16 <= 4'b0;
else if (tx_busy & ce_16) //只有发射机处于发送数据的状态时,ce_16脉冲计数,转换为ce_1脉冲
count16 <= count16 + 4'b1;
else if (~tx_busy) //不发送数据,则此寄存器清零
count16 <= 4'b0;
end
// ce_1 pulse indicating output data bit should be updated
assign ce_1 = (count16 == 4'b1111) & ce_16; //ce_1脉冲指示更新(计数器计满后,在来一个脉冲,则会产生一个ce_1时钟脉冲信号)
// tx_busy flag (电路状态的一些行为)
always @ (posedge clock or posedge reset)
begin
if (reset)
tx_busy <= 1'b0;//复位低电平
else if (~tx_busy & new_tx_data)//未传输数据,但新数据信号有效时,变为高电平,意思是数据正在传输
tx_busy <= 1'b1;
else if (tx_busy & (bit_count == 4'h9) & ce_1) //数据已经传输9位,在传输一位,传输停止,tx_busy表示空闲状态
tx_busy <= 1'b0;
end
// output bit counter (输出的数据位数计算)
always @ (posedge clock or posedge reset)
begin
if (reset)
bit_count <= 4'h0; //复位寄存器清零
else if (tx_busy & ce_1) //电路处于传输数据的状态,当ce_1脉冲产生,那么数据传输完成一位
bit_count <= bit_count + 4'h1;
else if (~tx_busy) //如果电路处于未传输的状态,那么没有数据传输,寄存器为0
bit_count <= 4'h0;
end
// data shift register (数据移位寄存器)
always @ (posedge clock or posedge reset)
begin
if (reset)
data_buf <= 9'b0;
else if (~tx_busy) //未传输数据时,寄存器存放的是起始位和待传输数据位
data_buf <= {tx_data, 1'b0};
else if (tx_busy & ce_1) //当一位数据传输完成后,移位寄存器中的数据移位1bit
data_buf <= {1'b1, data_buf[8:1]};//存储的数据右移
end
// output data bit (数据的串行输出)
always @ (posedge clock or posedge reset)
begin
if (reset)
ser_out <= 1'b1;
else if (tx_busy)
ser_out <= data_buf[0];//使用右移移位寄存器将数据不断送到最低位,从而不断的送到串行输出端
else
ser_out <= 1'b1;
end
endmodule
参考文献:
【1】opencores