其中F和G是两个有关状态的函数,状态寄存器一般是采用正跳边沿触发的D触发器,n个触发器最多记住2^n个状态。
上图是Mealy状态机,其输出不仅取决于当前状态还受输入的影响,Moore状态机的输出仅取决于当前状态。
二进制编码:所需寄存器数量少,但是用的组合逻辑多;
独热码:占用寄存器数量多,速度快,每次仅需判断一位,组合逻辑少;
格雷码:按顺序每次只变化一位的话,就用格雷码;
4个数,
二级制:00 01 10 11;
独热码:0001 0010 0100 1000;
寄存器数量多了,可能会有多余状态,记得添加default语句;
一般的三段式状态机:
检测输入为1101 ,每次输入一位din
module seq_det(
input clk,
input rst,
input din,
output reg out
);
parameter idle = 5'd0,
s1 = 5'd1,
s2 = 5'd2,
s3 = 5'd3,
s4 = 5'd4;
reg[2:0] cur_state;
reg[2:0] next_state;
always@(posedge clk,posedge rst)
begin
if(rst)
cur_state<=5'd0;
else
cur_state<=next_state;
end
always@(*)
begin
case(cur_state)
idle:
if(din==1'b1)
next_state=s1;
else
next_state=idle;
s1:
if(din==1'b1)
next_state=s2;
else
next_state=idle;
s2:
if(din==1'b0)
next_state=s3;
else
next_state=s2;
s3:
if(din==1'b1)
next_state=s4;
else
next_state=idle;
s4:
if(din==1'b1)
next_state=s1;
else
next_state=idle;
default:next_state=idle;
endcase
always@(*)begin
if(cur_state==s4)
sout=1'b1;
else
sout=1'b0;
end
endmodule
ADC:模数转换,将模拟信号变成数字信号,便于数字设备处理。
其中ale 是模拟端的输入选通信号,start为启动信号,eoc是转换进行中信号,转换结束oe输出使能端有效;
module adc_trans(
input clk,rst,
input start,eoc,
input[7:0] data,
output ale,oe,
output [2:0]addr
);
parameter idle =2'b00,
s1 =2'b01,
s2 =2'b10,
s3 =2'b11;
reg [1:0] cur_state,next_state;
always@(posedge clk,posedge rst)begin
if(rst)
cur_state<=idle;
else
cur_state<=next_state;
end
always@(*)begin
case(cur_state)
idle:
ale=0;start=0;oe=0;
next_state=s1;
s1:
ale=1;start=1;oe=0;
next_state=s2;
s2:
ale=0;start=0;oe=0;
if(eoc==1)
next_state=s3;
else
next_state=s2;
s3:
ale=0;start=0;oe=1;
next_state=idle;
endcase
end
endmodule
按键消抖的原因和原理不多赘述,直接写主要就是状态机的转换,理解了这一点就可以了。
由于这里的输入信号key_in 是异步信号,不依赖于clk;不处理会出现时序违例,常见方法是直接打两拍;
边沿检测:
检测上升下降沿的原理就是利用了寄存器当前状态的输入即为下一时钟的输出;
若现在为0,下一时刻为1,就是上升沿;
若现在为1,下一时刻为0,就是下降沿;
always@(posedge clk,posedge rst)begin
if(rst)
key_in_edge_tem1<=1'b0;
key_in_edge_tem2<=1'b0;
else
key_in_edge_tem1<=key_instable;
key_in_edge_tem2<=key_in_edge_tem1;
end
assign nedge=!(key_in_edge_tem1)&&(key_in_edge_tem2); //1到0 下降沿
assign pedge=(key_in_edge_tem1)&&!(key_in_edge_tem2); //0到1 上升沿
整体的代码,其中key_flag key_state 可以不管,只是为了反馈状态添加的;方便判断状态
module debounce(
input clk,
input rst,
input key_in,
output reg key_flag, //flag 代表 f的状态; 在f1/f2 flag为1,其他状态为0
output reg key_state //state 代表在f1 :0 or f2:1
);
//其中Key_flag为是否稳定按下的标志,key_state为按下/释放的标志
reg key_in_1;
reg key_in_2;
reg key_in_stable;
reg key_in_edge_tem1;
reg key_in_edge_tem2;
wire pedge;
wire nedge;
reg[18:0] cnt; //2^19*50MHz ==10.48576ms
reg cnt_en;
reg cnt_full;
parameter idle =2'd0,
f1 =2'd1,
down =2'd2,
s2 =2'd3;
reg [1:0] state;
reg [1:0] n_state;
///===========================input reg==================================
always@(posedge clk,posedge rst)begin
if(rst)
key_in_1<=1'b0;
key_in_2<=1'b0;
else
key_in_1<=key_in;
key_in_2<=key_in_1;
end
assign key_in_stable=key_in_2;
///============================detect egde============================
always@(posedge clk,posedge rst)begin
if(rst)
key_in_edge_tem1<=1'b0;
key_in_edge_tem2<=1'b0;
else
key_in_edge_tem1<=key_instable;
key_in_edge_tem2<=key_in_edge_tem1;
end
assign nedge=!(key_in_edge_tem1)&&(key_in_edge_tem2); //1到0 下降沿
assign pedge=(key_in_edge_tem1)&&!(key_in_edge_tem2); //0到1 上升沿
///=============================cnt==================================
always@(posedge clk,posedge rst)begin
if(rst)
cnt<=19'b0;
else(cnt_en)
cnt<=cnt+1'b1;
else
cnt<= 19'b0;
end
always@(posedge clk,posedge rst)begin
if(rst)
cnt_full<=1'b0;
else if(cnt==19'h7FFFF)
cnt_full<=1'b1;
else
cnt_full<=1'b0;
end
///=============================fsm================================
always@(posedge clk,posedge rst)begin
if(rst)
state<=idle;
else
state<=n_state;
end
always@(*)begin
case(state)
idle:
begin
if(nedge)
n_state=f1;
cnt_en=1'b1;
else
n_state=idle;
end
f1:
begin
if(pedge)
n_state=idle;
cnt_en=1'b0;
else if(cnt_full)
key_flag=1'b1;
key_state=1'b0;
n_state=down;
cnt_en=1'b0;
else
n_state=f1;
end
down:
begin
key_flag=1'b0; //只保持一个时钟周期的高脉冲
if(pedge)
n_state=f2;
cnt_en=1'b1;
else
n_state=down;
end
f2:
if(nedge)
cnt_en=1'b0;
n_state=down;
else if(cnt_full)
n_state=idle;
cnt_en=1'b0;
key_flag=1'b1;
key_state=1'b1;
else
n_state=f2;
default :
key_flag=1'b0;
key_state=1'b1;
cnt_en=1'b0;
state=idle;
endcase
endmodule