赞
踩
实验十五 摩尔状态机序列检测器(*****)
本文将呈现该项目的设计思路,遇到的问题以及对于设计开发的一些帮助(再次感谢学年第一曾神教会我debug)
首先思考该项目的输入输出端口和模块数目,输入为八位待测序列,启动信号;输出为一位的结果信号,满足1101序列则为,否则为0。为了项目的完整和严谨,我们再添加一个置位信号作为异步时序控制所有进程的复位。因为setd作为内部的启动信号,需要保证他的稳定性,需要对其进行按键消抖,这是模块一。二是对输入序列的锁存和并转串依次读取;三是以每位作为输入调整状态,起到检验序列的效果;四是一个顶层模块来串接三个模块。
首先对时钟信号进行了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
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
当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
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
这个没什么好说的,就是有限状态机状态的不断切换,使能信号是上一个模块的输出。最后要保持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
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
就是依次串接各个模块,真的气死我了,串接变量只能是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
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
附上电路图:
仿真文件如下:
- 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
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
时序图:
可以看到两组测试数据都是符合条件的,在desetd到来后的八个时钟沿后依次读入序列的每个位置,也能正确的做出结果响应。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。