在许多(较旧的)串行通信协议中,每个数据字节与一个起始位和一个停止位一起发送,以帮助接收器从比特流中划分字节。一种常见的方案是使用一个起始位(0)、8个数据位和1个停止位(1)。当无任何传输(空闲)时,线路也处于逻辑1。
设计一个有限状态机,当给定一个比特流时,它将识别何时正确接收字节。它需要识别起始位,等待所有8个数据位,然后验证停止位是否正确。如果停止位未按预期出现,则FSM必须等到找到停止位后再尝试接收下一个字节。
现在,您有了一个有限状态机,可以识别在串行位流中何时正确接收字节,添加一个数据路径,该路径将输出正确接收的数据字节。当done为1时,out_字节必须有效,否则为don-care。
请注意,串行协议首先发送最低有效位。
cnt都是从0开始的,上升沿加1
cnt计数器,计算接收的数据数量0-7 ,cnt=8时候判断in是否为停止位,来判断是否进入stop状态
n_state比c_state早一拍
如果使用c_state,那么会丢失第一个数字
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
);
// Use FSM from Fsm_serial
parameter idle =3'd0;
parameter start =3'd1;
parameter data =3'd2;
parameter stop =3'd3;
parameter hunluan =3'd4;
reg [2:0] c_state,n_state;
always@(posedge clk)begin
if(reset)
c_state<=idle;
else
c_state<=n_state;
end
always@(*)begin
case(c_state)
idle :n_state=(in==0)?start:idle;
start :n_state=data;
//没有接收到停止位,这个字节被抛弃
//直到等到停止位,才开始下一个字节
data :n_state=(cnt==8)?((in==1)?stop:hunluan):data;
hunluan:n_state=(in)?idle:hunluan;
stop :n_state=(in==0)?start:idle;
endcase
end
reg [3:0]cnt;
always@(posedge clk)begin
if(reset)
cnt<=0;
else if(n_state==data)
cnt<=cnt+1'b1;
else
cnt<=0; //其他状态下cnt为0
end
assign done=(c_state==stop);
// New: Datapath to latch input bits.
reg [7:0]out;
always@(posedge clk)begin
if(reset)
out<=0;
else if(n_state==data)
out[cnt]<=in;
//out<={in,out[7:1]};
else
out<=out;
end
assign out_byte=out;
endmodule
我们想给串行接收器增加奇偶校验。奇偶校验在每个数据字节后添加一个额外的位。我们将使用奇数奇偶校验,其中接收到的9位中的1数必须是奇数。例如,101001011满足奇数奇偶校验(有5个1),但001001011不满足。
更改FSM和数据路径以执行奇数奇偶校验。仅当正确接收字节且奇偶校验通过时,才断言done信号。与串行接收器FSM一样,该FSM需要识别起始位,等待所有9位(数据和奇偶校验),然后验证停止位是否正确。如果停止位未按预期出现,则FSM必须等到找到停止位后再尝试接收下一个字节。
您可以使用以下模块来计算输入流的奇偶校验(这是一个带重置的TFF)。其预期用途是,应为其提供输入位流,并在适当的时间重置,以便其计算每个字节中的1位数。
两种做法
方法一:仍然使用n_state
方法二:状态start和data结合在一起,那么就可以使用c_state
奇偶校验的关键:奇偶模块的复位信号,在方法一n_state!=data时候有效,
方法二c_state!=start时候有效
注意:奇偶校验的前提是有停止位,在组合逻辑中判断
有停止位并且奇偶校验为1,那么进入stop状态
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
wire odd;
// Modify FSM and datapath from Fsm_serialdata
// Use FSM from Fsm_serial
parameter idle =3'd0;
parameter start =3'd1;
parameter data =3'd2;
parameter stop =3'd3;
parameter hunluan =3'd4;
reg [2:0] c_state,n_state;
always@(posedge clk)begin
if(reset)
c_state<=idle;
else
c_state<=n_state;
end
always@(*)begin
case(c_state)
idle :n_state=(in==0)?start:idle;
start :n_state=data;
//没有接收到停止位,这个字节被抛弃
//直到等到停止位,才开始下一个字节
//没有接收到停止位,就不用谈及奇偶校验,停止位优先级高
data :if(cnt==9)
if(in)
if(odd)
n_state<=stop;
else
n_state<=idle;
else
n_state<=hunluan;
else
n_state<=data;
hunluan:n_state=(in)?idle:hunluan;
stop :n_state=(in==0)?start:idle;
endcase
end
reg [3:0]cnt;
always@(posedge clk)begin
if(reset)
cnt<=0;
else if(n_state==data)
cnt<=cnt+1'b1;
else
cnt<=0; //其他状态下cnt为0
end
assign done=(c_state==stop);
// New: Datapath to latch input bits.
reg [7:0]out;
always@(posedge clk)begin
if(reset)
out<=0;
else if((n_state==data)&&(cnt<=7))
out[cnt]<=in;
//out<={in,out[7:1]};
else
out<=out;
end
assign out_byte=out;
// New: Add parity checking.
parity u_parity (
.clk(clk),
.reset(n_state!=data),
.in(in),
.odd(odd));
endmodule
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
wire odd;
// Modify FSM and datapath from Fsm_serialdata
parameter idle =2'd0;
parameter start =2'd1;
//parameter data =3'd2;
parameter stop =2'd2;
parameter hunluan =2'd3;
reg [1:0] c_state,n_state;
always@(posedge clk)begin
if(reset)
c_state<=idle;
else
c_state<=n_state;
end
always@(*)begin
case(c_state)
idle :n_state=(in==0)?start:idle;
//没有接收到停止位,这个字节被抛弃
//直到等到停止位,才开始下一个字节
start :if(cnt==9)
if(in)
if(odd)
n_state=stop;
else
n_state=idle;
else
n_state=hunluan;
else
n_state=start;
hunluan:n_state=(in)?idle:hunluan;
stop :n_state=(in==0)?start:idle;
endcase
end
reg [3:0]cnt;
always@(posedge clk)begin
if(reset)
cnt<=0;
else if(c_state==start)
cnt<=cnt+1'b1;
else
cnt<=0;
end
// New: Datapath to latch input bits.
reg [7:0]out;
always@(posedge clk)begin
if(reset)
out<=0;
else if(c_state==start&&cnt<=4'd7)
out[cnt]<=in;
//out<={in,out[7:1]};
else
out<=out;
end
assign out_byte=out;
assign done=(c_state==stop);
// New: Add parity checking.
parity u_parity (
.clk(clk),
.reset(!(c_state==start)),
.in(in),
.odd(odd));
endmodule