Key4 を例にとると、デバウンスには 2ms のスケジュール割り込みが使用され、キーの状態が 8 回連続 (16ms) 判定されます。
すべて 1 の場合、ポップアップが表示され、キー (Keysta) の現在の状態が 1 になります。
すべてが 0 の場合は、それを押してキー (Keysta) の現在のステータスを 0 に設定します。
残りの状態はすべてジッタリングしており、ボタンの現在の状態は変化しません。
鍵の状態はメインプログラムで判断され、現在の鍵の状態(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 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; //使能U3 选中数码管DS1
ADDR3 = 1;
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
TMOD = 0x01; //T0为模式1
TH0 = 0xf8; //定时2ms
TL0 = 0xcd;
ET0 = 1;
TR0 = 1; //启动T0
P2 = 0xf7; //P2.3置0,即输出低电平
P0 = LedChar[cnt]; //显示按键次数
while(1)
{
if(KeySta != backup) //当前值与前次值不相等说明此时有动作
{
if(backup == 0) //如果前次值为0,则说明是弹起动作
{
cnt++; //按键次数加1
if(cnt >= 10)
{
cnt = 0; //10次清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 //其他情况则按键状态还未稳定
{}
}