华南理工大学数电课程设计Word下载.docx
《华南理工大学数电课程设计Word下载.docx》由会员分享,可在线阅读,更多相关《华南理工大学数电课程设计Word下载.docx(17页珍藏版)》请在冰豆网上搜索。
矩阵键盘识别电路从原理上讲就是一个典型的数字电路,包括组合逻辑电路和时序逻辑电路。
设计键盘扫描程序,将程序划分为时序产生模块、键盘扫描模块、键值译码模块,蜂鸣器模块四个模块,时序产生模块为键盘扫描和蜂鸣器模块产生时钟信号,键盘扫描模块采用行扫描法对4*4矩阵键盘进行扫描,键值译码模块将所按键值译码为共阴极8位7段数码管的显示码几个模块组合起来实现键盘扫描的设计要求。
第2章、方案论证(设计理念)
1设计任务
设计任务的设计功能包括:
1单独按某个键,数码管显示该键的数字,如J0,显示00,J1,显示01…,J15显示15。
2同时按两个或以上按键,显示ER。
3单独按某个键,发出一音“嘀”,同时按两个或以上按键,发出一音“嘀”,连续发出“嘟嘟嘟……”,直到松开按键,声音关闭。
(1)设计理念:
将矩阵键盘识别电路各个功能分成模块来实现,包括分频模块描模块、键值译码模块,蜂鸣器模块四个模块,在主电路中通过连线实现识别功能。
分模块能使电路看起来更有条理,接线更清晰,功能更加可靠,排查错误更简单和更有针对性。
2方案论证;
一:
识别方式:
判断键盘上哪个键被按下,可以采用静态译码法或扫描法,静态译码法原理简单,容易理解,但电路复杂,扫描法比较抽象,电路相对简单,通常采用,扫描法又称为逐行或列扫描查询法,它是一种最常用的多按键识别方法。
综上,选取扫描方法
二:
实现方式
方案1:
采用用门电路和各种寄存器等搭建组合时序电路的方式来实现,可以采用移位寄存器循环扫描信号,并通过数据选择器来判断各种情况,这种方法实现原理简单,但搭电路的时候复杂,接线繁多,尤其是识别两个以上的按键时不灵活,容易漏接错接,且检查错误比较麻烦。
方案2:
采用用硬件描述语言Veriloghdl来实现,Veriloghdl语言和c语言比较类似,所以上手比较快,因此,虽然之前没接触过该语言,但在做课程设计的这段时间里,用它来实现课程设计所要实现的功能还是可以的。
用这种方法的话,程序简单易懂,而且比较简洁,思路比较清晰,尤其在识别两个按键以上的时候优越性特别明显。
方案3:
采用用硬件描述语言vhdl来实现,与Veriloghdl相似,但是vhdl的语法比Veriloghdl复杂一点,由于没有学过,对该语言一窍不通。
所以该方案不考虑。
综上所述,选取方案二。
第3章、过程论述
1总电路
作用:
将各个模块串连起来以实现识别电路的功能。
图1总电路图
输入1kHZ的频率,首先经过分频器成1HZ,100HZ,250HZ,500HZ的脉冲,用于驱动蜂鸣器,1kHZ的脉冲进入扫描模块,扫描模块将扫描结果分别送给显示译码器模块和蜂鸣器模块,从而驱动两个led数码管显示结果,只有一个键按下时,蜂鸣器发出一音“嘀”,当同时按两个或以上按键,发出一音“嘀”,连续发出“嘟嘟嘟……”。
2分频模块
在输入脉冲只有11kHZ的情况下,将1kHZ的脉冲分频成1HZ,100HZ,250HZ,500HZ的脉冲,用于驱动蜂鸣器,不同的频率使蜂鸣器发出不同的声音。
图2分频模块电路图
图中各成分的作用,和成分之间的交互:
输入1kHZ的脉冲,运用7490芯片构成分频电路,当7490的SET9A,SET9B,CLRA.CLRB管脚接低电平CLKA接QD输出管脚,CLKB接输入脉冲,QA输出脉冲,构成十分频电路。
依据这样的原理,经过三个十分频即可输出100,1HZ的脉冲信号。
分频模块的下部分是用D触发器构成的二分频电路,因此可以分频出500HZ,250HZ的脉冲信号。
3扫描模块:
判断按键的状态,即识别按键,按照识别结果输出一个按键标志位flag,错误按键标志位flag2,和按键值key_value。
图3.扫描模块电路逻辑符号图
图4矩阵键盘结构图
程序见附录,各成分的作用,和成分之间的交互:
扫描流程
1、判断键盘中有无键按下
将全部列线KR0-KR3置低电平然后检测行线KL0-KL3的状态,只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中,若所有行线均为高电平则表示键盘中无键按下。
2、判断按键所在的位置
在确认有键按下后,即可进入确定具体闭合键的过程,其方法是依次将列线置为低电平,即在置某根列线为低电平时,其它线为高电平,例如:
KR0KR1KR2KR3置0111,之后扫描KL端,当J0键按下,则KL0输出为0,其余则为1,即KL3KL2KL1KL0输出为1110,此时就可以判断为J0键被按下,数码管显示01,依此类推,判断其他键。
而在一次扫描过程中,当扫描到某列有键按下,即将该列的按键标志置1,在扫描结束后,如果有多列置1,就判断有多个键按下,从而key_value=16,即报错,而在一行之中的最后判断之中,例如KR0-KR3置1110时,当KL3KL2KL1KL0输出至少两个管脚为低电平时,也判断为多个按键按下,即就报错。
即识别思想是在一次轮回中,依次将KR0KR1KR2KR3分别置为00000,0111,1011,1101,1101,此次扫描结束才判断扫描结果,判断按键错误的顺序是先列后行。
表1按键位置与数码的关系KR——KL
J0
J1
J2
J3
J4
J5
1110_1110
1101_1110
1011_1110
0111_1110
1110_1101
1101_1101
J6
J7
J8
J9
J10
J11
1011_1101
0111_1101
1110_1011
1101_1011
1011_1011
0111_1011
J12
J14
J15
J16(即报错标志)
1110_0111
1101_0111
1011_0111
0111_0111
defualt
4译码模块
将输进来的key_value译码出相应的码给led1,led2显示。
程序见附录。
图5.译码模块逻辑符号图
第4章、结果分析
1分频模块
Clk输入1KHZ的脉冲信号,分频出500HZ,250HZ,100HZ,1HZ的信号,分析波形结果正确。
图6分频模块仿真波形
2译码模块
当电路输入key_value分别为:
00000,00001,00010,00011,00100,00101,00110,00111,01000,
01001,01010,01011,01100,01101,01110,01111,10000
led1输出:
00111111,00111111,00111111,00111111,00111111
00111111,00111111,00111111,00111111,00111111,00110000
00110000,00110000,00110000,00110000,00110000,01111001
led2输出:
00111111,00110000,01011011,01001111,01100110
01101101,01111100,00000111,01111111,01101111,00111111
00110000,01011011,01001111,01100110,01101101,01110111
图7.译码模块的仿真波形图
3扫描模块
扫描程序依次将KR0KR1KR2KR3置0111,1011,1101,1110,进行扫描。
图8.扫描模块的仿真波形图
4总电路
在时钟的控制下,扫描程序依次将KR0KR1KR2KR3置0111,1011,1101,1110,进行扫描,如果第一个键按下时,此时flag置一,数码管中led1,led2都置00111111。
其他的同理。
图9.总电路仿真波形图
第5章、课程设计总结
1收获与心得
通过本次课程设计,我收获到在课堂上所不能给予我的知识和处理问题的能力,也深刻体会到,正如老师在任务书中说的一样,做设计是一件很辛苦的事情,千万不能够浮躁,想走捷径,只有静下心来,根据本课程的知识、查找资料、学习前人经验,才能有自己的作品。
在设计过程中,感觉自己收获到了很多比仅仅做题,上课更丰富的知识,同时也加深了对数电知识的理解,并且这个过程现在回想起来真的很奇妙——自己能够独立地运用自己学的知识来设计电路,真的很有成就感。
让我感受最深的是在这次设计之中出现的那些问题,真的,做设计如同人生,并不是一帆风顺的,也不能一蹴而就。
从选择矩阵键盘的这道题开始,就意味着我要开始接受一个新的挑战。
说实话,一开始选择这道题目是因为之前有接触过矩阵键盘,后来才发现用数电知识来实现和我之前接触的有特别大的区别,真的可以说天壤之别。
在选择方案的时候,一开始挺纠结,是要用描述语言还是用搭电路的方法,因为我之前没接触过硬件描述语言。
后来通过论证,果断选了硬件语言,硬件语言对我来说真的是一个新的东西,所以这不得不说是一个新的挑战。
也正因为此次设计,我对Veriloghdl语言有了一个大概的了解。
选择了用描述语言来描述电路,首先就是要补充知识,我把数电课本的关于硬件语言的那章看了,然后就到处于找关于Veriloghdl的语法资料。
在写扫描程序的过程中,单个按键检测比较容易,但当然这个过程出现了很多小问题,这些小问题有时候也是挺难发现的,有时候就改了一个地方,然后程序就可以正常工作了,所以程序编译了数不清n遍,出现问题的时候就找找书,例如阻塞语句和非阻塞语句的区别,还有case语句在Veriloghdl中的应用等,尤其是阻塞语句和非阻塞语句,花了很久才搞懂是什么回事。
最困难的部分是两个以上按键的检测,首先是扫描方法,如何检测出两个以上的按键,真的想了好久,看着那个矩阵键盘原理图想了不知道多少遍了。
一开始想出来的程序,按照原理,它应该能够检测出不同行的两个按键以上的,但是结果却出乎我意料,竟然只能够识别同一列的两个以上按键,然后检测很久也没发现问题,真的考验人的耐心,奇怪的是在之后的写的程序,没怎么改,它就正常工作了。
之后用它又写了一个程序,虽然感觉那个原理能够检测任意两个以上按键但结果却是只能检测不同行。
迫于无奈,只能改另外一种扫描方法,前一种扫描方法由于时间关系,只能先放下查找它的错误,自己感觉可能对Veriloghdl有些细节的东西还不是很清楚,可能这也是此次设计遇到的最大问题。
之后的那个程序扫描方法在实现过程中也是遇到各种问题,经过查资料,最后很幸运都解决了。
在程序调试的时候,需要的是发现问题的细心和耐心,程序问题才能够一一解决。
数电课程设计过程充满挑战,既有有趣的地方,又有困难的让人想要放弃的地方。
每当想到一个新方法,就想去用它,验证它,有时睡在床上想着,想出一些解决方案,于是跳下床,到电脑前操作,这也许就是它的魅力,每一个困难都让人跃跃欲试下想要克服它。
在每一个问题解决的背后需要一颗有耐心的心和思考的大脑。
在不断发现问题和解决问题的过程中,收获的不仅仅是知识,更是一种主动的态度。
学习是一种态度。
我觉得我很享受做课程设计的过程,它让我经历了柳暗花明的喜悦,让我在这个过程中的到很多的满足感。
2致谢
衷心感谢老师在实验过程中的谆谆教导,通过实验,我更加巩固了课堂上的知识,也感谢学校安排了这次数电设计,让我有了这次不同以往的经历,增加了我实践的机会。
附录1:
参考文献
[1]阎石.数学电子技术基础.北京:
高等教育出版社
[2]夏宇闻.Verilog数字系统设计教程.北京.北京航空航天大学出版社
[3]魏家明.Verilog编程艺术.电子工业出版社
附录2:
部分采用verilog语言编写的模块的原程序…
扫描模块程序
/********************************************************
*时钟CLK管脚:
PIN_18*
*键盘col输入管脚:
PIN_8,PIN_7,PIN_6,PIN_5*
*键盘row输出管脚:
PIN_14,PIN_13,PIN_12,PIN_11*
*实验结果:
按键每个数字对应亮灯数,其它按键对应不同结果*
*********************************************************/
modulejuzhen(clk,incol,outrow,key_value,key_flag,key_flag1);
inputclk;
//定义时钟引脚
input[3:
0]incol;
//定义横向数据输入
output[3:
0]outrow;
//定义纵向数据输出
output[4:
0]key_value;
//定义识别的按键值
outputkey_flag,key_flag1;
//定义按键标志,flag表示一个flag
//flag2表示两个按键
reg[3:
0]row;
reg[3:
0]incol_reg;
//寄存扫描行值
0]outrow_reg;
//寄存扫描列值
reg[2:
0]state;
//状态标志
regkey_flag,key_flag1;
//按键标志位
reg[4:
0]key_value;
//读取的状态值
0]incol_1,incol_2,incol_3,incol_4;
regstate1,state2,state3,state4;
0]statez;
//总的按键标志
always@(posedgeclk)
begin
case(state)
0:
row<
=4'
b0000;
key_flag<
=1'
b0;
key_flag1<
if(incol!
b1111)
begin
state<
=1;
row<
b1110;
end
elsestate<
=0;
end
1:
incol_1<
=incol;
state1<
b1;
state<
=2;
b1101;
else
state<
2:
incol_2<
state2<
=3;
b1011;
state2<
end
3:
incol_3<
state3<
=4;
b0111;
state3<
4:
begin
begin
incol_4<
state4<
=5;
end
else
beginstate<
state4<
end
5:
statez<
={state4,state3,state2,state1};
case(statez)
4'
b1000:
beginincol_reg<
=incol_4;
outrow_reg<
case(incol_4)
b1110:
key_flag<
b1101:
b1011:
b0111:
b0011:
key_flag1<
b1100:
b1001:
b0101:
b1010:
b0110:
default:
endcase
end
b0100:
=incol_3;
case(incol_3)
b0010:
beginincol_reg<
=incol_2;
case(incol_2)
b0001:
=incol_1;
case(incol_1)
endcase
state<
always@(clkoroutrow_regorincol_reg)
case({outrow_reg,incol_reg})
8'
b1110_1110:
beginkey_value<
=5'
b00000;
b1101_1110:
b00001;
b1011_1110:
b00010;
b0111_1110:
b00011;
b1110_1101:
b00100;
b1101_1101:
b00101;
b1011_1101:
b00110;
b0111_1101:
b00111;
b1110_1011:
b01000;
b1101_1011:
b01001;
b1011_1011:
b01010;
b0111_1011:
b01011;
b1110_0111:
b01100;
b1101_0111:
b01101;
b1011_0111:
b01110;
b0111_0111:
b01111;
default:
b10000;
assignoutrow=row;
endmodule
译码模块程序:
moduleyima(key_value,led1,led2);
i