|
本帖更新內(nèi)容詳見(jiàn):http://www.torrancerestoration.com/bbs/dpj-176186-1.html
#define BaseTime 10 //時(shí)間基準(zhǔn)10 ms ,如果設(shè)計(jì)的時(shí)基是5ms 則前面的10就用該變成5
#define number_init 0xfffffffd // 初始化相關(guān)的utime(unsigned long)變量(如果是unsigned int 就應(yīng)該是0xfffd),采用這個(gè)值的好處是,即使發(fā)生時(shí)鐘計(jì)數(shù)器溢出,也不影響其他的程序
typedef unsigned long utime; //這個(gè)類型是為了方便移植專門給時(shí)間相關(guān)變量使用
typedef unsigned long ulong;
typedef unsigned int uint;
typedef unsigned char uchar;
enum ButtonModel{noneClick=0,singalClick,doubleClick,repeatClick,longPress}; //doubleClick目前未定義完整動(dòng)作 pressDownHold,按下保持
enum ButtonStaus{nonePress=1,pressDown,pressUp,pressDownHold}; /
struct button
{
uchar outPutEn:1; //發(fā)送數(shù)據(jù)使能
uchar lastButton:1; //按鍵上次變動(dòng)后的狀態(tài) 默認(rèn) 1
uchar init_leavel:1; //設(shè)置默認(rèn)按鍵電平
uchar longPressFlag:1; //長(zhǎng)按釋放標(biāo)志 默認(rèn)0,一旦開(kāi)始長(zhǎng)按則置1
uchar Gpio_level :3;
uchar applyUseOpenMaxPwm:1; //在關(guān)機(jī)狀態(tài)下,若本按鍵按下啟動(dòng)了系統(tǒng),則需要申請(qǐng)全局變量標(biāo)明,禁止其他按鍵關(guān)閉被本按鍵打開(kāi)的系統(tǒng)(自己打開(kāi)自己負(fù)責(zé)關(guān)閉)
uchar ticks; //按鍵按下次數(shù)
enum ButtonStaus lastButtonStaus; //按鍵上個(gè)循環(huán)的狀態(tài)
enum ButtonStaus thisButtonStaus; //按鍵本循環(huán)的狀態(tài)
enum ButtonModel lastButtonModel; //按鍵上個(gè)循環(huán)所處的模式
enum ButtonModel thisButtonModel; //按鍵本循環(huán)應(yīng)該所處的模式
uint changeModelTime; //10ms基準(zhǔn) //長(zhǎng)按時(shí)間定義
uint pressLongTime; //10ms基準(zhǔn) //多擊時(shí)間定義
utime lastPressDownMoment; //上次按鍵按下所處的時(shí)刻
utime thisPressDownMoment; //本次按鍵按下所處的時(shí)刻
uint tempTime; //緩存按鍵兩次按下之間的時(shí)長(zhǎng)
utime buttonConfir; //按鍵防抖時(shí)長(zhǎng)
utime getTimer; //獲取時(shí)鐘精準(zhǔn)時(shí)刻,用于設(shè)定按鍵掃描周期
utime acquisitionMoment; //獲取時(shí)鐘精準(zhǔn)時(shí)刻,用于記錄相同按鍵狀態(tài)持續(xù)時(shí)長(zhǎng)
uchar (*read_gpio)(void); //獲取按鍵狀態(tài)方法
};
/*================================
outPutEn 是為后面接收按鍵是單擊、多擊長(zhǎng)按函數(shù)準(zhǔn)備的參數(shù)。比如按鍵掃描程序10ms運(yùn)行一次,輸出的是單擊,如果沒(méi)有outPutEn這個(gè)參數(shù),后面的接收程序會(huì)在10ms內(nèi)一直都接收的是單擊指令,這樣就會(huì)一直執(zhí)行單擊需要進(jìn)行的操作,本來(lái)單擊一次檔位變化1,結(jié)果現(xiàn)在檔位變化了n
applyUseOpenMaxPwm 是為多按鍵且按鍵操作有優(yōu)先權(quán)做準(zhǔn)備,,有優(yōu)先權(quán)的操作不會(huì)被其他按鍵操作打斷
===============================*/
struct button button1,button2,button3;
void Scan_key(struct button *Key,utime timer ,uint enOutTime ,uint noiseProofTime)
{
enOutTime/=BaseTime;
noiseProofTime/=BaseTime;
if(number_init==Key->getTimer) //如果是第一次運(yùn)行,則更新時(shí)間
{
Key->getTimer=timer;
}
else
{
if(timer-Key->getTimer>=enOutTime) //如果時(shí)間足夠“定義的循環(huán)時(shí)間” ,則更新時(shí)間并允許運(yùn)行
{
Key->getTimer=timer;
Key->Gpio_level=Key->read_gpio();
if(Key->Gpio_level>1);
else
{
if(Key->lastButton^Key->Gpio_level)//按鍵有電平變化模塊處理開(kāi)始----------------------------------------------------------------------------//
{
if(number_init==Key->buttonConfir)
Key->buttonConfir=timer;
if(timer-Key->buttonConfir>=noiseProofTime)//按鍵防抖,必須再確認(rèn)狀態(tài)
{
Key->lastButton=Key->Gpio_level;
Key->acquisitionMoment=number_init;
Key->buttonConfir=number_init; //二次確認(rèn)標(biāo)志重置
if(Key->init_leavel^Key->Gpio_level)//本次按鍵狀態(tài)改變后與定義的電平不一致模塊處理開(kāi)始
{
switch(Key->lastButtonStaus)
{
case nonePress: //上個(gè)循環(huán)是定義的初始電平
case pressUp:
{
if(number_init==Key->lastPressDownMoment)//是第一次記錄按鍵按下時(shí)刻
{
Key->thisPressDownMoment=Key->lastPressDownMoment=timer;
}
else //不第一次記錄
{
Key->thisPressDownMoment=timer;
Key->tempTime+=Key->thisPressDownMoment-Key->lastPressDownMoment; //獲取兩次按鍵按下之間的時(shí)間間隔
Key->lastPressDownMoment=Key->thisPressDownMoment; //更新
}
Key->ticks++;
//不在此處增加pressLongTime判斷的原因是,buftime0記錄的是兩次按鍵按下之間的時(shí)長(zhǎng),在兩次按下之間必有彈起,一旦彈起,pressLongTime 就置零
switch(Key->ticks)
{
case 1:
{
if(Key->tempTime>=Key->changeModelTime)//ticks未初始化。
{
Key->ticks=0;
Key->tempTime=0;
}
Key->thisButtonModel=singalClick;
break;
}
case 2:
{
if(Key->tempTime<Key->changeModelTime)//ticks未初始化
Key->thisButtonModel=doubleClick;
else
{
Key->thisButtonModel=singalClick;
Key->ticks=0;
Key->tempTime=0;
}
break;
}
case 3: //三擊,想要增加N擊自己在后面添加 CASE 4,CASE 5,CASE N
{
if(Key->tempTime<Key->changeModelTime)//第三擊的時(shí)間也小于定義的改變模式時(shí)間
{
Key->thisButtonModel=repeatClick;
}
else //第三擊的時(shí)間大于定義的改變模式時(shí)間
{
Key->thisButtonModel=singalClick;
}
Key->ticks=0;
Key->tempTime=0;
Key->thisPressDownMoment=Key->lastPressDownMoment=number_init;
break;
}
default :
{
Key->ticks=0;
Key->thisButtonModel=noneClick;
}
}
Key->thisButtonStaus=pressDown; //按鍵按下
break;
}
}
} //按鍵狀態(tài)改變后是與定義的電平模塊不同處理結(jié)束//
///////////////////////////////////////////////////////////////////////////
else //按鍵狀態(tài)改變與定義的電平模塊相同開(kāi)始處理//
{
Key->longPressFlag=0;
switch(Key->lastButtonStaus)
{
case pressDown://上個(gè)循環(huán)是低電平,機(jī)器人手速
case pressDownHold:
{
if(Key->tempTime>=Key->changeModelTime)
{
Key->tempTime=0;
Key->ticks=0;
}
Key->thisButtonStaus=pressUp; //按鍵彈起
Key->thisButtonModel=noneClick;
break;
}
}
}//本次按鍵狀態(tài)改變后是定義的電平處理結(jié)束//
}
}//按鍵有電平變化模塊處理結(jié)束-------------------------------------------------------------------------------------------------------//
else if(Key->init_leavel==Key->Gpio_level)//按鍵無(wú)改變且是初始電平處理開(kāi)始//
{
if(number_init==Key->acquisitionMoment)
{
Key->acquisitionMoment=timer;
}
if(timer-Key->acquisitionMoment>Key->pressLongTime||timer-Key->acquisitionMoment>Key->changeModelTime||Key->tempTime>=Key->pressLongTime||Key->tempTime>=Key->changeModelTime)
{
Key->ticks=0;
Key->tempTime=0; //tempTime 一旦置零,記錄按鍵按下時(shí)刻的值都應(yīng)當(dāng)重置
Key->thisPressDownMoment=Key->lastPressDownMoment=number_init;
}
if(timer-Key->acquisitionMoment>259200000)//一個(gè)月都沒(méi)有使用了,所以清零
{
Open_timer0; //重置timer0 防止一年后溢出
}
switch(Key->lastButtonStaus)
{
case nonePress:
case pressUp:
{
Key->thisButtonStaus=nonePress;
Key->thisButtonModel=noneClick;
break;
}
/*
case pressDown:
case pressDownHold: //容錯(cuò)處理,理論上若上個(gè)循環(huán)與本循環(huán)電平不一致,應(yīng)該在電平有變化模塊處理不會(huì)在本模塊
{
Key->thisButtonStaus=pressUp;
if(Key->tempTime+1>=Key->pressLongTime)
{
Key->thisButtonModel=longPress;
}
else
{
Key->thisButtonModel=noneClick;
}
Key->tempTime=0;
Key->thisPressDownMoment=Key->lastPressDownMoment=number_init;
break;
}
*/
}
}//按鍵狀態(tài)無(wú)改變且是初始電平處理結(jié)束//
else//按鍵狀態(tài)無(wú)改變且是非初始電平處理開(kāi)始//
{
if(number_init==Key->acquisitionMoment)
{
Key->acquisitionMoment=timer;
}
switch(Key->lastButtonStaus)
{
/*
case nonePress: //容錯(cuò)處理,理論上若上個(gè)循環(huán)與本循環(huán)電平不一致,應(yīng)該在電平有變化模塊處理不會(huì)在本模塊
case pressUp:
{
if(longPress==Key->lastButtonModel)
{
Key->thisButtonStaus=nonePress;
Key->thisButtonModel=noneClick;
}
else
{
if(timer-Key->acquisitionMoment>Key->pressLongTime||Key->tempTime>=Key->pressLongTime)
{
Key->thisButtonModel=longPress;
Key->lastPressDownMoment=Key->thisPressDownMoment=number_init; //一但超時(shí),所謂的記錄按鍵按下時(shí)間間隔就無(wú)意義,必須重置
Key->tempTime=0; //按鍵鍵緩沖時(shí)間不清零,對(duì)操作體驗(yàn)影響很不好
Key->ticks=0;
}
else
{
Key->thisButtonModel=singalClick;
}
Key->thisButtonStaus=pressDown;
}
}
*/
case pressDown:
case pressDownHold:
{
if(longPress==Key->lastButtonModel||Key->longPressFlag)
{
Key->thisButtonModel=noneClick; // 改變了模式,下個(gè)循環(huán)程序進(jìn)入其它分支,所以必須在上面加入模式判斷
Key->thisButtonStaus=pressDownHold;
Key->acquisitionMoment=timer;
Key->lastPressDownMoment=Key->thisPressDownMoment=timer; //PressDownMoment必須在按鍵按下保持狀態(tài)下更新時(shí)間,否則tempTime會(huì)計(jì)算總的按鍵時(shí)長(zhǎng),以至于無(wú)法進(jìn)入repeat模式
}
else
{
if(timer-Key->acquisitionMoment>Key->pressLongTime)
{
Key->longPressFlag=1;
Key->thisButtonModel=longPress;
Key->tempTime=0;
Key->ticks=0;
Key->thisPressDownMoment=Key->lastPressDownMoment=Key->acquisitionMoment=number_init;
}
else
{
Key->thisButtonModel=noneClick;
}
Key->thisButtonStaus=pressDownHold;
}
break;
}
}
}
Key->lastButtonStaus=Key->thisButtonStaus; //最后更新
Key->lastButtonModel=Key->thisButtonModel;
Key->outPutEn=1;
}
}
}
}
/*============================
void Scan_key(struct button *Key,utime timer ,uint enOutTime ,uint noiseProofTime) 中,timer 是授時(shí)系統(tǒng),比如每10ms加一位,enOutTime 是循環(huán)檢測(cè)時(shí)間,比如允許每50ms建成運(yùn)行一次,noiseProofTime是按鍵防抖動(dòng)時(shí)間,程序運(yùn)行后檢測(cè)按鍵的thisButtonModel狀態(tài)就能知道是單擊雙擊多擊還是長(zhǎng)按。目前在函數(shù)中定義了單擊到三擊,三擊以上可自己添加
================================*/
|
評(píng)分
-
查看全部評(píng)分
|