|
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
單片機(jī)源程序如下:
#ifndef _KEY_H
#define _KEY_H
//#include"reg51.h"
sbit KEY_INPUT = P1^2; // 按鍵IO
#define KEY_STATE_0 0 // 按鍵狀態(tài)
#define KEY_STATE_1 1
#define KEY_STATE_2 2
#define KEY_STATE_3 3
#define KEY_STATE_4 4
#define KEY_STATE_5 5
#define KEY_STATE_6 6
#define KEY_STATE_7 7
#define KEY_STATE_8 8
#define KEY_STATE_9 9
#define SINGLE_KEY_TIME 3 // SINGLE_KEY_TIME*10MS = 30MS 判定單擊的時(shí)間長(zhǎng)度,軟件消抖
#define KEY_INTERVAL 70 // KEY_INTERVAL*10MS = 300MS 判定雙擊的時(shí)間間隔(仿真調(diào)慢了700MS)實(shí)際30-40
#define LONG_KEY_TIME 300 // LONG_KEY_TIME*10MS = 3S 判定長(zhǎng)按的時(shí)間長(zhǎng)度
#define N_KEY 0 // no click
#define S_KEY 1 // single click
#define D_KEY 2 // double click
#define T_KEY 3 // Triple click
#define F_KEY 4 //4擊
#define FIVE_KEY 5 //5擊
#define SIX_KEY 6 //6擊
#define SEVEN_KEY 7 //7擊
#define EIGHT_KEY 8 //8擊
#define NINE_KEY 9 //9擊
#define TEN_KEY 10 //10擊
#define L_KEY 15 // long press
//unsigned char key_driver(void);
//unsigned char key_read(void);
#endif
#include "key.h"
// =========================== key.c ======================
// ----------------------------------- key_driver --------------------------
unsigned char key_driver(void)
{
static unsigned char key_state = 0;
static unsigned int key_time = 0;
unsigned char key_press, key_return;
key_return = N_KEY; // 清除 返回按鍵值
key_press = KEY_INPUT; // 讀取當(dāng)前鍵值
switch (key_state)
{
case KEY_STATE_0: // 按鍵狀態(tài)0:判斷有無(wú)按鍵按下
if (!key_press) // 有按鍵按下
{
key_time = 0; // 清零時(shí)間間隔計(jì)數(shù)
key_state = KEY_STATE_1; // 然后進(jìn)入 按鍵狀態(tài)1
}
break;
case KEY_STATE_1: // 按鍵狀態(tài)1:軟件消抖(確定按鍵是否有效,而不是誤觸)。按鍵有效的定義:按鍵持續(xù)按下超過(guò)設(shè)定的消抖時(shí)間。
if (!key_press)
{
key_time++; // 一次10ms
if(key_time>=SINGLE_KEY_TIME) // 消抖時(shí)間為:SINGLE_KEY_TIME*10ms = 30ms;
{
key_state = KEY_STATE_2; // 如果按鍵時(shí)間超過(guò) 消抖時(shí)間,即判定為按下的按鍵有效。按鍵有效包括兩種:?jiǎn)螕艋蛘唛L(zhǎng)按,進(jìn)入 按鍵狀態(tài)2, 繼續(xù)判定到底是那種有效按鍵
}
}
else key_state = KEY_STATE_0; // 如果按鍵時(shí)間沒(méi)有超過(guò),判定為誤觸,按鍵無(wú)效,返回 按鍵狀態(tài)0,繼續(xù)等待按鍵
break;
case KEY_STATE_2: // 按鍵狀態(tài)2:判定按鍵有效的種類:是單擊,還是長(zhǎng)按
if(key_press) // 如果按鍵在 設(shè)定的長(zhǎng)按時(shí)間 內(nèi)釋放,則判定為單擊
{
key_return = S_KEY; // 返回 有效按鍵值:?jiǎn)螕?br />
key_state = KEY_STATE_0; // 返回 按鍵狀態(tài)0,繼續(xù)等待按鍵
}
else
{
key_time++;
if(key_time >= LONG_KEY_TIME) // 如果按鍵時(shí)間超過(guò) 設(shè)定的長(zhǎng)按時(shí)間(LONG_KEY_TIME*10ms=300*10ms=3000ms), 則判定為 長(zhǎng)按
{
key_return = L_KEY; // 返回 有效鍵值值:長(zhǎng)按
key_state = KEY_STATE_3; // 去狀態(tài)3,等待按鍵釋放
}
}
break;
case KEY_STATE_3: // 等待按鍵釋放
if (key_press)
{
key_state = KEY_STATE_0; // 按鍵釋放后,進(jìn)入 按鍵狀態(tài)0 ,進(jìn)行下一次按鍵的判定
}
break;
default: // 特殊情況:key_state是其他值得情況,清零key_state。這種情況一般出現(xiàn)在 沒(méi)有初始化key_state,第一次執(zhí)行這個(gè)函數(shù)的時(shí)候
key_state = KEY_STATE_0;
break;
}
return key_return; // 返回 按鍵值
}
// ----------------------------------- key_read --------------------------------
unsigned char key_read(void)
{
static unsigned char key_state1=0, key_time1=0;
unsigned char key_return,key_temp;
key_return = N_KEY; // 清零 返回按鍵值
key_temp = key_driver(); // 讀取鍵值
switch(key_state1)
{
case KEY_STATE_0: // 按鍵狀態(tài)0:等待有效按鍵(通過(guò) key_driver 返回的有效按鍵值)
if (key_temp == S_KEY ) // 如果是[單擊],不馬上返回單擊按鍵值,先進(jìn)入 按鍵狀態(tài)1,判斷是否有[雙擊]的可能
{
key_time1 = 0; // 清零計(jì)時(shí)
key_state1 = KEY_STATE_1;
}
else // 如果不是[單擊],直接返回按鍵值。這里的按鍵值可能是:[長(zhǎng)按],[無(wú)效按鍵]
{
key_return = key_temp; // 返回 按鍵值
}
break;
case KEY_STATE_1: // 按鍵狀態(tài)1:判定是否有[雙擊]
if (key_temp == S_KEY) // 有[單擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內(nèi),再次有[單擊],則為[雙擊],但是不馬上返回 有效按鍵值為[雙擊],先進(jìn)入 按鍵狀態(tài)2,判斷是否有[三擊]
{
key_time1 = 0; // 清零 時(shí)間間隔
key_state1 = KEY_STATE_2; // 改變 按鍵狀態(tài)值
// key_return = D_KEY; // 返回 有效按鍵:[雙擊]
// key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
else // 有[單擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內(nèi),沒(méi)有[單擊]出現(xiàn),則判定為 [單擊]
{
key_time1++; // 計(jì)數(shù) 時(shí)間間隔
if(key_time1 >= KEY_INTERVAL) // 超過(guò) 時(shí)間間隔
{
key_return = S_KEY; // 返回 有效按鍵:[單擊]
key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
}
break;
case KEY_STATE_2: // 按鍵狀態(tài)2:判定是否有[三擊]
if (key_temp == S_KEY) // 有[雙擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內(nèi),再次有[單擊],則為[三擊],由于這里只擴(kuò)展到[三擊],所以馬上返回 有效按鍵值為[三擊]
{
// key_return = T_KEY;
key_time1 = 0; // 返回 有效按鍵:[三擊]
key_state1 = KEY_STATE_3; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
else // 有[雙擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內(nèi),沒(méi)有[單擊],則判定為 [雙擊]
{
key_time1++; // 計(jì)數(shù) 時(shí)間間隔
if(key_time1 >= KEY_INTERVAL) // 超過(guò) 時(shí)間間隔
{
key_return = D_KEY; // 返回 有效按鍵 返回 有效按鍵:[2擊】
key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
}
break;
case KEY_STATE_3: // 按鍵狀態(tài)3:判定是否有[4擊]
if (key_temp == S_KEY) // 有[3擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內(nèi),再次有[單擊],則為[三擊]
{
// key_return = F_KEY; // 返回 有效按鍵:[4擊]
key_time1 = 0;
key_state1 = KEY_STATE_4; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
else // 有[3擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內(nèi),沒(méi)有[4擊],則判定為 [3擊]
{
key_time1++; // 計(jì)數(shù) 時(shí)間間隔
if(key_time1 >= KEY_INTERVAL) // 超過(guò) 時(shí)間間隔
{
key_return = T_KEY; // 返回 有效按鍵:[3擊]
key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
}
break;
case KEY_STATE_4: // 按鍵狀態(tài)4:判定是否有[5擊]
if (key_temp == S_KEY) // 有[4擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內(nèi),再次有[單擊],則為[5擊],由于這里只擴(kuò)展到[5擊],
{
//key_return = FIVE_KEY; // 返回 有效按鍵:[5擊]
key_time1 = 0;
key_state1 = KEY_STATE_5; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
else // 有[4擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內(nèi),沒(méi)有[5擊],則判定為 [4擊]
{
key_time1++; // 計(jì)數(shù) 時(shí)間間隔
if(key_time1 >= KEY_INTERVAL) // 超過(guò) 時(shí)間間隔
{
key_return = F_KEY; // 返回 有效按鍵:[4擊]
key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
}
break;
case KEY_STATE_5: // 按鍵狀態(tài)5:判定是否有[5擊]
if (key_temp == S_KEY) // 有[5擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內(nèi),再次有[單擊],則為[6擊]
{
// key_return = SIX_KEY; // 返回 有效按鍵:[6擊]
// key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
key_time1 = 0;
key_state1 = KEY_STATE_6; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
else // 有[5擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內(nèi),沒(méi)有[6擊],則判定為 [5擊]
{
key_time1++; // 計(jì)數(shù) 時(shí)間間隔
if(key_time1 >= KEY_INTERVAL) // 超過(guò) 時(shí)間間隔
{
key_return = FIVE_KEY; // 返回 有效按鍵:[5擊]
key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
}
break;
case KEY_STATE_6: // 按鍵狀態(tài)6:判定是否有[6擊]
if (key_temp == S_KEY) // 有[6擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內(nèi),再次有[單擊],則為[7擊]
{
// key_return = SEVEN_KEY; // 返回 有效按鍵:[7擊]
// key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
key_time1 = 0;
key_state1 = KEY_STATE_7; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
else // 有[6擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內(nèi),沒(méi)有[7擊],則判定為 [6擊]
{
key_time1++; // 計(jì)數(shù) 時(shí)間間隔
if(key_time1 >= KEY_INTERVAL) // 超過(guò) 時(shí)間間隔
{
key_return = SIX_KEY; // 返回 有效按鍵:[6擊]
key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
}
break;
case KEY_STATE_7: // 按鍵狀態(tài)7:判定是否有[7擊]
if (key_temp == S_KEY) // 有[7擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內(nèi),再次有[單擊],則為[8擊]
{
// key_return = EIGHT_KEY; // 返回 有效按鍵:[8擊]
// key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
key_time1 = 0;
key_state1 = KEY_STATE_8; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
else // 有[7擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內(nèi),沒(méi)有[8擊],則判定為 [7擊]
{
key_time1++; // 計(jì)數(shù) 時(shí)間間隔
if(key_time1 >= KEY_INTERVAL) // 超過(guò) 時(shí)間間隔
{
key_return = SEVEN_KEY; // 返回 有效按鍵:[7擊]
key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
}
break;
case KEY_STATE_8: // 按鍵狀態(tài)7:判定是否有[8擊]
if (key_temp == S_KEY) // 有[8擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內(nèi),再次有[單擊],則為[9擊]
{
// key_return = NINE_KEY; // 返回 有效按鍵:[9擊]
// key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
key_time1 = 0;
key_state1 = KEY_STATE_9; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
else // 有[8擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內(nèi),沒(méi)有[9擊],則判定為 [8擊]
{
key_time1++; // 計(jì)數(shù) 時(shí)間間隔
if(key_time1 >= KEY_INTERVAL) // 超過(guò) 時(shí)間間隔
{
key_return = EIGHT_KEY; // 返回 有效按鍵:[8擊]
key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
}
break;
case KEY_STATE_9: // 按鍵狀態(tài)7:判定是否有[9擊]
if (key_temp == S_KEY) // 有[9擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內(nèi),再次有[單擊],則為[9擊]
{
key_return = TEN_KEY; // 返回 有效按鍵:[10擊]
key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
else // 有[9擊]后,如果在 設(shè)定的時(shí)間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內(nèi),沒(méi)有[10擊],則判定為 [9擊]
{
key_time1++; // 計(jì)數(shù) 時(shí)間間隔
if(key_time1 >= KEY_INTERVAL) // 超過(guò) 時(shí)間間隔
{
key_return = NINE_KEY; // 返回 有效按鍵:[9擊]
key_state1 = KEY_STATE_0; // 返回 按鍵狀態(tài)0,等待新的有效按鍵
}
}
break;
//=============================================================================================
default: // 特殊情況:key_state是其他值得情況,清零key_state。這種情況一般出現(xiàn)在 沒(méi)有初始化key_state,第一次執(zhí)行這個(gè)函數(shù)的時(shí)候
key_state1 = KEY_STATE_0;
break;
}
return key_return; // 返回 按鍵值
}
// =========================== main.c ======================
#include "reg51.h"
#include "key.c"
#define FOSC 11059200L
#define T1MS (65536-FOSC/12/100) //1ms timer calculation method in 12T mode
sbit LED1 = P2^0; // 定義LEDIO口
sbit LED2 = P2^1;
sbit LED3 = P2^2; // 定義LEDIO口
sbit LED4 = P2^3;
sbit LED5 = P2^4; // 定義LEDIO口
sbit LED6 = P2^5;
sbit LED7 = P2^6;
sbit LED8 = P2^7;
unsigned char g_u8_KeyValue; // 按鍵值
unsigned char g_flag_10ms_key; // 10ms 計(jì)時(shí)標(biāo)志
unsigned char key_read(); // 聲明讀取按鍵函數(shù)
void T0_Init_10ms(void) // timer0,初始化函數(shù) ,定時(shí)時(shí)間為 10ms
{
TMOD = 0x01; //set timer0 as mode1 (16-bit)
TL0 = T1MS; //initial timer0 low byte
TH0 = T1MS >> 8; //initial timer0 high byte
TR0 = 1; //timer0 start running
ET0 = 1; //enable timer0 interrupt
EA = 1;
}
// 主函數(shù)
void main(void)
{
// P1^2=1; // P1.0 拉高
T0_Init_10ms(); // 定時(shí)器0,初始化,定時(shí)10ms
while(1)
{
if(g_flag_10ms_key) // 等待10ms,定時(shí)完成
{
g_flag_10ms_key = 0; // 清零10ms定時(shí)標(biāo)志
g_u8_KeyValue = key_read(); // 讀取按鍵值
switch(g_u8_KeyValue)
{
case S_KEY: LED1=0;LED2=1;LED3=1;LED4=1;LED5=1;LED6=1;LED7=1;LED8=1; break; // 單擊 點(diǎn)亮LED1
case D_KEY: LED1=1;LED2=0;LED3=1;LED4=1;LED5=1;LED6=1;LED7=1;LED8=1; break; // 雙擊
case T_KEY: LED1=1;LED2=1;LED3=0;LED4=1;LED5=1;LED6=1;LED7=1;LED8=1; break; // 三擊
case F_KEY: LED1=1;LED2=1;LED3=1;LED4=0;LED5=1;LED6=1;LED7=1;LED8=1; break; // 四擊
case FIVE_KEY: LED1=1;LED2=1;LED3=1; LED4=1; LED5=0;LED6=1;LED7=1;LED8=1;break; //五擊
case SIX_KEY: LED1=1;LED2=1;LED3=1; LED4=1; LED5=1;LED6=0;LED7=1;LED8=1;break; //六擊
case SEVEN_KEY: LED1=1;LED2=1;LED3=1; LED4=1; LED5=1;LED6=1;LED7=0;LED8=1;break; //7擊
case EIGHT_KEY: LED1=1;LED2=1;LED3=1; LED4=1; LED5=1;LED6=1;LED7=1;LED8=0;break; //8擊
case NINE_KEY: LED1=0;LED2=0;LED3=0; LED4=0; LED5=1;LED6=1;LED7=1;LED8=1;break; //9擊
case TEN_KEY: LED1=1;LED2=1;LED3=1; LED4=1; LED5=0;LED6=0;LED7=0;LED8=0;break; //10擊
case L_KEY: LED1=1;LED2=1;LED3=1; LED4=1; LED5=1;LED6=1;LED7=1;break; // 長(zhǎng)按 熄滅所有LED
}
}
}
}
// timer0 中斷服務(wù)程序
void IRQ_T0(void) interrupt 1
{
TL0 = T1MS; //reload timer0 low byte
TH0 = T1MS >> 8; //reload timer0 high byte
g_flag_10ms_key = 1; // 置位 10ms 定時(shí)標(biāo)志
}
仿真程序:
按鍵單擊多擊長(zhǎng)按掃描演示 -狀態(tài)機(jī).7z
(135.29 KB, 下載次數(shù): 54)
2023-12-20 13:27 上傳
點(diǎn)擊文件名下載附件
按鍵
|
評(píng)分
-
查看全部評(píng)分
|