但凡涉及到双方通信的系统,接收机的复杂度往往都是高于发送机的,对于串口通信系统也如此。在接收系统中,起始状态和数据都需要依靠接收端检测得到,为了避免毛刺影响,能够得到正确的起始信号和有效数据,需要完成一个简单的最大似然判决,其方法如下:由于bclk信号的频率为9600Hz的16倍,则对于每个数据都会有16个样值,最终的采样比特值为出现次数超过8次的电平逻辑值。
整个接收模块的状态机包含3个状态:s_idle、s_sample以及s_stop,其状态转移图如图13-8所示。
s_idle状态为空闲状态,用于检测接收数据链路上的起始信号。系统复位后,接收模块就处于这一状态,一直检测rxd数据是否从1跳变为0,一个起始位代表着新的一帧数据。一旦检测到起始位,立刻进入s_sample状态,采集有效数据。在此状态下,rx_ready信号的值为1。
s_sample为数据采样状态,在此状态下,接收模块连续采样数据,并对每16个采样样值进行最大似然判决,判决得到相应的逻辑值,这一过程要重复8次,并依次完成串并转换,直到接收完8个数据比特后,直接进入s_stop状态。在这一状态下,rx_ready信号的值为0。
s_stop状态用于检测停止位,为了使得接收模块的使用范围更广,本程序在这一状态等待一定的时间后,直接跳转到s_idle状态,无论停止位是1、1.5还是2位,也不对其数值进行采样判断。这是因为没有添加校验位,根据串口的传输协议,8个有效数据后肯定是停止位,但停止位所占的时间却是要补偿的,对于不同位宽的停止位,需要修改计数器的模值。
代码语言:js复制module uart_rx(
bclk,reset,rxd,rx_ready,rx_dout
);
input bclk;
input reset;
input rxd;
output rx_ready;
output [7:0]rx_dout;
parameter [3:0]Lframe=9;
parameter [2:0]s_idle=3'b000;
parameter [2:0]s_sample=3'b010;
parameter [2:0]s_stop=3'b100;
reg rx_ready;
reg [7:0]rx_doutmp=0;
reg [2:0]state=s_idle;
reg [3:0]cnt=0;
reg [3:0]dcnt=0;
reg [3:0]num=0;
assign rx_dout=rx_doutmp;
always @(posedge bclk or posedge reset)
begin
if(reset==1'b1)
begin
state<=s_idle;
cnt<=0;
dcnt<=0;
num<=0;
rx_doutmp<=0;
rx_ready<=0;
end
else
begin
case(state)
s_idle:
begin
rx_dout<=0;
rx_ready<=1;
dcnt<=0;
if(cnt==4'b1111)
begin
cnt<=0;
if(num>7)
begin
state<=s_sample;
num<=0;
end
else
begin
state<=s_idle;
num<=0;
end
end
else
begin
cnt<=cnt 1;
if(rxd==1'b0)
begin
num<=num 1;
end
else
begin
num<=num;
end
end
end
s_sample:
begin
rx_ready<=1'b0;
if(dcnt==Lframe)
begin
state<=s_stop;
end
else
begin
if(cnt==4'b1111)
begin
dcnt<=dcnt 1;
cnt<=0;
if(num>7)
begin
num<=0;
rx_doutmp[dcnt]<=1;
end
else
begin
num<=0;
rx_doutmp[dcnt]<=0;
end
end
else
begin
cnt<=cnt 1;
if(rxd==1'b1)
begin
num<=num 1;
end
else
begin
num<=num;
end
end
end
end
s_stop:
begin
rx_ready<=1'b1;
if(cnt==4'b1111)
begin
cnt<=0;
state<=s_idle;
end
else
begin
cnt<=cnt 1;
end
end
endcase
end
end
endmodule