当前位置:   article > 正文

数字逻辑第四次实验——检测1101序列_1101 序列检测器设计与仿真

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的稳定性

代码如下:

  1. module shake(clk,rstn,setd,desetd);
  2. input clk;
  3. input rstn;
  4. input setd;
  5. output desetd;
  6. //parameter T100Hz = 499999;
  7. parameter T100Hz = 4;
  8. reg [31:0]cnt_100Hz;
  9. reg clk_100Hz;
  10. always@(posedge clk,negedge rstn)//100Hz分频模块
  11. begin
  12. if(!rstn)begin
  13. cnt_100Hz <= 32'b0;
  14. clk_100Hz <= 0;
  15. end
  16. else
  17. begin
  18. cnt_100Hz <= cnt_100Hz + 1'b1;
  19. if(cnt_100Hz==T100Hz)
  20. begin
  21. cnt_100Hz <= 32'b0;
  22. clk_100Hz <= ~clk_100Hz;
  23. end
  24. end
  25. end
  26. reg setdr,setdrr,setdrrr;
  27. always@(posedge clk_100Hz,negedge rstn)//按键消抖模块
  28. begin
  29. if(!rstn)
  30. begin
  31. setdr <= 1'b0;
  32. setdrr <= 1'b0;
  33. setdrrr <= 1'b0;
  34. end
  35. else
  36. begin//每次时钟沿赋值一个
  37. setdrrr <= setdrr;
  38. setdrr <= setdr;
  39. setdr <= setd;
  40. end
  41. end
  42. assign desetd = setdr & setdrr & setdrrr;//当三个时钟沿setd都保持稳定的话,就输出信号
  43. 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来依次输出,就错了。

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

  1. module exportlist(list,clk,rstn,setd,spot);
  2. input [7:0]list;
  3. input clk;
  4. input setd;
  5. input rstn;
  6. output reg spot;
  7. reg [7:0]relist;
  8. always@(posedge setd,negedge rstn)//以消抖后的setd为时钟信号
  9. begin
  10. if(!rstn) relist <= 8'b0;//重置relist序列
  11. else
  12. begin
  13. relist <= list;//setd上升沿到来,把list锁存给relist
  14. end
  15. end
  16. reg [3:0]i=0;
  17. always@(posedge clk,negedge rstn)
  18. begin
  19. if(!rstn)
  20. begin
  21. spot <= 1'b0;//重置
  22. i <= 0;
  23. end
  24. else
  25. if(setd == 1)begin
  26. begin
  27. spot <= relist[7-i];//spot是relist的最高位
  28. if(i==7) i <= i;
  29. else i <= i+1;
  30. end
  31. end
  32. else
  33. spot <= 1'b0;
  34. end
  35. endmodule

3.检测模块

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

贴一个状态图

代码如下:

  1. module detector(en,clk,rstn,result);
  2. input clk;
  3. input rstn;
  4. input en;
  5. output reg result=0;
  6. reg [2:0]y;
  7. reg [2:0]Y;
  8. always@(en,y)//0~4依次对应s0~4
  9. begin
  10. case(y)
  11. 0:if(en) Y = 1;
  12. else Y = 0;
  13. 1:if(en) Y = 2;
  14. else Y = 0;
  15. 2:if(en) Y = 2;
  16. else Y = 3;
  17. 3:if(en) Y = 4;
  18. else Y = 0;
  19. 4:if(en) Y = 2;
  20. else Y = 0;
  21. default: Y = 0;
  22. endcase
  23. end
  24. always@(posedge clk,negedge rstn)
  25. begin
  26. if(!rstn) y <= 0;
  27. else y <= Y;
  28. end
  29. always@(*)
  30. begin
  31. if(!rstn) result <= 0;
  32. else
  33. begin
  34. if(y==4) result <= 1;
  35. end
  36. end
  37. endmodule

 4.顶层模块:

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

  1. module top1(list,rstn,clk,setd,result);
  2. input [7:0]list;
  3. input rstn;
  4. input clk;
  5. input setd;
  6. output wire result;
  7. wire desetd;
  8. wire spot;
  9. shake shake_1(
  10. .clk(clk),
  11. .rstn(rstn),
  12. .setd(setd),
  13. .desetd(desetd)
  14. );
  15. exportlist exportlist_1(
  16. .list(list),
  17. .clk(clk),
  18. .rstn(rstn),
  19. .setd(desetd),
  20. .spot(spot)
  21. );
  22. detector detector_1(
  23. .en(spot),
  24. .clk(clk),
  25. .rstn(rstn),
  26. .result(result)
  27. );
  28. endmodule

 附上电路图:

 四.仿真及实验效果

仿真文件如下:

  1. module detector1101_tb();
  2. reg [7:0] list;
  3. wire result; // 修改为wire类型
  4. reg clk = 0;
  5. reg rstn = 0;
  6. reg setd = 0;
  7. top1 top(.list(list),.clk(clk), .rstn(rstn), .setd(setd), .result(result));
  8. initial begin
  9. rstn = 0;
  10. #9;
  11. list = 8'b10110100;
  12. #10 rstn = 1;
  13. #10 setd = 1;
  14. // 仿真运行一段时间
  15. #100 rstn = 0;
  16. setd = 0;
  17. #10 list = 8'b10101101;
  18. #10 rstn = 1;
  19. #10 setd = 1;
  20. #100
  21. // 在仿真结束后输出结果
  22. $finish;
  23. end
  24. // 时钟翻转
  25. always #1 clk = ~clk;
  26. endmodule

 时序图:

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/676632
推荐阅读
相关标签
  

闽ICP备14008679号