独立按键
独立按键的扫描
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit LED9 = P0^7;
sbit LED8 = P0^6;
sbit LED7 = P0^5;
sbit LED6 = P0^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;
void main()
{
ENLED = 0; //选择独立LED进行显示
ADDR3 = 1;
ADDR2 = 1;
ADDR1 = 1;
ADDR0 = 0;
P2 = 0xF7; //P2.3置0,即KeyOut1输出低电平
while (1)
{
//将按键扫描引脚的值传递到LED上
LED9 = KEY1; //按下时为0,对应的LED点亮
LED8 = KEY2;
LED7 = KEY3;
LED6 = KEY4;
}
}
- 计数值显示到数码管上
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;
unsigned char code LedChar[] = { //数码管显示字符转换表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
void main()
{
bit backup = 1; //定义一个位变量,保存前一次扫描的按键值
unsigned char cnt = 0; //定义一个计数变量,记录按键按下的次数
ENLED = 0; //选择数码管DS1进行显示
ADDR3 = 1;
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
P2 = 0xF7; //P2.3置0,即KeyOut1输出低电平
P0 = LedChar[cnt]; //显示按键次数初值
while (1)
{
if (KEY4 != backup) //当前值与前次值不相等说明此时按键有动作
{
if (backup == 0) //如果前次值为0,则说明当前是由0变1,即按键弹起
{
cnt++; //按键次数+1
if (cnt >= 10)
{ //只用1个数码管显示,所以加到10就清零重新开始
cnt = 0;
}
P0 = LedChar[cnt]; //计数值显示到数码管上
}
backup = KEY4; //更新备份为当前值,以备进行下次比较
}
}
}
按键消抖
在绝大多数情况下,我们是用软件即程序来实现消抖的。最简单的消抖原理,就是当检测到按键状态变化后,先等待一个 10ms 左右的延时时间,让抖动消失后再进行一次按键状态检测,如果与刚才检测到的状态相同,就可以确认按键已经稳定的动作了。
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;
unsigned char code LedChar[] = { //数码管显示字符转换表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
void delay();
void main()
{
bit keybuf = 1; //按键值暂存,临时保存按键的扫描值
bit backup = 1; //按键值备份,保存前一次的扫描值
unsigned char cnt = 0; //按键计数,记录按键按下的次数
ENLED = 0; //选择数码管DS1进行显示
ADDR3 = 1;
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
P2 = 0xF7; //P2.3置0,即KeyOut1输出低电平
P0 = LedChar[cnt]; //显示按键次数初值
while (1)
{
keybuf = KEY4; //把当前扫描值暂存
if (keybuf != backup) //当前值与前次值不相等说明此时按键有动作
{
delay(); //延时大约10ms
if (keybuf == KEY4) //判断扫描值有没有发生改变,即按键抖动
{
if (backup == 0) //如果前次值为0,则说明当前是弹起动作
{
cnt++; //按键次数+1
if (cnt >= 10)
{ //只用1个数码管显示,所以加到10就清零重新开始
cnt = 0;
}
P0 = LedChar[cnt]; //计数值显示到数码管上
}
backup = keybuf; //更新备份为当前值,以备进行下次比较
}
}
}
}
/* 软件延时函数,延时约10ms */
void delay()
{
unsigned int i = 1000;
while (i--);
}
优化消抖
假如左边时间是起始 0 时刻,每经过 2ms 左移一次,每移动一次,判断当前连续的 8 次按键状态是不是全 1 或者全 0,如果是全 1 则判定为弹起,如果是全 0 则判定为按下,如果0 和 1 交错,就认为是抖动,不做任何判定。
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;
unsigned char code LedChar[] = { //数码管显示字符转换表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
bit KeySta = 1; //当前按键状态
void main()
{
bit backup = 1; //按键值备份,保存前一次的扫描值
unsigned char cnt = 0; //按键计数,记录按键按下的次数
EA = 1; //使能总中断
ENLED = 0; //选择数码管DS1进行显示
ADDR3 = 1;
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
TMOD = 0x01; //设置T0为模式1
TH0 = 0xF8; //为T0赋初值0xF8CD,定时2ms
TL0 = 0xCD;
ET0 = 1; //使能T0中断
TR0 = 1; //启动T0
P2 = 0xF7; //P2.3置0,即KeyOut1输出低电平
P0 = LedChar[cnt]; //显示按键次数初值
while (1)
{
if (KeySta != backup) //当前值与前次值不相等说明此时按键有动作
{
if (backup == 0) //如果前次值为0,则说明当前是弹起动作
{
cnt++; //按键次数+1
if (cnt >= 10)
{ //只用1个数码管显示,所以加到10就清零重新开始
cnt = 0;
}
P0 = LedChar[cnt]; //计数值显示到数码管上
}
backup = KeySta; //更新备份为当前值,以备进行下次比较
}
}
}
/* T0中断服务函数,用于按键状态的扫描并消抖 */
void InterruptTimer0() interrupt 1
{
static unsigned char keybuf = 0xFF; //扫描缓冲区,保存一段时间内的扫描值
TH0 = 0xF8; //重新加载初值
TL0 = 0xCD;
keybuf = (keybuf<<1) | KEY4; //缓冲区左移一位,并将当前扫描值移入最低位
if (keybuf == 0x00)
{ //连续8次扫描值都为0,即16ms内都只检测到按下状态时,可认为按键已按下
KeySta = 0;
}
else if (keybuf == 0xFF)
{ //连续8次扫描值都为1,即16ms内都只检测到弹起状态时,可认为按键已弹起
KeySta = 1;
}
else
{} //其它情况则说明按键状态尚未稳定,则不对KeySta变量值进行更新
}
矩阵按键
矩阵按键的扫描
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY_IN_1 = P2^4;
sbit KEY_IN_2 = P2^5;
sbit KEY_IN_3 = P2^6;
sbit KEY_IN_4 = P2^7;
sbit KEY_OUT_1 = P2^3;
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P2^1;
sbit KEY_OUT_4 = P2^0;
unsigned char code LedChar[] = { //数码管显示字符转换表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char KeySta[4][4] = { //全部矩阵按键的当前状态
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
};
void main()
{
unsigned char i, j;
unsigned char backup[4][4] = { //按键值备份,保存前一次的值
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
};
EA = 1; //使能总中断
ENLED = 0; //选择数码管DS1进行显示
ADDR3 = 1;
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
TMOD = 0x01; //设置T0为模式1
TH0 = 0xFC; //为T0赋初值0xFC67,定时1ms
TL0 = 0x67;
ET0 = 1; //使能T0中断
TR0 = 1; //启动T0
P0 = LedChar[0]; //默认显示0
while (1)
{
for (i=0; i<4; i++) //循环检测4*4的矩阵按键
{
for (j=0; j<4; j++)
{
if (backup[i][j] != KeySta[i][j]) //检测按键动作
{
if (backup[i][j] != 0) //按键按下时执行动作
{
P0 = LedChar[i*4+j]; //将编号显示到数码管
}
backup[i][j] = KeySta[i][j]; //更新前一次的备份值
}
}
}
}
}
/* T0中断服务函数,扫描矩阵按键状态并消抖 */
void InterruptTimer0() interrupt 1
{
unsigned char i;
static unsigned char keyout = 0; //矩阵按键扫描输出索引
static unsigned char keybuf[4][4] = { //矩阵按键扫描缓冲区
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}
};
TH0 = 0xFC; //重新加载初值
TL0 = 0x67;
//将一行的4个按键值移入缓冲区
keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
//消抖后更新按键状态
for (i=0; i<4; i++) //每行4个按键,所以循环4次
{
if ((keybuf[keyout][i] & 0x0F) == 0x00)
{ //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下
KeySta[keyout][i] = 0;
}
else if ((keybuf[keyout][i] & 0x0F) == 0x0F)
{ //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起
KeySta[keyout][i] = 1;
}
}
//执行下一次的扫描输出
keyout++; //输出索引递增
keyout = keyout & 0x03; //索引值加到4即归零
switch (keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚
{
case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
default: break;
}
}