Mealy型序列检测机+按键防抖模块
内容简述
输入8位序列,检测是否有“1011”序列。按btnA开始工作。按一次btnB检测一位,用currled显示该位是0/1,若检测到“1011”则将markled标为1.
按键防抖模块
我试过网上能找到的许许多多按键防抖模块,自己也写过好多,以下是我见过最清楚并且好用的一个。该按键保证每次按下不论按多久都只产生一次脉冲,凡是需要用到按键的时候都可以调用,可移植性强。下面是来源网址一个不错的FPGA学习网站
module debounce(input clk,pb_1,output pb_out);
wire slow_clk_en;
wire Q1,Q2,Q2_bar,Q0;
clock_enable u1(clk,slow_clk_en);
my_dff_en d0(clk,slow_clk_en,pb_1,Q0);
my_dff_en d1(clk,slow_clk_en,Q0,Q1);
my_dff_en d2(clk,slow_clk_en,Q1,Q2);
assign Q2_bar = ~Q2;
assign pb_out = Q1 & Q2_bar;
endmodule
//--------------------------------------------------------------------
// Slow clock enable for debouncing button
module clock_enable(input Clk_100M,output slow_clk_en);
reg [26:0]counter=0;
always @(posedge Clk_100M)
begin
counter <= (counter>=249999)?0:counter+1;
end
assign slow_clk_en = (counter == 249999)?1'b1:1'b0;
endmodule
//--------------------------------------------------------------------
// D-flip-flop with clock enable signal for debouncing module
module my_dff_en(input DFF_CLOCK, clock_enable,D, output reg Q=0);
always @ (posedge DFF_CLOCK) begin
if(clock_enable==1)
Q <= D;
end
endmodule
主模块
verilog语言中不能用变量名(如cnt)进行下表索引,由于不太习惯用硬件语言,刚开始程序虽能通过,但是上板的结果不正确。找了很久才找到原因。后来改用了seq<={seq[6:0],seq[7]}这种方式,用固定的下标则能正确显示结果。
module mealy(
clk,
btnA,
btnB,
switchs,
currled,
markled,
work,
);
input clk;
input btnA,btnB;
input [7:0] switchs;
reg [1:0] y;//当前状态
reg [2:0] cnt;//计数输到了第几位
reg [7:0] seq;//存储当前序列
output reg currled;//用于输出当前位置的信息。
output reg markled;//是否检测到“1011”序列
output reg work;//是否处于工作状态
integer i;
//----------------------------------------------------
initial
begin
markled<=1'b0;
work<=1'b0;
seq<=switchs;
end
//----------------------------------------------------
//button debounce
wire signalA;
wire signalB;
debounce myBtnA(clk, btnA, signalA);
debounce myBtnB(clk, btnB, signalB);
//-----------------------------------------------------
//Sequence detection
always@(posedge signalB or posedge signalA)
begin
if(signalA)//由于是上升沿,1为有效值,判断是否开始
begin
work<=~work;
seq<=switchs;
markled=1'b0;
cnt<=3'b000;
y<=2'b00;
end
else if(signalB&&work)//由于是上升沿,1为有效值,判断是否读入下一位
//对signalB的判断必须写在else中,不然有可能在A为上升沿进入aways语句时却进行了B的操作。
begin
seq<={seq[6:0],seq[7]};
currled<=seq[7];
if(!seq[7])
case(y)
2'b00:begin y<=2'b00;markled<=1'b0; end
2'b01:begin y<=2'b10;markled<=1'b0; end
2'b10:begin y<=2'b00;markled<=1'b0; end
2'b11:begin y<=2'b10;markled<=1'b0; end
endcase
else
case(y)
2'b00:begin y<=2'b01;markled<=1'b0; end
2'b01:begin y<=2'b01;markled<=1'b0; end
2'b10:begin y<=2'b11;markled<=1'b0; end
2'b11:begin y<=2'b01;markled<=1'b1; end
endcase
if(cnt==3'b111)work<=1'b0;//cnt用于计数,是否已输到末尾,并判断停止工作状态。
else cnt<=cnt+1;
end
end
endmodule