在单片机系统中应用按键的时候,如果只需要按下一次按键加 1 或减 1,那用第 8 章学到的知识就可以完成了,但如果想连续加很多数字的时候,要一次次按下这个按键确实有点不方便,这时我们会希望一直按住按键,数字就自动持续增加或减小,这就是所谓的长短按键应用。 
  当检测到一个按键产生按下动作后,马上执行一次相应的操作,同时在程序里记录按键按下的持续时间,该时间超过 1 秒后(主要是为了区别短按和长按这两个动作,因短按的时间通常都达到几百 ms),每隔 200ms(如果你需要更快那就用更短的时间,反之亦然)就自动再执行一次该按键对应的操作,这就是一个典型的长按键效果。 
  对此,我们做了一个模拟定时炸弹效果的实例,提供给大家作为参考。打开开关后,数码管显示数字 0,按向上的按键数字加 1,按向下的按键数字减 1,长按向上按键 1 秒后,数字会持续增加,长按向下按键 1 秒后,数字会持续减小。设定好数字后,按下回车按键,时间就会进行倒计时,当倒计时到 0 的时候,用蜂鸣器和板子上的 8 个 LED 小灯做炸弹效果,蜂鸣器持续响,LED 小灯全亮。
 
- #include <reg52.h>  
-   
- sbit BUZZ = P1^6;  
- 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 LedBuff[7] = {   
-     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF  
- };  
- unsigned char code KeyCodeMap[4][4] = {   
-     { 0x31, 0x32, 0x33, 0x26 },   
-     { 0x34, 0x35, 0x36, 0x25 },   
-     { 0x37, 0x38, 0x39, 0x28 },   
-     { 0x30, 0x1B, 0x0D, 0x27 }   
- };  
- unsigned char KeySta[4][4] = {   
-     {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}  
- };  
- unsigned long pdata KeyDownTime[4][4] = {   
-     {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}  
- };  
-   
- bit enBuzz = 0;   
- bit flag1s = 0;   
- bit flagStart = 0;   
- unsigned char T0RH = 0;   
- unsigned char T0RL = 0;   
- unsigned int CountDown = 0;   
-   
- void ConfigTimer0(unsigned int ms);  
- void ShowNumber(unsigned long num);  
- void KeyDriver();  
-   
- void main(){  
-     EA = 1;   
-     ENLED = 0;   
-     ADDR3 = 1;  
-     ConfigTimer0(1);   
-     ShowNumber(0);   
-      
-     while (1){  
-         KeyDriver();   
-         if (flagStart && flag1s){   
-             flag1s = 0;  
-             if (CountDown > 0){   
-                 CountDown--;  
-                 ShowNumber(CountDown);   
-                 if (CountDown == 0){   
-                     enBuzz = 1;  
-                       
-                     LedBuff[6] = 0x00;   
-                 }  
-             }  
-         }  
-     }  
- }  
-   
- void ConfigTimer0(unsigned int ms){  
-     unsigned long tmp;   
-     tmp = 11059200 / 12;   
-     tmp = (tmp * ms) / 1000;   
-     tmp = 65536 - tmp;   
-     tmp = tmp + 28;   
-     T0RH = (unsigned char)(tmp>>8);   
-     T0RL = (unsigned char)tmp;  
-     TMOD &= 0xF0;   
-     TMOD |= 0x01;   
-     TH0 = T0RH;   
-     TL0 = T0RL;  
-     ET0 = 1;   
-     TR0 = 1;   
- }  
-       
- void ShowNumber(unsigned long num){  
-     signed char i;  
-     unsigned char buf[6];  
-     for (i=0; i<6; i++){   
-         buf[i] = num % 10;  
-         num = num / 10;  
-     }  
-     for (i=5; i>=1; i--){   
-         if (buf[i] == 0){  
-             LedBuff[i] = 0xFF;  
-         }else{  
-             break;  
-         }  
-     }  
-      
-     for ( ; i>=0; i--){   
-         LedBuff[i] = LedChar[buf[i]];  
-     }  
- }  
-   
- void KeyAction(unsigned char keycode){   
-     if (keycode == 0x26){   
-         if (CountDown < 9999){   
-             CountDown++;  
-             ShowNumber(CountDown);  
-         }  
-     }else if (keycode == 0x28){   
-         if (CountDown > 1){   
-             CountDown--;  
-             ShowNumber(CountDown);  
-         }  
-     }else if (keycode == 0x0D){   
-         flagStart = 1;   
-     }else if (keycode == 0x1B){   
-         enBuzz = 0;   
-         LedBuff[6] = 0xFF;   
-         flagStart = 0;   
-         CountDown = 0;   
-         ShowNumber(CountDown);  
-     }  
- }  
-   
- void KeyDriver(){  
-     unsigned char i, j;  
-     static unsigned char pdata backup[4][4] = {   
-         {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}  
-     };  
-     static unsigned long pdata TimeThr[4][4] = {   
-         {1000, 1000, 1000, 1000}, {1000, 1000, 1000, 1000},  
-         {1000, 1000, 1000, 1000}, {1000, 1000, 1000, 1000}  
-     };  
-      
-     for (i=0; i<4; i++){   
-         for (j=0; j<4; j++){  
-             if (backup[i][j] != KeySta[i][j]){   
-                 if (backup[i][j] != 0){   
-                     KeyAction(KeyCodeMap[i][j]);   
-                 }  
-             }  
-             backup[i][j] = KeySta[i][j];  
-             if (KeyDownTime[i][j] > 0){  
-                 if (KeyDownTime[i][j] >= TimeThr[i][j]){   
-                     KeyAction(KeyCodeMap[i][j]);   
-                     TimeThr[i][j] += 200;   
-                 }  
-             }else{   
-                 TimeThr[i][j] = 1000;   
-             }  
-         }  
-     }  
- }  
-   
- void KeyScan(){  
-     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}  
-     };  
-      
-       
-     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++){   
-           
-         if ((keybuf[keyout][i] & 0x0F) == 0x00){  
-             KeySta[keyout][i] = 0;  
-             KeyDownTime[keyout][i] += 4;   
-           
-         }else if ((keybuf[keyout][i] & 0x0F) == 0x0F){  
-             KeySta[keyout][i] = 1;  
-         }  
-     }  
-     KeyDownTime[keyout][i] = 0;   
-       
-     keyout++;   
-     keyout &= 0x03;   
-     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;  
-     }  
- }  
-   
- void LedScan(){  
-     static unsigned char i = 0;   
-     P0 = 0xFF;   
-     P1 = (P1 & 0xF8) | i;   
-     P0 = LedBuff[i];   
-     if (i < 6){   
-         i++;  
-     }else{  
-         i = 0;  
-     }  
- }  
-   
- void InterruptTimer0() interrupt 1{  
-     static unsigned int tmr1s = 0;   
-     TH0 = T0RH;   
-     TL0 = T0RL;  
-     if (enBuzz){   
-         BUZZ = ~BUZZ;   
-     }else{  
-         BUZZ = 1;   
-     }  
-     LedScan();   
-     KeyScan();   
-     if (flagStart){   
-         tmr1s++;  
-         if (tmr1s >= 1000){  
-             tmr1s = 0;  
-             flag1s = 1;  
-         }  
-     }else{   
-         tmr1s = 0;  
-     }  
- }   
 
  长按键功能实现的重点有两个:第一,是在原来的矩阵按键扫描函数 KeyScan 内,当检测到按键按下后,持续的对一个时间变量进行累加,其目的是用这个时间变量来记录按键按下的时间;第二,是在按键驱动函数 KeyDriver 里,除了原来的检测到按键按下这个动作时执行按键动作函数 KeyAction 外,还监测表示按键按下时间的变量,根据它的值来完成长按时的连续快速按键动作功能。