实验二 键盘显示实验
实验准备:软件Keil uVision5、Proteus 8 Professional
-
实验目的
1、掌握矩阵键盘检测的原理和方法;
2、掌握按键消抖的方法;
3、再次熟悉数码管的显示。
-
实验任务
从4×4矩阵键盘输入4位字符(如“15EF”),并显示于4位数码管。
-
实验原理
在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,如图2-1所示。在矩阵键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。
图2-1 矩阵键盘
矩阵键盘的按健识别方法很多,其中最常见的方法是行扫描法。行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法,下面介绍矩阵键盘的扫描过程。
(1)判断有无键按下
第一步:向所有的列输出口线输出低电平;
第二步:然后将行线的电平状态读入;
第三步:判断读入的行线值。若无键按下,所有的行线仍保持高电平状态;若有键按下,行线中至少应有一条线为低电平。
(2)去除按键的抖动
去抖原理:当判断到键盘上有键按下后,则延时一段时间再判断键盘的状态,若仍为有键按下状态,则认为有一个键按下,否则当作按键抖动来处理。
(3)按键识别(列或行扫描法)
在确认有键按下后,即可进入确定具体闭合键的过程。其方法是:依次将列(行)线置为低电平,即在置某根列(行)线为低电平时,其列(行)线为高电平,再逐行(列)检测各行(列)线的电平状态。若某行为低电平,则该行线与置为低电平的列线交叉处的按键就是闭合的按键。
(4)求按键的键值
根据闭合键的行值row和列值col采用计算法(如健值=行号×4+列号)或查表法将闭合键的行值和列值转换成所定义的键值。
电路原理图如下图所示。
图2-2 键盘显示实验电路
注释:上面的原理是课程设计给的模板,不是我写的,仅供参考,如有相同就是参考的,参考书:单片机原理与接口技术实验指导书、单片机原理与接口技术
-
程序流程图
图一 程序流程图
-
实验结果及分析总结
键盘显示实验测试结果
该电路图根据该实验指导书绘制,使用的软件Proteus 8 Professional,如图二所示,将编写好的代码(代码详情转附录)录入到该电路,从而实现键盘显示实验。(图中数码管输入的内容是本人学号后四位,如需需要输入其他内容可根据按键进行更改)。
图二 键盘显示电路仿真测试
编写数码管动态显示代码
本次实验实验代码模块化的内容,是根据本人在网络视频学习所得(江协科技——51单片机入门教程视频所得),本次实验模块化编程内容如图二所示。
附录中代码的顺序:main.c(主程序调用函数)、main.h(主程序的header文件)、keyScan.c(按键扫描函数)、keyScan.h、segDisplay.c(数码显示函数)、segDisplay.h、time0_int.c(定时器延迟函数)、time0_int.h。
图三 模块化代码编写内容
实验总结
本次实验运用之前偶然所学的模块编程的知识内容,首先,需要解决的问题是四个数码管输入问题。课程的学习只是一个数码管的编写,因此,使用数组keyValue完成四个数码管的定义,之后进行数码管的移位。其次,需要解决按键扫描的问题,再其次是需要解延时的问题,最后将编写好的程序在主函数中调用。本次的实验,需要结合学习过的知识点进行整合,修改合理的代码内容。在编写代码是需要先画出流程图,将程序模块化。处理的代码内容更加的清晰明了。
-
程序附录
-
main.c程序
#include"main.h" void main() { unsigned char temp=0; unsigned char keyValue[4]={0}; //定义一个数组,用来存放四个数码管所显示的值 while(1){ temp=keyScan(); //keyScan()为矩阵按键扫描函数 if(temp!=16) { //因为矩阵按键所表示的值是0~15(在数码管上是显示0~F),所以要满足temp<16才执行下面滚显的指令 //当按键按了后,有新值进入数码管时,数码管的旧值都往左移一位,腾出一个位置给新值显示 keyValue[3]=keyValue[2]; keyValue[2]=keyValue[1]; keyValue[1]=keyValue[0]; keyValue[0]=temp; } segDisplay(keyValue); //显示键值函数 } }
main.h
#ifndef __MAIN_H__ #define __MAIN_H__ #include"segDisplay.h" #include"keyScan.h" #endif
segDisplay.c
#include"segDisplay.h" //显示0~F的值,采用共阳数码管 //定义中的code代表的是把定义的数据表存储在flash存储器中,如去掉code则存储在RAM中 unsigned char code sgmduan[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; void segDisplay(unsigned char *value){ unsigned char i; for(i=0;i<4;i++){ switch(i){ //位选,选择点亮的数码管, //数码管从右往左排序 case(0): LSA=0;LSB=0;LSC=0;LSD=1; break;//显示第 0 位 case(1): LSA=0;LSB=0;LSC=1;LSD=0; break;//显示第 1 位 case(2): LSA=0;LSB=1;LSC=0;LSD=0; break;//显示第 2 位 case(3): LSA=1;LSB=0;LSC=0;LSD=0; break;//显示第 3 位 } P0=sgmduan[value[i]];//发送段码 //Delay(100); //间隔一段时间扫描 //定时器延时 timer0_init(); while(~TF0); TF0=0; P0=0xFF;//消隐上次显示的数字,使下次显示更清晰 } }
segDisplay.h
-
#ifndef __SEGDISPLAY_H__ #define __SEGDISPLAY_H__ #include"timer0_init.h" sbit LSA=P1^3; sbit LSB=P1^2; sbit LSC=P1^1; sbit LSD=P1^0; void segDisplay(unsigned char *value); #endif
keyScan.c
#include "keyScan.h" unsigned char keyScan() { unsigned char a = 0; unsigned char t; unsigned char KeyValue = 16; P2 = 0xF0; if (P2 != 0xF0) { for (t = 0; t < 10; t++) { timer0_init(); while (~TF0); TF0 = 0; } if (P2 != 0xF0) { P2 = 0xF0; switch (P2) { case (0x70): KeyValue = 3; break; case (0xB0): KeyValue = 2; break; case (0xD0): KeyValue = 1; break; case (0xE0): KeyValue = 0; break; } P2 = 0x0F; switch (P2) { case (0x07): KeyValue = KeyValue + 12; break; case (0x0B): KeyValue = KeyValue + 8; break; case (0x0D): KeyValue = KeyValue + 4; break; case (0x0E): KeyValue = KeyValue; break; } while ((a < 50) && (P2 != 0x0F)) { for (t = 0; t < 10; t++) { timer0_init(); while (~TF0); TF0 = 0; } a++; } } } return KeyValue;
keyScan.h
#ifndef __KEYSCAN_H__ #define __KEYSCAN_H__ #include"timer0_init.h" unsigned char keyScan(); extern unsigned char keyValue[4]; //外部变量声明 #endif
timer0_init.c
#include"timer0_init.h" void timer0_init(){ //定时器初始化函数 EA=1; //打开总中断 ET0=1; //中断0控制允许位 TR0=1; //开启中断0 TMOD=0x01;//定时器工作模式为1 TH0=0xfc;//定时器延时10ms(延时1ms为FC66H) TL0=0x66; }
timer0_init.h
#ifndef __TIMER0_INIT_H__ #define __TIMER0_INIT_H__ #include"reg52.h" void timer0_init(); #endif
学习过程中,参考资料网上的,如有侵权删。如有需要自行下载源文件,里面code文件是程序代码,还有一个仿真文件。