题目:
有一种特殊的串行通信系统,数据以包的形式传输,数据的包头为
01111110
, 然后为数据内容,然后 01111110
结尾,现在需要编写程序,完成数据包头插入和接收,试画出两种情况下FSM 转态转移图。
分析:
按照题意,数据接收开始对包头数据进行检测,当检测到
01111110
序列时, 将开启传输信号,正式接收数据内容,然后边传输边继续检测序列,当再次出现
01111110
序列时,停止传输,接收停止。 采用有限状态机的方法来进行编写,需要先明确各状态和状态间的转移图。 依照序列检测要求,设定状态有 9 个,按照独热码方式进行编码。以每次接收 1bit 后的数据作为状态,外加一个不定态,共 9 个状态,以下一个输送的 1bit 数据作为状态转移的判断条件。 可以绘出状态转移图,如下所示:
(其中 S0-S7,Idle 表示状态,方框里面的序列表示具体的状态情况)
1.以下为采用三段式状态机进行编写的 Verilog 代码:
module FSMserialdata(clk,rst,datain,dataout);
input clk;
input rst;
input datain; //输入串行数据
output wire dataout; //接收信号
reg flag; //检测序列脉冲信号
assign dataout=flag? (datain):0;
//检测脉冲打开后开始传输数据,否则不传输
//采用独热码形式进行状态编码
parameter idle=9'b000_000_001,
s0=9'b000_000_010,
s1=9'b000_000_100,
s2=9'b000_001_000,
s3=9'b000_010_000,
s4=9'b000_100_000,
s5=9'b001_000_000,
s6=9'b010_000_000,
s7=9'b100_000_000;
reg [8:0] state,nstate;//现态与次态
//三段式状态机编写:
always@(posedge clk or negedge rst)
begin
if(!rst) begin
state<=idle;
end
else begin
state<=nstate;
end
end
always@(state or datain)
begin
case(state)
idle:begin
if(datain)
nstate<=idle;
else
nstate<=s0;
end
s0:begin
if(datain)
nstate<=s1;
else
nstate<=s0;
end
s1:begin
if(datain)
nstate<=s2;
else
nstate<=s0;
end
s2:begin
if(datain)
nstate<=s3;
else
nstate<=s0;
end
s3:begin
if(datain)
nstate<=s4;
else
nstate<=s0;
end
s4:begin
if(datain)
nstate<=s5;
else
nstate<=s0;
end
s5:begin
if(datain)
nstate<=s6;
else
nstate<=s0;
end
s6:begin
if(datain)
nstate<=idle;
else
nstate<=s7;
end
s7:begin
nstate<=idle;
end
default: nstate<=idle;
endcase
end
always@(posedge clk or negedge rst)
begin
if(!rst)
flag<=0;
else begin
case(nstate)
idle,s0,s1,s2,s3,s4,s5,s6: flag<=flag;
s7: flag<=~flag;
default: flag<=0;
endcase
end
end
endmodule
2. 然后对所编写的代码进行时序仿真,testbench 如下:
本次仿真模拟了 48 个数据的传输,并带有数据包头需要检测的序列和数据包尾,其中可以观察到在接收并检测到包头后开始接收数据的情况,以及检测到包尾后停止传输的情况。采用 48 位的 data 数据寄存器,将待传输数据放入 data 序列中,并不断进行循环左移,从最高位开始传输。
`timescale 1ns / 1ps
module FSMserialdata_tb( );
reg clk,rst;
wire datain;
wire dataout;
reg [47:0] data=0;
always #10 clk=~clk;
//将待传输数据放入 data 序列中,并不断进行循环左移,从最高位开始传输
always@(posedge clk) data={data[46:0],data[47]};
assign datain=data[47];
initial
begin
rst<=0;
clk<=0;
#25 rst<=1;
#25
data=48'b1001_0011_0111_1110_1001_1000_0110_1110_0111_1110_0010_110
0;
#(48*20) $stop;
end
FSMserialdata datats(
.clk(clk),
.rst(rst),
.datain(datain),
.dataout(dataout)
);
endmodule
下图为仿真时序图:

在图中黄线位置已经检测到了序列
01111110
的出现,故检测脉冲置 1,开始进行数据的传输,dataout=datain
; (序列 01111110
为图中红框区域)

当传输数据开始后,如再次接收到序列 01111110(图中红框区域),则检测脉冲置 0,数据传输停止。此时接收到的末尾八位数据则为停止位数据序列 01111110。