由于波特率发生器产生的时钟信号bclk的频率为9600Hz的16倍,因此在发送器中,每16个bclk周期发送一个有效比特,发送数据格式严格按照图13-3所示的串口数据帧来完:首先是起始位(发送端口txd从逻辑1转化为逻辑0,并持续1/9600s),其次是8个有效数据比特(低位在前,高位在后),最后是一位停止位(没有添加校验位)。
整个发送模块的状态机包含5个状态:s_idle、s_start、s_wait、s_shift以及s_stop,其状态转移图如图13-6所示。
其中,s_idle为空闲状态,当复位信号有效或者发送任务已完成时,发送模块就处于s_idle状态,等待下一个发送指令(tx_cmd)的到来。在s_idle中,发送完成指示tx_ready为高电平,表明随时可以接收外部的发送指令。tx_cmd信号高有效,且持续时间为一个bclk信号的周期,其由顶层模块根据外部按键响应同步整形得到。当tx_cmd有效时,发送模块的下一状态为s_start。
s_start为发送模块的起始状态,拉低tx_ready信号,表明发送模块正处于工作中,并拉低发送比特线txd,给出起始位,然后跳转到s_wait状态。需要注意的是,s_start状态仅持续一个bclk周期,完成相关信号值的改变后,无条件进入s_wait状态。
s_wait为发送模块的等待状态,保持所有信号值不变。当发送模块处于这一状态时,等待计满16个bclk后,判断8个有效数据比特是否发送完毕,如果发送完毕跳转到s_stop,结束有效数据的发送;否则,跳转到s_shift状态,发送下一个有效比特。
s_shift为数据移位状态,发送模块在这一状态将下一个要发送的数据移动到发送端口上,然后直接跳转到s_wait状态。
s_stop状态完成停止位的发送,当有效数据发送完成后,发送模块进入该状态,发送一个停止位,发送完成后自动进入s_idle状态,并且将tx_ready信号拉高。在实际设计中,如果读者需要实现1.5位或者2位停止码,直接修改计数器的数值即可。
代码语言:js复制module uart_tx(
bclk,reset,tx_din,tx_cmd,tx_ready,txd
);
input bclk;
input reset;
input [7:0]tx_din;
input tx_cmd;
output tx_ready;
output txd;
reg tx_ready;
parameter Lframe=8;
parameter [2:0]s_idle=3'b000;
parameter [2:0]s_start=3'b001;
parameter [2:0]s_wait=3'b010;
parameter [2:0]s_shift=3'b011;
parameter [2:0]s_stop=3'b100;
reg [2:0]state=s_idle;
reg [3:0]cnt=0;
reg [3:0]dcnt=0;
reg txdt;
assign txd=txdt;
always @(posedge bclk or posedge reset)
begin
if(reset)
begin
state<=s_idle;
cnt<=0;
tx_ready<=0;
txdt<=1'b1;
end
else
begin
case(state)
s_idle:
begin
tx_ready<=1;
cnt<=0;
txdt<=1'b1;
if(tx_cmd==1'b1)
state<=s_start;
else
state<=s_idle;
end
s_start:
begin
tx_ready<=1'b0;
txdt<=1'b0;//the start bit
state<=s_wait;
end
s_wait:
begin
tx_ready<=1'b0;
if(cnt>=4'b1110)
begin
cnt<=0;
if(dcnt==Lframe)
begin
state<=s_stop;
txdt<=1'b1;
dcnt<=0;
end
else
begin
state<=s_shift;
txdt<=txdt;
end
end
else
begin
state<=s_shift;
cnt<=cnt 1;
end
end
s_shift:
begin
tx_ready<=1'b0;
txdt<=tx_din[dcnt];
dcnt<=dcnt 1;
state<=s_wait;
end
s_stop:
begin
txdt<=1'b1;
if(cnt>4'b1110)
begin
tx_ready<=1'b1;
cnt<=0;
state<=s_idle;
end
else
begin
state<=s_stop;
cnt<=cnt 1;
end
end
endcase
end
end
endmodule