此程序目前只能仿真实现,稍作修改便可以做成实物。
EDA课程设计报告 课程设计名称:电子密码锁 院系:机械与电子信息工程系 专业:电子信息工程 班级:1430402 学号:20143*0228 姓名:吴*琴 指导老师:蔡*民
2017年6月 利用基于所学EDA相关知识以Quartus II 软件设计一个具有较高安全性和较低成本的通用电子密码锁,其具体功能要求如下: - 密码输入:每按下一个数字键,就输入一个数值,并在显示器上的最左方显示‘*’号,输入第二个数值后,最左方显示两个‘*’号,直到输入完8位数值密码后,显示器上显示出8个‘*’号。输入完成8位数值密码后,输入的数值无效。
- 密码清除:按下此键可以撤销前一次输入的密码。
- 密码更改:在开锁状态下按下此键时会将目前的数字设定成新的密码,其它状态密码更改无效。
- 解除电锁:按下此键会检查输入的密码是否正确,密码正确即开锁。
- 警报:密码在连续三次输入错误之后,电子密码锁会发出警报。
- 新建工程dianzimimasuo
- 新建Verilog HDL File
选择菜单File,选择New选项,根据所使用的硬件描述语言类型选择相应的新建文件型(Verilog HDL File)。 三.任务分析和设计方案 作为通用电子密码锁,主要由三个部分组成:数字密码输入电路,密码锁控制电路和密码显示电路。 各个模块电路的选取: (1)4x4矩阵键盘的工作原理:矩阵键盘又称为行列式键盘,它是由4条行线,4条列线组成的键盘,其原理如图1.1所示,在行线和列线的每个交叉点上,设置一个按键,按键的个数是4x4个,按键排列如图1.2所示。当按下某个按键后,为了辨别和读取键值信息,一般采用如下的方法:向X端口扫描输入一组只含一个0的4位数据,如1110,1101,1011,0111,如有按键按下,则Y口一定会输出对应的数据,因此,只要结合X,Y口的数据,就能判断按键的位置。
图1.1 4x4矩阵键盘电路
(图片详见51hei附件)
图1.2按键排列 (2)4x4矩阵键盘检测程序:如下是用Verilog编写的4x4矩阵键盘键值扫描判断程序,键盘扫描程序由1个always模块构成,在always模块中先进行模4计数,在计数器的每个状态从FPGA内部送出一列扫描数据给键盘,然后读入经过去抖处理的4行数据,根据行,列数据,确定按下的是哪个键。 //按键模块 module scankey(clk,a,b,keyvalue); input clk; //键盘扫描时钟信号 input [3:0]b; output reg[3:0]a; //输出扫描信号给键盘 output reg [3:0]keyvalue; reg [1:0]q; reg [3:0] qdb;//消抖后的b reg [3:0]rxbuf; always @( posedge clk) begin //按键消抖 rxbuf[0] <= b[0]; qdb[0] <= ~(rxbuf[0] & (~b[0])); end always @( posedge clk) begin //按键消抖 rxbuf[1] <= b[1]; qdb[1] <= ~(rxbuf[1] & (~b[1])); end always @( posedge clk) begin //按键消抖 rxbuf[2] <= b[2]; qdb[2] <= ~(rxbuf[2] & (~b[2])); end always @( posedge clk) begin //按键消抖 rxbuf[3] <= b[3]; qdb[3] <= ~(rxbuf[3] & (~b[3])); end always@(posedge clk) begin q<=q+1; case(q) //给a口送出扫描数据 0:a<=4'b1110; 1:a<=4'b1101; 2:a<=4'b1011; 3:a<=4'b0111; endcase case({a,qdb}) //判断键值 8'b1110_0111:keyvalue<=4'b0000; //key0 8'b1110_1011:keyvalue<=4'b0001; //key1 8'b1110_1101:keyvalue<=4'b0010; 8'b1110_1110:keyvalue<=4'b0011; 8'b1101_0111:keyvalue<=4'b0100; 8'b1101_1011:keyvalue<=4'b0101; 8'b1101_1101:keyvalue<=4'b0110; 8'b1101_1110:keyvalue<=4'b0111; 8'b1011_0111:keyvalue<=4'b1000; 8'b1011_1011:keyvalue<=4'b1001; //key9 8'b1011_1101:keyvalue<=4'b1010; //keyA 8'b1011_1110:keyvalue<=4'b1011; 8'b0111_0111:keyvalue<=4'b1100; 8'b0111_1011:keyvalue<=4'b1101; 8'b0111_1101:keyvalue<=4'b1110; //keyE 8'b0111_1110:keyvalue<=4'b1111; //keyF default:keyvalue=8'b1111_1111; endcase end Endmodule - 密码显示电路采用8个七段数码管显示密码输入状态,绿色发光二极管指示锁的开闭状态,黄色发光二极管指示密码修改成功与否,红色发光二极管指示警报状态。
- 密码锁控制电路采用EP4CE10F17C8芯片控制。
根据以上选定的输入设备和显示器件,并考虑到实现各项数字密码锁功能的具体要求,整个电子密码锁系统的总体组成框图如图1.3所示。 (1)密码锁输入电路包括时序产生电路,键盘扫描电路,键盘弹跳消除电路,键盘译码电路等几个小的功能电路。 (2)密码锁控制电路包括按键数据的缓冲存储电路,密码的清除,变更,存储,密码核对(数值比较电路),解锁电路(开/关门锁电路)等几个小的功能电路。 (3)七段数码管显示电路主要将待显示数据的BCD码转换成数码器的七段显示驱动编码。 (详见51hei附件)
密码控制电路 显示电路 七段数码管 图1.3数字电子密码锁系统总体框图 总体设计方案: 采用主,从两个状态机来完成8位电子密码锁设计。 主状态机用来完成waits(等待)状态,pass(开锁)状态,changing(改密)状态,alarm(警报)状态之间的切换。主状态机状态图如图2.1所示 (详见51hei附件) 图2.1主状态机 主状态机简要说明:复位键(Resetb)为0,进入等待(waits)状态;主现状态为等待状态且correct为1,主状态进入开锁(pass)状态;在开锁状态延时10s后,主状态回到等待状态;主现态为开锁状态且mimagaile为1,主状态进入改密(changing)状态;在改密状态延时10s后,主状态回到等待状态;主现态为等待状态且密码连续输入错误3次,主状态进入警报(alarm)状态;在警报状态延时1分钟后,主状态回到等待状态。 从状态机用于输入8位密码,程序如下: always@(posedge clk or negedge resetb) begin if(!resetb) sub_state<=first;//从状态为first else sub_state<=next_sub_state;//从状态为下一个从状态 end always@(cmd or cmd_t or sub_state) begin if(cmd_t==0)//检测有按键按下 case(cmd) cancel:begin //密码输入错误时,重复上一个状态 if(sub_state==first) next_sub_state=first; else case(sub_state) second:next_sub_state=first; third: next_sub_state=second; fourth:next_sub_state=third; fifth:next_sub_state=fourth; sixth:next_sub_state=fifth; seventh:next_sub_state=sixth; eighth:next_sub_state=seventh; finish:next_sub_state=eighth; endcase end //4个密码输完时,进行确认 enter:next_sub_state=first; setmima:next_sub_state=first; sure:next_sub_state=first; //default为输入了某位密码,输入完自动将状态转入下一位 default: case(sub_state) first:begin next_sub_state=second;dig=8'b00000001;end second:begin next_sub_state=third;dig=8'b00000011;end third:begin next_sub_state=fourth;dig=8'b00000111;end fourth:begin next_sub_state=fifth;dig=8'b00001111;end fifth:begin next_sub_state=sixth;dig=8'b00011111;end sixth:begin next_sub_state=seventh;dig=8'b00111111;end seventh:begin next_sub_state=eighth;dig=8'b01111111;end eighth:begin next_sub_state=finish;dig=8'b11111111;end //当输入完8位密码后状态保持不变,等待输入enter命令 finish:begin next_sub_state=finish;dig=8'b11111111;end endcase endcase else next_sub_state=sub_state; end 从状态机简要说明:按下清除键后从状态机状态回到前一个状态,按下数字键后从状态机为下一个状态(即输入下一位密码) 四.实验结果 功能验证: - cmd为输入命令用来代替按键验证功能,cmd=0000表示按键0,cmd=0001表示按键1,cmd=0010表示按键2,cmd=0011表示按键3,cmd=0100表示按键4,cmd=0101表示按键5,cmd=0110表示按键6,cmd=0111表示按键7,cmd=1000表示按键8,cmd=1001表示按键9,cmd=1010表示确认键,cmd=1011表示清除键,cmd=1101表示改密键。
- dig用来控制8个共阳数码管的公共端(即可以控制8个数码管‘——’的亮灭来显示密码输入到第几位)。
- passed输出高电平表示开锁状态。
- resetmimaok输出高电平表示修改密码成功。
- alarmed输出高电平表示警报状态。
图3.1总体功能仿真结果(包含开锁,改密,清除,警报,显示密码输入到第几位) 下面将总图按功能分解分析:
图3.2初始密码开锁功能 初始密码为11111111,如图3.2中40ns开始输入密码为11011111按下确认键(1010)后密码错误passed保持低电平(电子锁未打开),接着输入正确密码(11111111)按下确认键(1010)后密码正确passed输出高电平(电子锁打开)。
图3.3修改密码功能 如图3.3在passed为高(即开锁状态)输入8位数字后按下改密键(1101)密码被修改为11101111成功,resetmimaok输出高电平。接着输入初始密码11111111按下确认键(1010)passed保持低电平(电子锁未打开)之后再随便输入一个错误密码,如图3.3输入01111110按下确认键(1010)passed保持低电平(电子锁未打开),最后输入修改后的密码11101111按下确认键(1010)passed输出高电平(电子锁打开)。
图3.4输入大于8个数字时,前8位有效 如图3.4中800ns处输入密码111011111按下确认键(1010)后passed输出高电平(电子锁打开)说明第九位数字1无效。
图3.5三次连续输错密码后警报 如图3.5在950ns处开始连续输入错误三次密码后,alarmed输出高电平表示发出警报。
图3.6清除功能 如图3.6在1.31us处输入密码1110113后按下清除键(1011)接着输入11后,按下确认键(1010)passed输出高电平(电子锁打开)。 五.存在的问题及改进分析 - 存在的问题:硬件电路该怎么做?如何把此设计做成实物?
- 改进分析:数码管显示模块可以改为输入数字后显示输入的数字一秒钟后变为‘*’;可以增加一个管理员密码,管理员密码优先级高于普通密码,警报的解除只能靠输入管理员密码,输入管理员密码可以开锁和更改普通密码。
六.实验心得及意见 通过这次设计,使我对EDA产生了浓厚的兴趣。特别是当实现每个小功能成功时,心里特别开心。这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。在设计的过程中遇到的问题,反映出来我的许多不足之处,我以后要努力克服缺点。虽然此设计在Quartus II 软件上功能能够大体上得到验证,但是离做出实物还差很远。一直没有玩过实物开发板,根本就不知道进行硬件的连接,就连一个简单的程序都下载进开发板进行验证。总的来说,这次设计的密码锁还是比较成功的,在设计中遇到了很多问题,最后在同学和老师的辛勤的指导下外加上自己的努力,终于都得到了解决,因此很有成就感,终于觉得平时所学的知识有了实用的价值,达到了理论与实际相结合的目的。 最后说一说我对本课程一些意见,该课程从开始做实验到最后的课程设计都一直是在电脑上进行仿真,没有在板子上跑过程序,我觉得老师应该在开发板给我们演示简单的程序,这样能够带动我们大多数人的兴趣,也能够便于我们更快上手做一些简单的实物,提高大家学习的积极性。
七.附录 程序: - module dianzisuo(clk,resetb,cmd,cmd_t,alarmed,passed,resetmimaok,dig);
- input cmd_t;//输入命令控制信号
- input clk; //输入时钟信号
- input resetb; //输入复位信号
- input [3:0] cmd;//输入命令信号
- output reg [7:0]dig;//位选输出信号
- output alarmed; //输出警报信号
- output passed; //输出通过信号
- output resetmimaok; //输出密码修改成功信号
- reg alarmed;
- reg passed;
- reg resetmimaok;
- wire clk;
- wire resetb;
- wire [3:0]cmd;
- wire cmd_t;
- reg[22:0]CNT_R0;//clk1延时寄存器
- reg clk1;//clk为10ns时clk1为5ms周期脉冲
- reg [31:0]inputpassword;//输入值存放寄存器
- reg [31:0]PASSWORD=32'b0001_0001_0001_0001_0001_0001_0001_0001;//初始密码
- parameter zero=4'b0000,//0
- one=4'b0001,//1
- two=4'b0010,//2
- three=4'b0011,//3
- four=4'b0100,//4
- five=4'b0101,//5
- six=4'b0110,//6
- seven=4'b0111,//7
- eight=4'b1000,//8
- nine=4'b1001,//9
- enter=4'b1010,//确认键
- cancel=4'b1011,//清除一位键
- setmima=4'b1100,//
- sure=4'b1101;//修改密码键
- reg [3:0]main_state;//主现态
- reg [3:0]next_state;//主次态
- parameter waits=4'b0001,
- pass=4'b0010,
- alarm=4'b0100,
- changing=4'b1000;
- reg [3:0]sub_state;//从现态
- reg [3:0]next_sub_state;//从次态
- parameter first=4'b0000,
- second=4'b0001,
- third=4'b0010,
- fourth=4'b0100,
- fifth=4'b1000,
- sixth=4'b0011,
- seventh=4'b0101,
- eighth=4'b0110,
- finish=4'b0111;
- reg[7:0] pass_count;//通过计时寄存器
- reg[10:0] alarm_count;//警报计时寄存器
- reg[1:0] try_count;//尝试次数寄存器
- reg[7:0] mima_count;//改密计时寄存器
- reg error;
- reg correct;
- reg mimagaile;
- //clk为10ns时,clk1为5ms时钟
- always @(posedge clk)
- begin
- CNT_R0 <= CNT_R0 + 1'b1;
- if(CNT_R0 < 5000000)
- begin
- clk1 <= 1;
- end else
- begin
- clk1 <= 0;
- end
- end
- //主状态机部分
- always@(main_state or correct or error or try_count or pass_count or alarm_count or mimagaile)
- begin
- case(main_state)
- waits: if(correct==1)//由waits转换到pass的条件
- begin
- next_state=pass;
- end
- else if(error==1&&try_count==2)
- next_state=alarm;//由waits转换的alarm的条件
- else
- next_state=waits;
- pass: if(pass_count[7]==1)//由pass转换到waits的条件
- next_state=waits;
- else if(mimagaile==1)//由pass转换到changing的条件
- next_state=changing;
- else
- next_state=pass;
- changing:if(mima_count[7]==1)//由changing转换到waits的条件
- next_state=waits;
- else
- next_state=changing;
- alarm:if(alarm_count[10]==1)//由alarm转换到waits的条件
- next_state=waits;
- else
- next_state=alarm;
- default:next_state=waits;
- endcase
- end
- //alarm一段时间后,自动进入waits状态
- //alarm定时器
- always@(posedge clk1 or negedge resetb)
- begin
- if(!resetb)
- alarm_count<=0;
- else if(main_state==alarm)//alarm状态计时器alarm定时器加1
- alarm_count<=alarm_count+1;
- else
- alarm_count<=0;
- end
- //锁pass以后计数开始,当规定的时间到达后自动上锁,并进入waits状态
- //pass定时器
- always@(posedge clk1 or negedge resetb)
- begin
- if(!resetb)
- pass_count<=0;
- else if(main_state==pass) //pass状态计时器pass定时器加1
- pass_count<=pass_count+1;
- else
- pass_count<=0;
- end
- //changing以后计数开始,当规定的时间到达后自动上锁,并进入waits状态
- //changing定时器
- always@(posedge clk1 or negedge resetb)
- begin
- if(!resetb)
- mima_count<=0;
- else if(main_state==changing) //changing状态计时器mima_count定时器加1
- mima_count<=mima_count+1;
- else
- mima_count<=0;
- end
- //状态转换
- always@(posedge clk or negedge resetb)
- begin
- if(!resetb)//如果按下复位键,则主状态为等待状态
- main_state<=waits;
- else //如果没按则进入下一个状态
- main_state<=next_state;
- end
- //输出控制部分
- always@(posedge clk or negedge resetb)
- begin
- if(!resetb)//复位按下时,开锁输出和报警输出都为零
- begin
- passed<=0;
- alarmed<=0;
- resetmimaok<=0;
- end
- else if(main_state==pass)//当主机状态为pass时开锁
- begin
- passed<=1;
- alarmed<=0;
- resetmimaok<=0;
- end
- else if(main_state==changing)//当主机状态为changing时,改密码
- begin
- passed<=0;
- alarmed<=0;
- resetmimaok<=1;
- end
- else if(main_state==alarm)//当主机状态为alarm时,警报
- begin
- passed<=0;
- alarmed<=1;
- resetmimaok<=0;
- end
- end
- //从状态机,用于输入8位密码
- always@(posedge clk or negedge resetb)
- begin
- if(!resetb)
- sub_state<=first;//从状态为first
- else
- sub_state<=next_sub_state;//从状态为下一个从状态
- end
- always@(cmd or cmd_t or sub_state)
- begin
- if(cmd_t==0)//检测有按键按下
- case(cmd)
- cancel:begin //密码输入错误时,重复上一个状态
- if(sub_state==first)
- next_sub_state=first;
- else
- case(sub_state)
- second:next_sub_state=first;
- third: next_sub_state=second;
- fourth:next_sub_state=third;
- fifth:next_sub_state=fourth;
- sixth:next_sub_state=fifth;
- seventh:next_sub_state=sixth;
- eighth:next_sub_state=seventh;
- finish:next_sub_state=eighth;
- endcase
- end
- //4个密码输完时,进行确认
- enter:next_sub_state=first;
- setmima:next_sub_state=first;
- sure:next_sub_state=first;
- //default为输入了某位密码,输入完自动将状态转入下一位
- default:
- case(sub_state)
- first:begin next_sub_state=second;dig=8'b00000001;end
- second:begin next_sub_state=third;dig=8'b00000011;end
- third:begin next_sub_state=fourth;dig=8'b00000111;end
- fourth:begin next_sub_state=fifth;dig=8'b00001111;end
- fifth:begin next_sub_state=sixth;dig=8'b00011111;end
- sixth:begin next_sub_state=seventh;dig=8'b00111111;end
- seventh:begin next_sub_state=eighth;dig=8'b01111111;end
- eighth:begin next_sub_state=finish;dig=8'b11111111;end //当输入完8位密码后状态保持不变,等待输入enter命令
- finish:begin next_sub_state=finish;dig=8'b11111111;end
- endcase
- endcase
- else
- next_sub_state=sub_state;
- end
- //记录密码
- always@(posedge clk or negedge resetb)
- begin
- if(!resetb)
- inputpassword<=0;
- else if(cmd_t==0)
- case(sub_state)
- first:inputpassword[31:28]<=cmd[3:0];
- second:inputpassword[27:24]<=cmd[3:0];
- third:inputpassword[23:20]<=cmd[3:0];
- fourth:inputpassword[19:16]<=cmd[3:0];
- fifth:inputpassword[15:12]<=cmd[3:0];
- sixth:inputpassword[11:8]<=cmd[3:0];
- seventh:inputpassword[7:4]<=cmd[3:0];
- eighth:inputpassword[3:0]<=cmd[3:0];
- default:inputpassword<=inputpassword;
- endcase
- else
- inputpassword<=inputpassword;
- end
- //比较密码
- always@(posedge clk or negedge resetb)
- begin
- if(!resetb)//如果复位键按下则正确,错误都清零
- begin
- correct<=0;
- error<=0;
- end
- else if(cmd_t==0&&cmd==enter)//当按键按下,且是enter键按下时对密码进行比较
- if(inputpassword==PASSWORD)//密码正确时correct=1
- begin
- correct<=1;
- error<=0;
- end
- else //密码错误时,error为1
- begin
- error<=1;
- correct<=0;
- end
- else
- begin
- correct<=0;
- error<=0;
- end
- end
- //修改密码
- always@(posedge clk )
- begin
- if(cmd_t==0&&cmd==sure)
- begin
- PASSWORD<=inputpassword;
- mimagaile<=1;
- end
- else
- mimagaile<=0;
- end
- //记录错误次数
- always@(posedge clk or negedge resetb)
- begin
- if(!resetb)//复位时密码重试次数清零
- try_count<=0;
- else
- if(error==1)//当输入密码错误时,重试次数加1
- try_count<=try_count+2'b01;
- else if(main_state==pass||main_state==alarm)//当有一次成功,重试次数超过三次后,进入报警后重试次数清零
- try_count<=0;
- end
- endmodule
- //按键模块
- module scankey(clk,a,b,keyvalue);
- input clk;
- input [3:0]b;
- output reg[3:0]a;
- output reg [3:0]keyvalue;
- reg [1:0]q;
- reg [3:0] qdb;//消抖后的b
- reg [3:0]rxbuf;
- always @( posedge clk) begin //按键消抖
- rxbuf[0] <= b[0];
- qdb[0] <= ~(rxbuf[0] & (~b[0]));
- end
- always @( posedge clk) begin //按键消抖
- rxbuf[1] <= b[1];
- qdb[1] <= ~(rxbuf[1] & (~b[1]));
- end
- always @( posedge clk) begin //按键消抖
- rxbuf[2] <= b[2];
- qdb[2] <= ~(rxbuf[2] & (~b[2]));
- end
- always @( posedge clk) begin //按键消抖
- rxbuf[3] <= b[3];
- qdb[3] <= ~(rxbuf[3] & (~b[3]));
- end
- always@(posedge clk)
- begin q<=q+1;
- case(q)
- 0:a<=4'b1110;
- 1:a<=4'b1101;
- 2:a<=4'b1011;
- 3:a<=4'b0111;
- endcase
- case({a,qdb})
- 8'b1110_0111:keyvalue<=4'b0000;//按键0
- 8'b1110_1011:keyvalue<=4'b0001;//按键1
- 8'b1110_1101:keyvalue<=4'b0010;
- 8'b1110_1110:keyvalue<=4'b0011;
- 8'b1101_0111:keyvalue<=4'b0100;
- 8'b1101_1011:keyvalue<=4'b0101;
- 8'b1101_1101:keyvalue<=4'b0110;
- 8'b1101_1110:keyvalue<=4'b0111;
- 8'b1011_0111:keyvalue<=4'b1000;//按键8
- 8'b1011_1011:keyvalue<=4'b1001;//按键9
- 8'b1011_1101:keyvalue<=4'b1010;//确认键
- 8'b1011_1110:keyvalue<=4'b1011;//清除键
- 8'b0111_0111:keyvalue<=4'b1100;
- 8'b0111_1011:keyvalue<=4'b1101;//改密键
- 8'b0111_1101:keyvalue<=4'b1110;
- 8'b0111_1110:keyvalue<=4'b1111;
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
完整论文下载(word格式 可编辑):
EDA电子密码锁课程设计报告.docx
(673.02 KB, 下载次数: 188)
|