百度网站官方认证怎么做,温州网络推广平台建设,广州天河区做网站,太原建站推广文章目录 一、本次实验简介二、源码及分析三、总结 一、本次实验简介
本次是实验是为了利用状态机模拟电子锁#xff0c;相关要求如下#xff1a;
顺序输入4位密码#xff0c;密码为1234#xff0c;用按键来键入密码用led灯指示键入第几位密码#xff0c;#xff08;博… 文章目录 一、本次实验简介二、源码及分析三、总结 一、本次实验简介
本次是实验是为了利用状态机模拟电子锁相关要求如下
顺序输入4位密码密码为1234用按键来键入密码用led灯指示键入第几位密码博主IDLE状态亮1个LED输入第一位密码后亮2个以此类推若密码输入正确让4个led闪烁每间隔0.3s用3个按键按下key1对应位的数值加1按下key2对应位的数值减1按下按键key3表示确认键入该数值
二、源码及分析
fsm_lock模块
源码分析
博主为状态机设计了五个状态并采用独热码编码的方式一般均建议状态机状态编码方式采用独热码 IDLE 空闲状态 P1密码1输入正确状态 P2 密码2输入正确状态 P3密码3输入正确状态 P4密码4输入正确后LED闪烁状态有题目可以看出我们有四位的密码博主的想法是设置四个密码寄存器KEY1按下后计数值加1KEY2按下时计数值减一以此来存储键入密码值当然每个密码寄存器的加1条件有些许不同详细请看代码。而除了最后一个状态其他状态博主设置的跳转下一状态的条件均为状态机处于当前状态并且按下了KEY3确认键并且此时键入的值为密码值。对于最后一个状态由于需要在P4闪烁LED灯因此跳转状态设置为了LED闪烁结束。至于如何控制LED闪烁结束博主设置了一个八位的次数寄存器LED每完成一次闪烁该计数器左移一位初始值为8’d1当闪烁完成时该计数器的最高位为1此时便可以将最高位作为跳转的控制条件。
/****
状态机模拟电子锁- 顺序输入4位密码密码为1234用按键来键入密码
- 用led灯指示键入第几位密码博主IDLE状态亮1个LED输入第一位密码后亮2个以此类推若密码输入正确让4个led闪烁每间隔0.3s
- 用3个按键按下key1对应位的数值加1
- 按下key2对应位的数值减1
- 按下按键key3表示确认键入该数值****/
module fsm_lock (input wire clk ,input wire rst_n ,input wire [2:0] key_in , //按键输入信号output reg [3:0] led //输出led
);//参数定义
parameter MAX 15_000_000 ;//300ms计数器
parameter IDLE 5b00001 ,//空闲状态P1 5b00010 ,//密码1输入正确状态 P2 5b00100 ,//密码2输入正确状态P3 5b01000 ,//密码3输入正确状态P4 5b10000 ;//密码4输入正确LED闪烁状态//状态转移条件定义
wire idle2p1 ;
wire p12p2 ;
wire p22p3 ;
wire p32p4 ;
wire p42idle ;//内部信号定义
reg [23:0] cnt ;//300ms计数寄存器
reg [7:0] cnt_8 ;//解锁成功后让LED闪烁4次reg [4:0] cstate ;//现态
reg [4:0] nstate ;//次态reg [3:0] cnt_key1 ;//密码计数器 计数当前按下的密码值
reg [3:0] cnt_key2 ;
reg [3:0] cnt_key3 ;
reg [3:0] cnt_key4 ;reg led_light;//三段式状态机
//第一段时序逻辑描述状态转移
always(posedge clk or negedge rst_n)beginif(!rst_n)begincstate IDLE;endelse begincstate nstate;end
end//第二段组合逻辑描述状态转移规律及状态转移条件
always(*)begincase(cstate)IDLE : beginif(idle2p1)beginnstate P1;endelse beginnstate cstate;endendP1 : beginif(p12p2)beginnstate P2;endelse beginnstate cstate;endendP2 : beginif(p22p3)beginnstate P3;endelse beginnstate cstate;endendP3 : beginif(p32p4)beginnstate P4;endelse beginnstate cstate;endendP4 : beginif(p42idle)beginnstate IDLE;endelse beginnstate cstate;endenddefault : nstate IDLE;endcase
endassign idle2p1 (cstate IDLE) (key_in[2]) (cnt_key1 4d1);
assign p12p2 (cstate P1 ) (key_in[2]) (cnt_key2 4d2);
assign p22p3 (cstate P2 ) (key_in[2]) (cnt_key3 4d3);
assign p32p4 (cstate P3 ) (key_in[2]) (cnt_key4 4d4);
assign p42idle (cstate P4 ) (cnt_8[7]);//led闪烁完成后跳转//第三段时序逻辑描述不同状态下的输出
always(posedge clk or negedge rst_n)beginif(!rst_n)beginled 4b0000;endelse begincase(cstate)IDLE : led 4b0001 ;P1 : led 4b0011 ;P2 : led 4b0111 ;P3 : led 4b1111 ;P4 : led led_light ;default : led 4b0000 ;endcaseend
end//密码计数器1
always(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_key1 1b0;endelse if(key_in[0] cstate IDLE)begincnt_key1 cnt_key1 1b1;endelse if(key_in[1] (cnt_key1 ! 1b0))begincnt_key1 cnt_key1 - 1b1;endelse if(cnt_8[7])begincnt_key1 1b0;endelse begincnt_key1 cnt_key1;end
end//密码计数器2
always(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_key2 1b0;endelse if(key_in[0] cstate P1)begincnt_key2 cnt_key2 1b1;endelse if(key_in[1] (cnt_key2 ! 1b0))begincnt_key2 cnt_key2 - 1b1;endelse if(cnt_8[7])begincnt_key2 1b0;endelse begincnt_key2 cnt_key2;end
end//密码计数器3
always(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_key3 1b0;endelse if(key_in[0] cstate P2)begincnt_key3 cnt_key3 1b1;endelse if(key_in[1] (cnt_key3 ! 1b0))begincnt_key3 cnt_key3 - 1b1;endelse if(cnt_8[7])begincnt_key3 1b0;endelse begincnt_key3 cnt_key3;end
end//密码计数器4
always(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_key4 1b0;endelse if(key_in[0] cstate P3)begincnt_key4 cnt_key4 1b1;endelse if(key_in[1] (cnt_key4 ! 1b0))begincnt_key4 cnt_key4 - 1b1;endelse if(cnt_8[7])begincnt_key4 1b0;endelse begincnt_key4 cnt_key4;end
end//300ms计数器
always (posedge clk or negedge rst_n)beginif(!rst_n)begincnt 1b0;endelse if(cnt MAX - 1b1)begincnt 1b0;endelse if(cstate P4)begincnt cnt 1b1;endelse begincnt 1b0;end
end//闪烁次数寄存器
always (posedge clk or negedge rst_n) beginif(!rst_n)begincnt_8 8b00000001;end else if(cnt MAX -1d1)begincnt_8 {cnt_8[6:0],cnt_8[7]};endelse if(cstate IDLE)begincnt_8 8b00000001;endelse begincnt_8 cnt_8;end
end//led闪烁
always(posedge clk or negedge rst_n)beginif(!rst_n)beginled_light 4b1111;endelse if(cstate P4 cnt MAX - 1b1)beginled_light ~led_light;endelse beginled_light led_light;end
endendmodulefsm_key模块按键消抖模块 如果有读者不了解按键消抖原理与代码细节的可以查看博主此篇博文博主在此就不再赘述了 module fsm_key#(parameter WIDTH 3) (input wire clk ,input wire rst_n ,input wire [WIDTH - 1:0] key_in ,//按键信号输入output reg [WIDTH - 1:0] key_out //消抖后稳定的脉冲信号输出
);//参数定义
parameter IDLE 4b0001;//空闲状态
parameter FILTER_DOWN 4b0010;//按键按下抖动状态
parameter HOLD_DOWN 4b0100;//按键稳定状态
parameter FILTER_UP 4b1000;//按键释放抖动状态parameter MAX 20d1_000_000 ;//延时20ms采样//内部信号定义
reg [19:0] cnt_20ms ;//20ms计数寄存器
reg [WIDTH - 1:0] key_r0 ;//同步
reg [WIDTH - 1:0] key_r1 ;//打一拍
reg [WIDTH - 1:0] key_r2 ;//打两拍reg [3:0] cstate ;//现态寄存器
reg [3:0] nstate ;//次态寄存器//状态转移条件定义
wire idle2down ;
wire down2hold ;
wire hold2up ;
wire up2idle ; //计数器信号定义
wire add_cnt_20ms;//开始计时的标志
wire end_cnt_20ms;//结束计时的标志wire [WIDTH - 1:0] nedge ;//下降沿寄存器
wire [WIDTH - 1:0] pedge ;//上升沿寄存器//同步打拍
always (posedge clk or negedge rst_n) beginif(!rst_n)beginkey_r0 {WIDTH{1b1}};key_r1 {WIDTH{1b1}};key_r2 {WIDTH{1b1}};endelse beginkey_r0 key_in;key_r1 key_r0;key_r2 key_r1;end
end//20ms计数器
always(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_20ms 1b0;endelse if(add_cnt_20ms)beginif(end_cnt_20ms)begincnt_20ms 1b0;endelse begincnt_20ms cnt_20ms 1b1;endendelse begincnt_20ms 1b0;end
endassign add_cnt_20ms cstate FILTER_DOWN || cstate FILTER_UP;
assign end_cnt_20ms add_cnt_20ms cnt_20ms MAX - 1b1;//下降沿 上升沿检测
assign nedge ~key_r1 key_r2;
assign pedge key_r1 ~key_r2;//三段式状态机//第一段时序逻辑描述状态转移
always(posedge clk or negedge rst_n)beginif(!rst_n)begincstate IDLE;endelse begincstate nstate;end
end//第二段组合逻辑状态转移规律及状态转移条件
always (*)begincase (cstate)IDLE : beginif(idle2down)beginnstate FILTER_DOWN;endelse beginnstate cstate;endendFILTER_DOWN : beginif(down2hold)beginnstate HOLD_DOWN;endelse beginnstate cstate;endendHOLD_DOWN : beginif(hold2up)beginnstate FILTER_UP;endelse beginnstate cstate;endendFILTER_UP : beginif(up2idle)beginnstate IDLE;endelse beginnstate cstate;endenddefault : nstate IDLE;endcase
endassign idle2down cstate IDLE nedge ;
assign down2hold cstate FILTER_DOWN end_cnt_20ms ;
assign hold2up cstate HOLD_DOWN pedge ;
assign up2idle cstate FILTER_UP end_cnt_20ms ;//第三段 时序逻辑或组合逻辑 描述输出
always(posedge clk or negedge rst_n)beginif(!rst_n)beginkey_out {WIDTH{1b0}};endelse if(down2hold)beginkey_out ~key_in;endelse beginkey_out {WIDTH{1b0}};end
endendmodule顶层模块
module top_lock(input wire clk ,input wire rst_n ,input wire [2:0] key_in ,output wire [3:0] led
);wire [2:0] key_out;fsm_lock u_fsm_lock(.clk (clk ) ,.rst_n (rst_n ) ,.key_in(key_out) ,.led (led)
);fsm_key u_fsm_key(.clk (clk ) ,.rst_n (rst_n ) ,.key_in (key_in ) ,.key_out(key_out)
);endmodule三、总结
本次实验较为简单博主没有编写仿真文件跑仿真其实是因为懒毕竟我觉得TB文件写起来真的很麻烦功能实现也较为简单感兴趣的读者可以自主添加其他功能如输入错误蜂鸣器鸣叫并自动跳转回到IDLE状态或者利用数码管显示正在输入的密码位数与密码值等。