资源描述
数字逻辑设计
课程设计报告书
题目名称:电子密码锁
学 院:光 电 信 息 学 院
小组成员:钟永捷4
侯晨涛3
徐 昊9
指导教师:李 力
日 期: 2023年6月28日
一、 小组成员分工情况
侯晨涛:所有编程工作、资料查找 工作量:60%
钟永捷:辅助编程、图表制作、资料查找 工作量:20%
徐 昊:论文写作、图表制作、资料查找 工作量:20%
二、 题目分析
1. 输入信号
通过扫描键盘的行与检测键盘的列得到输入信号。
2. 输出信号
通过译码器得到的显示器显示信息,开关锁动作。
三、 设计总框图
四、 各模块说明
(一) 键盘扫描模块
1. 原理
通过时序信号产生脉冲,不间断地向矩阵键盘的行输入1110-1101-1011-0111的循环序列。同时将各列的电平置高,检测矩阵键盘各列的电平变化。若在一定期间内,扫描到第列电平为零时恰好第行的输入电平也为零,则判断键盘上位置上键被按下。
2. 模块框图
时序信号
4*3键盘
寄存器 比较
行
列
行
3. 状态表
此模块只需要通过编码器实现即可,假定前四位表达各行扫描结果,后三位表达各列扫描的结果。
动作
行输入
列输入
状态命名
编码输出
按下“0”键
0111
101
S0
0000
按下“1”键
1110
110
S1
0001
按下“2”键
1110
101
S2
0010
按下“3”键
1110
011
S3
0011
按下“4”键
1101
110
S4
0100
按下“5”键
1101
101
S5
0101
按下“6”键
1101
011
S6
0110
按下“7”键
1011
110
S7
0111
按下“8”键
1011
101
S8
1000
按下“9”键
1011
011
S9
1001
按下“#”键
0111
011
S10
1010
按下“*”键
0111
110
S11
1011
4. 仿真结果
Key_in代表按键按下与否情况,Key_mem将其记录并输出,scan为行扫描信号,Key_out为按键输出值。如上仿真结果所示,当scan为1110时,扫描第一行。按下第一个键,即Key_in为110,此时Key_out为0001,即输出值为1。其它状态依此类推。
(二) 输入模块
1. 原理
设立两个寄存器,一个作为用户所想设立密码的密码寄存器。另一个寄存器则是将键盘Input的键值存储起来。最后通过一个比较器将两个寄存器的值进行比较。若相同则输出“open”,反之,输出“error”。比较器内部通过多位异或门实现。
2. 模块框图
判 断
寄存器
输 入
寄存器
3. 状态图
4. 仿真结果
1) 删除字符
第一次输入值为0101,Number_sig第0到3位将其保存。第二次输入值为0011,Number_sig第4到7位将其保存。第三次输入值为0001,Number_sig第8到11位将其保存。第四次输入值为1010,即删除键。第五次输入值为0111,Number_sig第8到11位的值由0001变为0111,即实现了删除功能。
2) 密码输入对的
Correct=1说明密码输入对的,Number_sig的值为,Number_sig的值通过七段显示译码器之后将使数码管显示OPEn00。
3) 密码输入错误
Correct=1说明密码输入对的,Number_sig的值为,Number_sig的值通过七段显示译码器之后将使数码管显示ERROR0。
(三) 密码判断及更改
1. 原理
密码判断模块:通过比较器将输入寄存器与存储寄存器中的数据进行比较,假如数据相同,则判断密码对的。假如数据不同,则返回输入等待状态,并对输入寄存器中的数据清零。
密码更改模块:将第一次与第二次输入寄存器中的数据输入比较器比较,假如数据相同则将该数据输入进密码存储寄存器中。假如数据不同,则返回数据输入前的数据等待状态。
2. 模块框图
比较器
相同
不同
存 储
寄存器
返回输入前状态
第一次输入寄存器
第二次输入寄存器
输入
输入
比较器
输入寄存器
存储寄存器
输入
输入
不同
相同
判断密码对的
3. 仿真结果
main_state为10000即update状态,按键六次输入值为0110,0110,0110,0110,0110,0010,第二次输入相同。即将密码由666666改为266666。第二次输入完毕same为1,说明两次输入相同。按“#”键确认后。当状态变为01000时,即in_put输入密码Inputpd为即266666,correct为1说明密码修改成功并开锁。
(四) 主状态机
1. 原理
状态分五个状态:Waits,Input,Pass,Update,Forbid。
在Waits状态下,摁下“#”进入密码“Input”状态,在“Input”状态下摁“*”可删除当前Input的字符。若密码输入对的则进去“Pass”状态,否则进入“Forbid”状态,这时若摁下“#”键,则重新返回“Waits”状态。摁下“*”键进入“Update”状态,输入两次密码然后摁“#”键进行拟定,若两次密码不相同则Update失败,重新返回到“Pass”状态。若两次密码相同,则返回到“Waits”状态。
2. 模块框图
#
Forbid
Pass
两次
输入
不同
+
#键
*
Update
Waits
Input
#
Right
Wrong
两次输入相同+ # 键
3. 状态表
4. 仿真结果
1) 密码输入错误
按下“#”键,进行密码输入(main_state由00001变为01000),此时error为1说明密码输入错误。main_state变为forbid状态(由01000变为00100)。再按下“#”键,重新返回waits状态(由00100变为00001)。
2) 密码输入对的,且修改密码成功
按下“#”键,进行密码输入(main_state由00001变为01000),此时correct为1说明密码输入对的。由in_put变为pass(由01000变为00010)。按下“*”进行密码修改,由00010变为10000修改对的,主状态重新返为wait。
3) 密码输入对的,但密码修改失败
按下“#”键,进行密码输入(main_state由00001变为01000),此时correct为1说明密码输入对的。由in_put变为pass(由01000变为00010)。按下“*”进行密码修改,由00010变为00010主状态由修改错误重新返为pass。
(五) 显示
1. 原理
这里的选择24位数码管控制模块,将24位拆分为六组四位编码输入七段译码器。将译码输出与扫描模块产生的扫描时序共同作用于六位数码管。得到所需显示结果。
2. 模块框图
数码管控制模块
(24位)
七段译码器
扫描模块
六位数码管
输入
扫描
分六组输入四位编码
开始扫描
3. 仿真结果
输入信号Number_sig的值为即123456,Scan_sig的值为011111时,即第一个数码管亮时Duan_date的值为0110000即数码管显示数字为1。综合以上,此时第一个数码管显示为1,之后第二个数码管显示为2,第三个数码管显示为3……
五、 验证方案
采用自上而下的设计方案,一方面将题目规定拆提成各大模块,然后通过编写Verilog语言的程序实现各模块的功能。在 中仿真出时序逻辑图,并验证程序的对的性。
图1.设计总框图的实现
六、 课程设计心得体会
通过这次数字密码锁的课程设计,我们掌握了如何通过数字逻辑知识来设计一个可应用于生产生活中的拥有实际应用功能的数字逻辑器件。一方面我们要了解其具体功能规定,然后采用自上而下的设计方法,建立整体逻辑框图并将其划分为各个具体功能模块。之后,我们通过编写Verilog程序实现每一模块的功能。在编译无错误后,通过quartus 2软件自带的波形仿真功能检测模块功能是否实现。当波形达成规定,将各模块拼接,得到最终的密码锁整体逻辑结构(如图1)。
在讨论课程设计时,我们最初想通过简朴的逻辑门和逻辑器件来实现密码锁功能,以简化程序部分。但是由于状态之间转换的复杂性,无法实现。之后我们决定每一功能模块均通过程序来实现,并自动生成状态图及逻辑图。这样工作的任务所有转移到编程上。
编程的感想:对于编程,我想说从对verilog一窍不通(C也不太会)到能独立地使用其进行编程,这将近一月的时间里,我学会了很多,一开始面对这个题目,完全不知道从何下手,从图书馆借了一本书就开始慢慢看,然后就尝试着去写,有时候一个简朴的错误困扰了我整整一天甚至两天都想不出来。这个题目的程序是我这将近一个月的心血,每一行都是通过思考后写下的。通过这次课程设计,我体会到了编程的乐趣,当你长时间困扰在一个问题上,忽然间的一个奇思妙想就可以解决问题或者实现一个以前实现不了的功能,就是这种偶尔的惊喜使得我坚持了下来。这次课程设计美中局限性的是,虽然各个模块都可以实现其功能,但是将其和在一起就会有问题,虽然编译无错误,但是功能无法实现。由于时间因素,无法对其进行修正,这是我的一个遗憾。
程序编写的同时我们进行状态表的绘制,不同于软件仿真出的状态表,我们将状态简化绘制表格,只体现编程时的大体思绪。在这个过程中,我们纯熟掌握了如何将抽象的状态变化绘制成状态转移表。以及简朴状态图的绘制方法。
七、 源文献(详见附件)
源代码:
top.v //顶层文献
******************************************************************************************
module top(clk,Rst,key_out,Duan_date,Scan_sig);
input clk;
input Rst;
input [3:0] key_out;
output [6:0] Duan_date;
output [5:0] Scan_sig;
wire [3:0] scan;
wire [2:0] key_in;
wire [2:0] key_mem;
wire correct;
wire error;
wire same;
wire [4:0] main_state;
wire [23:0] Number_sig;
wire [23:0] Inputpd;
main_state_machine M1
(
.clk(clk),
.Rst(Rst),
.key_out(key_out),
.correct(correct),
.error(error),
.same(same),
.main_state(main_state),
.key_mem(key_mem)
);
key_scan M2
(
.clk(clk),
.Rst(Rst),
.key_in(key_in),
.scan(scan),
.key_out(key_out),
.key_mem(key_mem)
);
In_put M3
(
.clk(clk),
.Rst(Rst),
.key_out(key_out),
.key_mem(key_mem),
.correct(correct),
.error(error),
.main_state(main_state),
.Number_sig(Number_sig),
.Inputpd(Inputpd)
);
passwdcom M4
(
.clk(clk),
.Rst(Rst),
.key_out(key_out),
.Inputpd(Inputpd),
.main_state(main_state),
.key_mem(key_mem),
.correct(correct),
.error(error),
.same(same)
);
top_led M5
(
.clk(clk),
.Rst(Rst),
.Number_sig(Number_sig),
.Duan_date(Duan_date),
.Scan_sig(Scan_sig)
);
endmodule
******************************************************************************************
Key_scan.v //键盘扫描
******************************************************************************************
module key_scan(clk,scan,key_in,key_out,key_mem,Rst);
input clk;
input Rst;
input [2:0] key_in;
output [3:0] scan;
output [3:0] key_out;
output [2:0] key_mem;
reg [3:0] scan;
reg [3:0] key_out;
reg [31:0] counter;
reg _20clk;
reg [1:0] Q;
reg [2:0] key_mem;
always @(posedge clk or negedge Rst)
if(!Rst)
begin
counter <= 0;
end
else
begin
counter <= counter + 1'b1;
if( counter == 12500)
begin
counter <= 0;
_20clk <= ~_20clk;
end
end
always @( posedge _20clk )
begin
Q <= Q + 1'b1;
end
always @(posedge clk or negedge Rst)
begin
if(!Rst)
key_mem <= 3'b111;
else
case(Q)
2'b00:
begin
scan = 4'b1110;
case( key_in )
3'b110 :
begin
key_out <= 4'd1;
key_mem <= 3'b110;
end
3'b101 :
begin
key_out <= 4'd2;
key_mem <= 3'b101;
end
3'b011 :
begin
key_out <= 4'd3;
key_mem <= 3'b011;
end
default : key_out <= 4'dz;
endcase
end
2'b01:
begin
scan = 4'b1101;
case( key_in )
3'b110 :
begin
key_out <= 4'd4;
key_mem <= 3'b110;
end
3'b101 :
begin
key_out <= 4'd5;
key_mem <= 3'b101;
end
3'b011 :
begin
key_out <= 4'd6;
key_mem <= 3'b011;
end
default : key_out <= 4'dz;
endcase
end
2'b10:
begin
scan = 4'b1011;
case( key_in )
3'b110 :
begin
key_out <= 4'd7;
key_mem <= 3'b110;
end
3'b101 :
begin
key_out <= 4'd8;
key_mem <= 3'b101;
end
3'b011 :
begin
key_out <= 4'd9;
key_mem <= 3'b011;
end
default : key_out <= 4'dz;
endcase
end
2'b11:
begin
scan=4'b0111;
case( key_in )
3'b110 : key_out <= 4'd10;
3'b101 :
begin
key_out <= 4'd0;
key_mem <= 3'b101;
end
3'b011 : key_out <= 4'd11;
default : key_out <= 4'dz;
endcase
end
endcase
end
endmodule
******************************************************************************************
In_put.v //输入
******************************************************************************************
module In_put (clk,Rst,key_mem,Number_sig,key_out,Inputpd,correct,error,main_state);
input clk;
input Rst;
input [3:0] key_out;
input [2:0] key_mem;
input correct;
input error;
input [4:0] main_state;
output [23:0] Number_sig; //数码管显示数据
output [23:0] Inputpd;
reg [23:0] Number_sig;
reg [23:0] Inputpd;
reg [5:0] cur_state;
reg [5:0] next_state;
parameter first = 6'b000_001,
second = 6'b000_010,
third = 6'b000_100,
fourth = 6'b001_000,
fifth = 6'b010_000,
sixth = 6'b100_000,
finish = 6'b111_111;
parameter [4:0] waits = 5'b00001,
pass = 5'b00010,
forbid = 5'b00100,
in_put = 5'b01000,
update = 5'b10000;
always @(posedge clk or negedge Rst)
begin
if(!Rst)
cur_state <= first;
else
cur_state <= next_state;
end
reg KH2L_f1; //检测按键电平
reg KH2L_g1;
reg KH2L_f2;
reg KH2L_g2;
reg KH2L_f3;
reg KH2L_g3;
wire H2L_sig1;
wire H2L_sig2;
wire H2L_sig3;
always @(posedge clk or negedge Rst)
if(!Rst)
begin
KH2L_f1 <= 1'b1;
KH2L_g1 <= 1'b1;
KH2L_f2 <= 1'b1;
KH2L_g2 <= 1'b1;
KH2L_f3 <= 1'b1;
KH2L_g3 <= 1'b1;
end
else
begin
KH2L_f1 <= key_mem[0];
KH2L_g1 <= KH2L_f1;
KH2L_f2 <= key_mem[1];
KH2L_g2 <= KH2L_f2;
KH2L_f3 <= key_mem[2];
KH2L_g3 <= KH2L_f3;
end
assign H2L_sig1 = (KH2L_g1&(!KH2L_f1))? 1'b1:1'b0;
assign H2L_sig2 = (KH2L_g2&(!KH2L_f2))? 1'b1:1'b0;
assign H2L_sig3 = (KH2L_g3&(!KH2L_f3))? 1'b1:1'b0;
always @(posedge clk or negedge Rst)
begin
if(!Rst)
Number_sig <= 24'b0000_0000_0000_0000_0000_0000;
else if(main_state == in_put)
begin
if(correct == 1)
Number_sig <= 24'b0000_1100_1101_1110_0000_0000;
else if(error == 1)
Number_sig <= 24'b1101_1111_1111_0000_1111_0000;
else if(error == 0 && correct == 0)
case(cur_state)
first :
if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out == 4'd10))
next_state <= first;
else if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out != 4'd10))
begin
Number_sig[3:0] <= key_out;
next_state <= second;
end
else
next_state <= first;
second :
if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out == 4'd10))
next_state <= first;
else if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out != 4'd10))
begin
Number_sig[7:4] <= key_out;
next_state <= third;
end
else
next_state <= second;
third :
if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out == 4'd10))
next_state <= second;
else if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out != 4'd10))
begin
Number_sig[11:8] <= key_out;
next_state <= fourth;
end
else
next_state <= third;
fourth :
if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out == 4'd10))
next_state <= third;
else if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out != 4'd10))
begin
Number_sig[15:12] <= key_out;
next_state <= fifth;
end
else
next_state <= fourth;
fifth :
if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out == 4'd10))
next_state <= fourth;
else if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out != 4'd10))
begin
Number_sig[19:16] <= key_out;
next_state <= sixth;
end
else
next_state <= fifth;
sixth :
if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out == 4'd10))
next_state <= fifth;
else if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out != 4'd10))
begin
Number_sig[23:20] <= key_out;
next_state <= finish;
end
else
next_state <= sixth;
finish :
if((H2L_sig1||H2L_sig2||H2L_sig3) && (key_out == 4'd10))
next_state <= sixth;
else
next_state <= finish;
default next_state <= first;
endcase
end
end
always @(posedge clk or negedge Rst)
if(!Rst)
Inputpd = 0;
else if (cur_state == finish)
Inputpd = Number_sig;
endmodule
******************************************************************************************
Led_encode.v //数码管加码
******************************************************************************************
module led_encode(clk,Rst,Number_date,Duan_date);
input clk;
input Rst;
input [3:0] Number_date;
output [6:0] Duan_date;
parameter _0 = 7'b1111_110,
_1 = 7'b0110_000,
_2 = 7'b1101_101,
_3 = 7'b1111_001,
_4 = 7'b0110_011,
_5 = 7'b1011_011,
_6 = 7'b1011_111,
_7 = 7'b1110_000,
_8 = 7'b1111_111,
_9 = 7'b1111_011,
_p = 7'b1100_111,
_e = 7'b1001_111,
_n = 7'b1110_110,
_r = 7'b1110_111;
reg [6:0] rDuan;
always @(posedge clk or negedge Rst)
if(!Rst)
begin
rDuan <= 7'b0000_000;
end
else
case(Number_date)
4'd0 : rDuan <= _0;
4'd1 : rDuan <= _1;
4'd2 : rDuan <= _2;
4'd3 : rDuan <= _3;
4'd4 : rDuan <= _4;
4'd5 : rDuan <= _5;
4'd6 : rDuan <= _6;
4'd7 : rDuan <= _7;
4'd8 : rDuan <= _8;
4'd9 : rDuan <= _9;
4'd12 : rDuan <= _p;
4'd13 : rDuan <= _e;
4'd14 : rDuan <= _n;
4'd15 : rDuan <= _r;
endcase
assign Duan_date = rDuan;
endmodule
******************************************************************************************
passwdcom.v //密码比较及修改
******************************************************************************************
module passwdcom(clk,Rst,Inputpd,main_state,key_out,correct,error,key_mem,same);
input clk;
input Rst;
input [3:0] key_out;
input [23:0] Inputpd;
input [4:0] main_state;
input [2:0] key_mem;
output correct;
output error;
output same;
reg correct;
reg error;
reg [5:0] cur_state;
reg [5:0] next_state;
reg one;
reg same;
reg [4:0] in_put ,
update ;
initial
begin
in_put = 5'b01000;
update = 5'b10000;
end
reg [23:0] Password = 24'b0110_0110_0110_0110_0110_0110; //初始密码666666
always @(posedge clk or negedge Rst) //判断输入密码是否对的
if(!Rst)
begin
correct <= 0;
error <= 0;
end
else if(main_state == in_put)
if(Inputpd === Password) //密码输入对的
begin
correct <= 1;
error <= 0;
end
else //密码输入错误
begin
correct <= 0;
error <= 1;
end
parameter first = 6'b000_001, //定义按键状态
second = 6'b000_010,
third = 6'b000_100,
fourth = 6'b001_000,
fifth = 6'b010_000,
sixth = 6'b100_000,
finish = 6'b111_111,
finish2 = 6'b011_111;
reg KH2L_f1; //检测按键电平
reg KH2L_g1;
reg KH2L_f2;
reg KH2L_g2;
reg KH2L_f3;
reg KH2L_g3;
wire H2L_sig1;
wire H2L_sig2;
wire H2L_sig3;
always @(posedge clk or negedge Rst)
if(!Rst)
begin
KH2L_f1 <= 1'b1;
KH2L_g1 <= 1'b1;
KH2L_f2 <= 1'b1;
KH2L_g2 <= 1'b1;
KH2L_f3 <= 1'b1;
KH2L_g3 <= 1'b1;
end
else
begin
KH2L_f1 <= key_mem[0];
KH2L_g1 <= KH2L_f1;
KH2L_f2 <= key_mem[1];
KH2L_g2 <= KH2L_f2;
KH2L_f3 <= key_mem[2];
KH2L_g3 <= KH2L_f3;
end
as
展开阅读全文