独立按键
首先既然是检测输入,对于当然要用到拉电阻,来检测引脚电平变化变化。51单片机中,除了P0口外,P2,P3,P4都是内置上拉电阻的准双向IO口,一般 的 51 P0引脚都外接了上拉电阻,当然也可以用作输入口。
作为输入前需要拉为高电平。 当有按键按下,致使单片机的某个引脚接地,变为低电平时,我们就认为这个按键按下了。当按键松开后,由于输入不会锁存,所以此时拉高的引脚回归到高电平。
独立按键的内部原理。
独立按键的4个引脚中,两两为一组。每一组的2个引脚是连在一起的,当按键按键时,2个组又连接了,也就是4个脚都连接一起了。
在按键没有按下去的时候1,2号脚相连,3,4号脚相连。按键按下去的时候,1,2,3,4号脚就全部接通。
按键的很重要注意点就是消除抖动,消抖。因为人按下按键不是并瞬间到位的,按键在按下的过程中会有抖动。我们需要通过延时来让单片机绕过抖动的时间。
下面是一个用按键作为开关间接控制LED的demo。
注:下图中P2.0连接的按键应该再接一个电阻,我疏忽忘记画出来了。
/***************************************
按键按下,LED亮,松开,LED熄灭
**************************************/
#include<reg51.h> typedef unsigned int uint; typedef unsigned char uchar ; sbit button = P2^0; //按键输入引脚 sbit led = P0^0; //LED控制输出引脚 /***************************/ void delay(uint t); uchar isKeyPressed(void); /***************************/ void main(void) { button = 1; //P2 是 准 IO口,作为输入前要写1 led = 1; while(1) { if(isKeyPressed()) { led = 0; delay(100); led =1; } } } uchar isKeyPressed(void) { uchar isPressed = 0; //是否按下标志位 uchar c=50; if(button==0) //初次检测 { delay(5); //消抖延时 if(button==0) //再次验证 { isPressed = 1; while(isPressed==0 && c--) //如果不用c作为计数器,那么一直按着按键的话,程序就会一直在这里循环。是否要用c需要根据自己的要求。 ; } } return isPressed; } void delay(uint t) { uint i; uchar j; for(i=t;i>0;i--) for(j=110;j>0;j--) ; }
矩阵按键
矩阵按键的检测方式有多种,最常用的就是行列式扫描检测。原理和独立按键是一样的,只不过我们要扫描一组按键,找出那个被按下的而已。
对行列式扫描的分析。
假如我们按下了按键S6,现在来检测它。
用红色表示1高电平,蓝色表示0低电平。
先给键盘连接的GPIO口赋值为0XF0。
错误修正:图中的行改为列
电平反转。
错误修正:图中的列改为行
这样就可以判断定了按键的坐标。
demo的连线图。
/******************************
将按键的编号显示到数码管上
*****************************/
#include<reg51.h> typedef unsigned int uint; typedef unsigned char uchar; typedef signed char schar; /*************************/ void delay(uint t) ; void showDigit(uint num); schar martixKeyScan(void); /***************************/ uchar code TABLE[10]={0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F} ; #define DUAN_XUAN P1 //数码管的段选 #define KEYS_REC P2 //连接矩阵键盘 sbit Add0 = P0^0; //译码器的A0 A1 A3,用来数码管的位选 sbit Add1 = P0^1; sbit Add2 = P0^2; void main(void) { schar keyRe; uint number=0; while(1) { keyRe = martixKeyScan(); if(-1 != keyRe){ number = keyRe; } showDigit(number); } } void showDigit(uint num) { uchar count = 0; //根据输入数据的位数来开启数码管的位。 do { switch(count) { case 0:Add2 = 1;Add1 = 1;Add0 = 1;break; //送入位选,显示这个数的个位 case 1:Add2 = 1;Add1 = 1;Add0 = 0;break; //显示十位 case 2:Add2 = 1;Add1 = 0;Add0 = 1;break; case 3:Add2 = 1;Add1 = 0;Add0 = 0;break; case 4:Add2 = 0;Add1 = 1;Add0 = 1;break; case 5:Add2 = 0;Add1 = 1;Add0 = 0;break; case 6:Add2 = 0;Add1 = 0;Add0 = 1;break; case 7:Add2 = 0;Add1 = 0;Add0 = 0;break; } DUAN_XUAN = TABLE[num%10]; //送入段选 delay(5); DUAN_XUAN = 0 ; //关闭所有段,消影 count++; }while(num/=10); } /********************** 矩阵按键检测。 有按键按下,返回按键的编号,否则返回-1; ***********************/ schar martixKeyScan(void) { schar col,row; uchar c=50; //松手计数器 KEYS_REC = 0xF0 ; //让连接键盘的高4位为1 ,低4位为0 if(KEYS_REC != 0xF0) //初次检查到按下 { delay(5); //消抖延时 if(KEYS_REC != 0xF0) //真的被按下了 { switch(KEYS_REC) { case 0X70: row =1 ;break; // 0111 0000 case 0XB0: row = 2; break; // 1011 0000 case 0XD0: row = 3;break; // 1101 0000 case 0XE0: row = 4;break; // 1110 0000 default:break; } KEYS_REC = 0x0F; //电平反转,检测列 switch(KEYS_REC) { case 0X07: col = 1;break; //0000 0111 case 0X0B: col = 2; break; //0000 1011 case 0X0D: col = 3;break; //0000 1101 case 0X0E: col = 4;break; //0000 1110 default:break; } while((c--) && (KEYS_REC!=0x0F)) //等待按键松手 { delay(5); } return (row-1)*4+col; //使用4X4的键盘 } //真的按下了 else return -1; } return -1; } void delay(uint t) { uint i,j; for(i=t;i>0;i--) for(j=123;j>0;j--) ; }