这个实验的内容是:采用4x4矩阵按键,预先对每个矩阵按键的键值进行设置,然后通过按下按键,在四位数码管上以滚显的方式显示相应的值,并在Proteus上仿真。
我设置的矩阵按键为:
Proteus图:
通过使用行列扫描法对矩阵按键进行扫描监测,具体实现过程会在程序中详细讲解。
具体实现方式请看下面的程序:
#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); //显示键值函数
}
}
#ifndef __MAIN_H__
#define __MAIN_H__
#include"segDisplay.h"
#include"keyScan.h"
#endif
#include"keyScan.h"
unsigned char keyScan(){
unsigned char a=0;
unsigned char t;
unsigned char KeyValue=16; //无按键按下时反馈回去16
P2=0xF0; //高四位全为1,代表矩阵按键的列,低四位全为0,代表矩阵按键的行,
//只要有按键按下时,按下的按键所在的列就会为0
if(P2!=0xF0){ //读取按键是否按下
//Delay(1000);//延时 10ms 进行按键消抖,因为按键按下时,有一小段电压不稳定的时间
//for循环用的是一个定时器延时,作用和delay(1000)是一样的,定时器延时可以节省CPU开销
for(t=0;t<10;t++){
timer0_init();
while(~TF0);
TF0=0;
}
//再次检测键盘是否按下
if(P2!=0xF0){ //再次检测键盘是否按下
//一个按键的位置是由行和列决定的,下面程序是先确定按键的列再确定按键的行
//测试列
P2=0XF0;
switch(P2){
case(0X70): KeyValue=3;break; //从左往右,第四列,P2=0111 0000,下面同理
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; //从上往下,第四行,P2=0000 0111,下面同理
case(0X0B): KeyValue=KeyValue+8;break;
case(0X0D): KeyValue=KeyValue+4;break;
case(0X0E): KeyValue=KeyValue;break;
}
//延迟一段时间,以确保按键松开,否则在按下其间会多次扫描按键 ,我是延时0.5秒
while((a<50)&&(P2!=0x0F)){
//Delay(1000);
//下面又是定时器延时
for(t=0;t<10;t++){
timer0_init();
while(~TF0);
TF0=0;
}
a++;
}
}
return KeyValue; //返回键值
}
#ifndef __KEYSCAN_H__
#define __KEYSCAN_H__
#include"timer0_init.h"
unsigned char keyScan();
extern unsigned char keyValue[4]; //外部变量声明
#endif
#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;//消隐上次显示的数字,使下次显示更清晰
}
}
#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
#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;
}
#ifndef __TIMER0_INIT_H__
#define __TIMER0_INIT_H__
#include"reg52.h"
void timer0_init();
#endif