数字逻辑第四次实验——检测1101序列

                      数字逻辑第四次实验——检测1101序列

一.实验内容:

实验十五 摩尔状态机序列检测器(*****)

  1. 设计“1101”序列检测的状态转换图;
  2. 设计一个 8 位并转串输出模块 par2ser。该器件有 8 位输入 d[7:0],1 位输出 q,另有一个 clk 端,一个 set 端。set端上升沿将 8位输入锁存到逻辑右移移位寄存器中。
  3. 调用并转串输出模块,使用Verilog HDL语言的行为描述方式实现一个摩尔状态机,能检测一个8位的二进制数据中是否存在“1101”序列,如果检测到该序列则指定的LED灯亮;

       本文将呈现该项目的设计思路,遇到的问题以及对于设计开发的一些帮助(再次感谢学年第一曾神教会我debug)

二.设计思路:

       首先思考该项目的输入输出端口和模块数目,输入为八位待测序列,启动信号;输出为一位的结果信号,满足1101序列则为,否则为0。为了项目的完整和严谨,我们再添加一个置位信号作为异步时序控制所有进程的复位。因为setd作为内部的启动信号,需要保证他的稳定性,需要对其进行按键消抖,这是模块一。二是对输入序列的锁存和并转串依次读取;三是以每位作为输入调整状态,起到检验序列的效果;四是一个顶层模块来串接三个模块。

三.设计流程

1.按键消抖模块:

        首先对时钟信号进行了100Hz的分频,再在该时钟信号的时钟域下,采用了三个D触发器来对setd进行打三拍操作,即用三个中间变量来承接setd,每一个时钟沿赋值一个中间变量。当三个时钟沿内setd都保持不动时,可以输出desetd表示setd是手动启动而不是按键抖动,以此保证setd的稳定性

代码如下:

module shake(clk,rstn,setd,desetd);
  input clk;
  input rstn;
  input setd;
  output desetd;
  //parameter T100Hz = 499999;
  parameter T100Hz = 4;
  reg [31:0]cnt_100Hz;
  reg clk_100Hz;
always@(posedge clk,negedge rstn)//100Hz分频模块
begin
  if(!rstn)begin
   cnt_100Hz <= 32'b0;
  clk_100Hz <= 0;
  end
  else
  begin
    cnt_100Hz <= cnt_100Hz + 1'b1;
    if(cnt_100Hz==T100Hz)
    begin
      cnt_100Hz <= 32'b0;
      clk_100Hz <= ~clk_100Hz;
    end
  end
end
reg setdr,setdrr,setdrrr;
always@(posedge clk_100Hz,negedge rstn)//按键消抖模块
begin
  if(!rstn)
  begin
    setdr <= 1'b0;
    setdrr <= 1'b0;
    setdrrr <= 1'b0;
  end
  else
  begin//每次时钟沿赋值一个
    setdrrr <= setdrr;
    setdrr <= setdr;
    setdr <= setd;
  end
end
assign desetd = setdr & setdrr & setdrrr;//当三个时钟沿setd都保持稳定的话,就输出信号
endmodule

2.并转串模块

       当setd的上升沿到来时,将输入的序列转存到寄存器中,防止在检测期间,序列的改变造成结果的出错,并依次在后八个clk时钟沿,输出序列的各个位数。

       这里需要注意的是,需要在setd到来后再进行i的计数,不然会出现setd到来之前i就已经达到了最大值,无法达到并转串的效果。

      还有一个细节,为什么我可以在i等于7处保持不变。难道这样不会出现在八个时钟沿之后第九个时钟沿到来,再次输出第0位对最后的结果产生影响吗?答案是不会的,因为1101目标序列的最后两位是互异的,永远不会出现上述情况。下面举个例子说明:输入为10100110序列,当setd的上升沿到来后,在接下来的八个时钟内,依次输出1,0,1,0,0,1,1,0;显然输出并不会截止,这时我的i维持在7,会一直输出序列的第0位0(就是1010011000000000,0不断拼接下去,输出并不会截止)。1101检测中要求最后两位互异,所以不会出现问题,

       但如果检测1011序列这种最后的两位是相同的序列,就不可以用了,比如要检测10001101中的1011时,依次输出1,0,0,0,1,1,0,1是不含有1011序列的,但是第九个时钟到来,输出第0位1,这下输出就有了100011011符合条件影响结果。就需要对模块进行限制了,比如持续输出第0位的取反。

        而且我们不能对一个序列在不同的always中进行操作,不然在vivido进行实现综合网表的时候会出现问题。我一开始第二个always中采用移位改变relist,不是用i来依次输出,就错了。

       然而这个实验并不需要,代码如下:

