九、 按键
9.1 按键原理
- 当按键按下的时候,从高电平到低电平,当从低电平到高电平时会产生电流异常抖动。抖动时间一般为5ms~10ms。
- 一般开发板没有对按键进行硬件消抖处理,我们需要进行软件消抖(就是增加延时)。
9.1.1 独立按键原理
我们可以看到原理图,单片机芯片引脚默认输出高电平。当我们按下按键,这个引脚就接地导通,就是该引脚为低电平,当检测到引脚是低电平,就代表按键按下。
9.1.2 矩阵按键原理
矩阵按键原理和独立按键原理基本一样,重点就在于怎么检测按下的是哪一个按键。
这里给出一个方法:
- 先给所有行(P17~P14)输出低电平,检测所有列(P13 ~P10)中哪一列为低电平(确定按键的列)。
- 给所有列(P13~ P10)输出低电平,检测所有行(P17~P14)中哪一行为低电平(确定按键的行)。
9.2 代码
9.2.1 独立按键实验代码
- 这里我们使用四个独立按键控制四个LED灯,分别为P20~ P23的亮灭。
- 建立文件夹Sw1。
#include <reg52.h>
typedef unsigned int uint;
typedef unsigned char uchar;
sbit sw1=P3^2;
sbit sw2=P3^3;//按键
sbit sw3=P3^4;
sbit sw4=P3^5;
sbit LED1=P2^0;
sbit LED2=P2^1;//LED
sbit LED3=P2^2;
sbit LED4=P2^3;
void delay(uint i){
while(i--){
}
}
void main(){
while(1){
delay(10000);
if(!sw1) LED1=!LED1;
if(!sw2) LED2=!LED2;
if(!sw3) LED3=!LED3;
if(!sw4) LED4=!LED4;
delay(10000);
}
}
- 按键更改LED的状态,当我们按下按键,引脚为低电平(if条件),则更改LED状态,亮则熄灭,灭则点亮,(翻转状态)。
9.2.2 矩阵按键实验代码
- 矩阵按键扫描代码。
#ifndef __SCAN_BUTTON_H__//引用外部文件
#define __SCAN_BUTTON_H__
//扫描矩阵按键
#include <reg52.h>
typedef unsigned int uint;
typedef unsigned char uchar;
sbit across1=P1^7;
sbit across2=P1^6;//按键-行
sbit across3=P1^5;
sbit across4=P1^4;
sbit vertical1=P1^3;
sbit vertical2=P1^2;//按键-列
sbit vertical3=P1^1;
sbit vertical4=P1^0;
uint Table16[4][4]={{0x3f,0x06,0x5b,0x4f}, //宏定义4X4矩阵
{0x66,0x6d,0x7d,0x07},
{0x7f,0x6f,0x77,0x7c},
{0x39,0x5e,0x79,0x71}};
//确定行
uint get_line(void){ //get_line函数用于确定按键所在的行。然后逐一检测引脚的状态,如果有一行引脚为低电平,则代表按键所在的行是这行
uint retVal=4;//retVal初始值设置为4,当我们在检测时,如没检测到按键,返回一个错误值,可通过返回值是否为4判断是否有按键被按下。
across1=0;//将列引脚全部置为低电平
across2=0;
across3=0;
across4=0;
if(!vertical1) retVal=1;//检测4个竖直方向的引脚,如果有为低,则将retVal变量设置为相应的值,分别为1234。如果有按键按下,则通过检测引脚的状态来确定是哪一个按键被按下,就设置为相应的值。
if(!vertical2) retVal=2;
if(!vertical3) retVal=3;
if(!vertical4) retVal=4;
across1=1;//将列引脚重置为默认状态,置为高电平
across2=1;
across3=1;
across4=1;
return retVal;//并返回按键所在的行。
}
//确定列
uint get_col(void){
uint retVal=4;
vertical1=0;
vertical2=0;
vertical3=0;
vertical4=0;
if(!across1) retVal=1;
if(!across2) retVal=2;
if(!across3) retVal=3;
if(!across4) retVal=4;
vertical1=1;
vertical2=1;
vertical3=1;
vertical4=1;
return retVal;
}
#endif
显示代码
#ifndef __DISPIAY_UTILS_H__
#define __DISPIAY_UTILS_H__
#include <reg52.h>
sbit P22=P2^2;
sbit P23=P2^3;
sbit P24=P2^4;
void choose_dispiay(uint i){ //choose_diapiay此函数用于选择数码管显示,接收一个函数i,用来指定需显示的数码管,在函数内部,使用传入的参数i,通过P2的三个引脚,选择选择相应的数码管进行显示。其中,选择数码管的方法是通过设置P22、P23、P24三个引脚的输出电平来实现,共有八种不同的组合方式,对应8个数码管。
switch(i){
case 0:P24=1;P23=1;P22=1;break;
case 1:P24=1;P23=1;P22=0;break;
case 2:P24=1;P23=0;P22=1;break;
case 3:P24=1;P23=0;P22=0;break;
case 4:P24=0;P23=1;P22=1;break;
case 5:P24=0;P23=1;P22=0;break;
case 6:P24=0;P23=0;P22=1;break;
case 7:P24=0;P23=0;P22=0;break;
}
}
#endif
9.2.2.1 实验一:主函数
- 按下按键矩阵中的按键,在第一个数码管显示
#inlcude <Scan_Button.h>//引用外部文件
#include <dispiay_utils.h>
void delay (uint i){
while(i--){}
}
void mian (){
while(1){
uint line=4;
uint col=4;
delay (10000);
line = get_line();
col = get_col();
delay(10000);
if(line<4 && col<4){
P0=Table16[line][col];
}
}
}
9.2.2.2 实验二:主函数
- 按下字符后依次显示
#include <Scan_Button.h>
#include <dispiay_utils.h>
void delay(uint i){
while(i--){}
}
void main(){
uint buffer[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
int index=0;
while(1){
uint line=4;
uint col=4;
uinti;
delay(6000);
line=get_line();
col=get_col;
delay(6000);
if(line<4 && col<4){
if (index>7 )index=0;
buffer[index++]=Teble16[line][col];
}
for(i=0; i<8; ++i){
choose_display(i);
delay(100);
P0=buffer[i];
delay(100);
P0=0x00;
}
}
}
9.2.3 代码翻译
9.2.3.1 独立按键实验中的if语句?
- 按键主要作用为改变LED的状态,如果按下按键,引脚置为低电平(if包含的条件),就更改LED状态,亮则熄灭,灭则点亮。
9.3 整体总结
- 实验二中矩阵按键检测和数码管显示的时延很难调整,按键速度要够快,不然会出现误检测(出现多个按键同时操作)。