Verilog 代码编写 状态机-序列检测

题目:

      有一种特殊的串行通信系统,数据以包的形式传输,数据的包头为 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。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值