module exportlist(list,clk,rstn,setd,spot);
input [7:0]list;
input clk;
input setd;
input rstn;
output reg spot;
reg [7:0]relist;
always@(posedge setd,negedge rstn)//以消抖后的setd为时钟信号
begin
  if(!rstn) relist <= 8'b0;//重置relist序列
  else 
  begin
    relist <= list;//setd上升沿到来,把list锁存给relist
  end
end
reg [3:0]i=0;
always@(posedge clk,negedge rstn)
begin
  if(!rstn) 
  begin
    spot <= 1'b0;//重置
    i <= 0;
  end
  else
  if(setd == 1)begin
  begin
    spot <= relist[7-i];//spot是relist的最高位
    if(i==7) i <= i;
    else i <= i+1;
  end
end
else
spot <= 1'b0;
end
endmodule

3.检测模块

          这个没什么好说的,就是有限状态机状态的不断切换,使能信号是上一个模块的输出。最后要保持result的不变,不然会出现灯只亮一下或者灯不亮的情况。

贴一个状态图

代码如下:

module detector(en,clk,rstn,result);
input clk;
input rstn;
input en;
output reg result=0;
reg [2:0]y;
reg [2:0]Y;
always@(en,y)//0~4依次对应s0~4
begin
  case(y)
  0:if(en) Y = 1;
    else Y = 0;
  1:if(en) Y = 2;
    else Y = 0;
  2:if(en) Y = 2;
    else Y = 3;
  3:if(en) Y = 4;
    else Y = 0;
  4:if(en) Y = 2;
    else Y = 0;
  default: Y = 0;
  endcase
end
always@(posedge clk,negedge rstn)
begin
  if(!rstn) y <= 0;
  else y <= Y;
end
always@(*)
begin
  if(!rstn) result <= 0;
  else 
  begin
    if(y==4) result <= 1;
  end
end
endmodule

 4.顶层模块:

       就是依次串接各个模块,真的气死我了,串接变量只能是wire类型,找半天查了资料才知道,代码如下:

module top1(list,rstn,clk,setd,result);
input [7:0]list;
input rstn;
input clk;
input setd;
output wire result;
wire desetd;
wire spot;
shake shake_1(
  .clk(clk),
  .rstn(rstn),
  .setd(setd),
  .desetd(desetd)
);
exportlist exportlist_1(
  .list(list),
  .clk(clk),
  .rstn(rstn),
  .setd(desetd),
  .spot(spot)
);
detector detector_1(
  .en(spot),
  .clk(clk),
  .rstn(rstn),
  .result(result)
);
endmodule

 附上电路图:

 四.仿真及实验效果

仿真文件如下:

module detector1101_tb();
  reg [7:0] list;
  wire result; // 修改为wire类型
  reg clk = 0;
  reg rstn = 0;
  reg setd = 0;
  top1 top(.list(list),.clk(clk), .rstn(rstn), .setd(setd), .result(result));

  initial begin
  rstn = 0;
  #9;
    list = 8'b10110100;
    #10 rstn = 1;
    #10 setd = 1;

    // 仿真运行一段时间
    #100 rstn = 0;
        setd = 0;
    #10 list = 8'b10101101;
    #10 rstn = 1;
    #10 setd = 1;
    #100
    // 在仿真结束后输出结果
    $finish;
  end

  // 时钟翻转
  always #1 clk = ~clk;
endmodule

 时序图:

可以看到两组测试数据都是符合条件的,在desetd到来后的八个时钟沿后依次读入序列的每个位置,也能正确的做出结果响应。 

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值