数,也减少了产生毛刺和一些状态的可能。
采用一位独热编码,虽然多用了触发器,当可以有效节省和简化组合电路。对于寄存器数量多而逻辑相对缺乏的FPGA器件来说,采用一位独热编码可以有效提高电路的速度和可靠性,也有利于提高器件资源的利用率。
将产生状态的组合逻辑电路和用于保存状态的寄存器分别写在不同的always块中。其中主要包括:输出控制部分、警报计时部分、锁打开后的计时部分、比较密码部分、记录密码部分和记录错误次数的部分
3.4密码的输入
本次密码锁的密码输入采用FPGA芯片上的8位单个按键,考虑到按键数目不够,采用了一位按键作为功能转换按键;即前5位按键输入0~4,同时按下功能转换按键时,按键0~4即转换为按键5~9,这就弥补了按键数目的不足。最后两位按键设定为确认输入按键和复位按键。密码输入完成后可以按确认键检验密码的正误,报警、输入错误或者其他情况可以按复位按键重新输入。
另外由于按键的时候同时会引起状态机的转换,所以如果按键的时候对按键判断次数过多会产生状态的过快转换,记录的密码和数码管的显示就同时会出现错误,因此在按键部分加入了消除多重按键的程序,只检测一次按键的下降沿,解决了这个问题。
3.5 密码记录与比较
程序设定了一个寄存器用来记录输入的密码。当次有效状态机(即密码输入的状态机)发生转换并且有密码输入时,程序会记录下输入的密码在寄存器的其中4位里面,最后次有效状态转换到确认密码的状态时,会将记录下的密码与固化在锁内的密码进行对比,正确即将主状态机转换到通过阶段,错误则将状态机转换到报警阶段。其中正确错误的状态转换是通过控制相应的标志位实现的。
3.6密码的显示
密码显示采用数码管动态扫描显示,初始时显示密码为4位0,当输入密码后数码管的第一位、第二位、第三位、第四位会依次显示输入的密码,错误后复
位可以重新输入。密码显示采用的是记录密码的寄存器的数据,显示扫描的扫描时间设置为1ms左右,这样显示不会出现闪烁或者残影。
四、程序仿真
下前面的输入cmd的编码:
//输入的数字编码 0~9,enter,cancel
one=4'b0001, two=4’b0010,three=4'b0011,four=4'b0100,five=4'b0101, six=4'b0110,seven=4'b0111,eight=4'b1000,nine=4'b1001, zero=4'b1000,enter=4'b1010,cancel=4'b1011;
可以看到,在复位以后,输入第1,2,3,4个密码(依次为1111)后,passed变成高电平
当过了一定的时间后,passed变成低电平,重新计入键盘读入值,进行下一轮的密码辨别。
五、程序清单
module passwd_lock(
clk0, passed, one1, two1, three1, four1, zero1,
change, yes, resetb,
seg, dig
);
input one1,two1,three1,four1,zero1,change; reg zero,one,two,three,four;
input yes; input
input
resetb; clk0;
//输入复位信号 //输入时钟信号 //输出信号
output [7:0] passed; output [7:0] seg;//////段选
output [7:0] dig;//////位选
reg key_pressed_flag; // 键盘按下标志
reg [3:0] key;
reg RXBuf0,RXBuf1,RXBuf2,RXBuf3,RXBuf4; //display reg clk0_div;
reg [2:0] digyi;////////////yiwei//// reg [7:0] dig;/////////////weixuan reg [3:0] seg0;/////////////duanxuan reg [7:0] seg;
reg [12:0] CNT_R0;
reg [18:0] CNT_R1; reg clk1;
reg [21:0] CNT_R2; reg clk2; reg [7:0] passed; reg
[7:0]
alarmed;
/*输入与输出的声明部分,其中,clk0为输入的时钟信号,resetb为密码舒服的输入信号,key为输入命令,
需注意的时,key并不是总在表示密码,也表示密码的间隔,如当输入4位密码后需要一个确认“enter”信号,
当密码输入错误时,需要取消“cancel”信号,这些信号之间在设计中通过有限状态转换机实现。*/
parameter reg [15:0]
PASSWORD=16'b0001000100010001;//盛放密码的参数
password;//输入数值盛放寄存器
//输入的数字编码
always @( posedge clk1 ) begin RXBuf1 <= one1;
//检测线路的下降沿
one <= ~(RXBuf1 & ( ~one1 )); // RXFall1<=RXFall; end
//消除多重按键
always @( posedge clk1 ) begin RXBuf0 <= zero1;
//检测线路的下降沿
zero <= ~(RXBuf0 & ( ~zero1 )); // RXFall1<=RXFall; end
//检测线路的下降沿
//消除多重按键
always @( posedge clk1 ) begin
RXBuf2 <= two1;
two <= ~(RXBuf2 & ( ~two1 ));
// RXFall1<=RXFall; end
//消除多重按
always @( posedge clk1 ) begin //检测线路的下降沿
RXBuf3 <= three1;
three <= ~(RXBuf3 & ( ~three1 ));
// RXFall1<=RXFall; end
//消除多重按键
always @( posedge clk1 )
begin //检测线路的下降沿 RXBuf4 <= four1; four <= ~(RXBuf4 & ( ~four1 )); // RXFall1<=RXFall;
end
//消除多重按键 reg reg
[2:0] main_state;//主状态 [2:0] next_state;//下一个状态
waits=3'b001,
pass=3'b010,
//主有限状态转换机的三个状态:waits、pass、alarm parameter
reg reg
alarm=3'b100; [2:0] sub_state; [2:0] next_sub_state;
//主有限状态转换机的三个状态:first、second、third、fourth、finish。 parameter first=3'b000, second=3'b001,
third=3'b010, fourth=3'b011,
finish=3'b100; //通过计时寄存器 reg [7:0] pass_count; //警报计时寄存器
reg [10:0] alarm_count; //尝试次数寄存器
reg [1:0] try_count;
//输入状态寄存器:error和correct reg reg
error; correct;
//以上为中间状态的一些寄存器和一些所用到的参数 //主机状态机部分 always @(posedge clk0) begin
CNT_R2 <= CNT_R2 + 1'b1;
if(CNT_R2 < 4000000) begin
clk1 <= 1; end else begin