長按是在短按的基礎上,以一個很短的時間(10ms)再次判斷按鍵是否片於按下狀態,當達到一定的時間(1s)后,按鍵還處於按下狀態,說明是長按狀態,結合上一節的短按,下面實現一個從0-99的累加,短按時一次加1,長按后,進入快速累加的過程,同時使用了定時器來定時刷新數碼管,在Display的處理上就和之前的不同,原來在Display里通過循環刷新每個數碼管的顯示,現在放到了定時器定時觸發的事件里,設置定時時間為2ms,這2ms只負責刷新共陰極的8位數碼的一位,所以需要在定時事件里處理每次刷新不同位置的數碼管。
#include <reg52.h> sbit KeyAdd = P0^0; sbit LED = P0^1; sbit LATCH1=P2^2;//段鎖存 sbit LATCH2=P2^3;//位鎖存 unsigned char code DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 顯示段碼值0~9 unsigned char code WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//位碼 unsigned char TempData[8]; //存儲顯示值 unsigned char vT = 0; void Delay(unsigned int t); void Display(unsigned char Index); void InitTime0(void); void main(void) { unsigned char numadd = 0; // 累加的結果 unsigned int vExtend = 0; // 用於判斷是否滿足長按標准 LED = 0; TempData[0] = DuanMa[0]; TempData[1] = DuanMa[0]; InitTime0(); while (1) { if (!KeyAdd) // 發現按下 { Delay(1500); // 延時去抖 if (!KeyAdd) // 如果還處於按下 { while (!KeyAdd) //等待彈起 { Delay(100); // 延時,這里要短一點,vExtend長些,這樣有利於精確的判斷是否放開 vExtend++; // 長按計數 if (vExtend == 1000) // 按下時間大約1s認為長按 { vExtend = 0; //清空計數初值 while(!KeyAdd) // 如果按鍵還處於按下狀態,則快速增加 { if (numadd == 99) numadd = 0; else numadd++; TempData[0] = DuanMa[numadd / 10]; TempData[1] = DuanMa[numadd % 10]; Delay(10000); //延時讓數字顯示一段時間,否則數字不動直到放開按鈕后突然跳變 } } } vExtend = 0; //設置初值,為下一次長按做准備 if (numadd == 99) numadd = 0; else numadd++; TempData[0] = DuanMa[numadd / 10]; TempData[1] = DuanMa[numadd % 10]; } } } } void Delay(unsigned int t) { while (--t); } void Display(unsigned char Index) { P1 = 0; //清空數據,防止有交替重影 LATCH1 = 1; //段鎖存 LATCH1 = 0; P1 = WeiMa[Index]; //取位碼 LATCH2=1; //位鎖存 LATCH2=0; P1 = TempData[Index]; //取顯示數據,段碼 LATCH1=1; //段鎖存 LATCH1=0; } void InitTime0(void) { TMOD = 0x01; TH0 = 0xF8; // 計數初值F830H = 2000 (65536-63536=2000 * 1us = 2ms) TL0 = 0x30; ET0 = 1; // EA即IE^1 等於1時申請中斷定時器0中斷打開 EA = 1; // 總中斷打開 TR0 = 1; // 啟動定時器0 } void MyInterrept(void) interrupt 1 { LED = !LED; TH0 = 0xF8; //重新賦值 2ms TL0 = 0x30; Display(vT); vT++; if (vT == 8) vT = 0; }