久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费
標(biāo)題:
51單片機(jī)通用的按鍵長(zhǎng)按單擊雙擊單擊讀寫方式
[打印本頁]
作者:
千早愛音愛玩51
時(shí)間:
2025-7-3 15:10
標(biāo)題:
51單片機(jī)通用的按鍵長(zhǎng)按單擊雙擊單擊讀寫方式
本代碼參考了
https://blog.csdn.net/m0_52596850/article/details/126776765#
,在原代碼的基礎(chǔ)上按我的代碼風(fēng)格重寫了,添加了三擊功能。
具體原理在注釋中已經(jīng)給出,通讀一遍便能理解,簡(jiǎn)單的概括就是通過switch在各種不同的狀態(tài)之間切換實(shí)現(xiàn)按鍵的消抖,長(zhǎng)短按識(shí)別,相當(dāng)?shù)那擅睢F渲邢吨苯邮褂昧硕〞r(shí)器中斷的間隔進(jìn)行消抖,我認(rèn)為這是這個(gè)方案最巧思的一點(diǎn)。
如果要復(fù)用,直接根據(jù)你的按鍵IO口改變第一行的keyinput就行了,其他的不需要改變,然后在主循環(huán)中或者定時(shí)器中斷調(diào)用就可以了。目前為P32低電平為有效按鍵輸入,如有需求可以改為高電平。
#define KEYINPUT P32//按鍵輸入為P32
#define NOKEY 0//無
#define SINGLEKEY 1//單鍵
#define DOUBLEKEY 2//雙鍵
#define TRIPLEKEY 3//三鍵
#define LONGKEY 4//長(zhǎng)鍵
#define KEYSTATE0 0
#define KEYSTATE1 1
#define KEYSTATE2 2
#define KEYSTATE3 3
unsigned char KEY_DRIVER(void){
static unsigned char keystate = KEYSTATE0;
static unsigned char keytime = 0;
unsigned char keypress;
unsigned char keyreturn = NOKEY;
keypress = KEYINPUT;//讀取P32電平
switch(keystate){
case KEYSTATE0://按鍵初始狀態(tài),按下后轉(zhuǎn)換到消抖與確認(rèn)態(tài),用定時(shí)器中斷間隔實(shí)現(xiàn)消抖
if(!keypress){//P32==0
keystate = KEYSTATE1;//如果無按鍵按下就始終返回為NOKEY
}
break;
case KEYSTATE1:
if(!keypress){//P32==0
keytime = 0;
keystate = KEYSTATE2;}//按鍵仍然處于按下,消抖完成,狀態(tài)轉(zhuǎn)換到計(jì)時(shí)
else{
keystate = KEYSTATE0;//低電平持續(xù)時(shí)間過小,只有一個(gè)定時(shí)器間隔
} //認(rèn)為是無效按鍵,清零狀態(tài),實(shí)現(xiàn)消抖
break;
case KEYSTATE2:
if(keypress){//P32==1,按鍵釋放,且間隔2個(gè)定時(shí)器中斷,認(rèn)為是無抖動(dòng)的按鍵輸入。
keyreturn = SINGLEKEY;//返回單擊
keystate = KEYSTATE0;//清空狀態(tài)
}
else if(++keytime >= 64){//P32=0,繼續(xù)按下,計(jì)時(shí)加一個(gè)定時(shí)器中斷間隔時(shí)間,
keyreturn = LONGKEY;//在下次定時(shí)器中斷直接輸出為長(zhǎng)按,不需要等待
keystate = KEYSTATE3;//進(jìn)入狀態(tài)3,等待按鍵釋放
}
break;
case KEYSTATE3://等待按鍵釋放,釋放后清空狀態(tài)
if(keypress){//P32==1,按鍵已經(jīng)抬起
keystate = KEYSTATE0;//清空狀態(tài)
}
break;
}
return keyreturn;
}
//////////////////////////////////////////////////
unsigned char KEY_READ(void){
static unsigned char key1 = KEYSTATE0;
static unsigned char keytime1 = 0;//多次按鍵計(jì)數(shù)器
unsigned char keyreturn = NOKEY;
unsigned char keytemp;
keytemp = KEY_DRIVER();//讀取按鍵狀態(tài)
switch(key1){
case KEYSTATE0:
if(keytemp == SINGLEKEY){
keytime1 = 0;//第一次單擊,無返回值,到下個(gè)狀態(tài)判斷之后是否有再次單擊
key1 = KEYSTATE1;//切換單擊
}
else{
keyreturn = keytemp;//對(duì)于無鍵,長(zhǎng)按時(shí)間返回原事件
}
break;
case KEYSTATE1:
if(keytemp == SINGLEKEY){//再次單擊,間隔小于640ms
key1 = KEYSTATE2;//切換到狀態(tài)3,等待三擊
}//不清空計(jì)數(shù)器,因?yàn)橐獙?shí)現(xiàn)總間隔檢測(cè)
else{
if(++keytime1 >= 32){//在這里實(shí)現(xiàn)等待雙擊
keyreturn = SINGLEKEY;//返回單擊
key1 = KEYSTATE0;//清空狀態(tài)
}
}
break;
case KEYSTATE2:
if(keytemp == SINGLEKEY){//第三次單擊,總間隔小于640ms,沿用state1中的計(jì)數(shù)器
keyreturn = TRIPLEKEY;//輸出為三擊
key1 = KEYSTATE0;//返回初始狀態(tài)
}
else{
if(++keytime1 >= 32){//沿用之前的計(jì)數(shù)器值,繼續(xù)計(jì)數(shù)
keyreturn = DOUBLEKEY;//超時(shí),輸出雙擊
key1 = KEYSTATE0;
}
}
}
return keyreturn;
}
下面是測(cè)試代碼及調(diào)用功能示范,長(zhǎng)按帶點(diǎn)亮led,三擊熄滅led,可以用于測(cè)試功能,需要手動(dòng)
bit timer20msok = 0;
void TIMER0_ROUTINE(void) interrupt 1{
timer20msok = 1;
}
unsigned char keyevent = NOKEY;
void main(void){
TH0 = 0XD8;
TL0 = 0XF0;
IE = 0X8F;//允許中斷
TR0 = 1;//打開定時(shí)器電源
while(1){
if(timer20msok){
timer20msok = 0;
keyevent = KEY_READ();
if(keyevent == LONGKEY){
P30 = 0;
}
else if(keyevent == TRIPLEKEY)
P30 = 1;
}
}
}
作者:
WFX777888
時(shí)間:
2025-7-4 06:22
謝謝分享資料
作者:
joyb
時(shí)間:
2025-7-4 10:08
51hei.jpg
(40 KB, 下載次數(shù): 0)
下載附件
2025-7-8 19:12 上傳
作者:
千早愛音愛玩51
時(shí)間:
2025-7-4 12:50
我試了幾次,似乎不能在定時(shí)器中斷中直接調(diào)用,可能是異步執(zhí)行的問題吧,下面是一段調(diào)用該按鍵程序的參考代碼,可以參考。
////////////////PCA///////////////////////////////////
// PWM占空比值數(shù)組 (0x00=100%, 0x40=0%)
// 從最小值開始
const unsigned char ccapvalues[] = {0x38, 0x33, 0x2E, 0x25, 0x20, 0x16, 0x10, 0x00};
unsigned char ccapcounter = 0;//全局變量
void PCA_CONFIG(void){
P_SW1 = 0x10; // P3.1切換為PWM輸出
CCON = 0x00; // 復(fù)位PCA
CMOD = 0x0A; // 系統(tǒng)時(shí)鐘/4,6MHZ下為23.5khz
CL = 0x00; // 復(fù)位低字節(jié)
CH = 0x00; // 復(fù)位高字節(jié)
CCAPM0 = 0x42; // PCA0 PWM模式
PCA_PWM0 = 0x80;// 6位PWM模式
CCAP0H = ccapvalues[ccapcounter];//在喚醒后讀取ram中的ccapcounter值
CR = 1; //初始化不開啟電源
}
///////////////////////按鍵上層處理
bit keydet = 0;//允許按鍵檢測(cè)
unsigned char keyevent = NOKEY;//初始化為0
void KEY_HANDLER(void){
keyevent = KEY_READ();//調(diào)用按鍵讀取函數(shù)
switch(keyevent){
case LONGKEY:
poweron ^= 1;
break;
case SINGLEKEY:
if(poweron && ledmode<=2){
if(ccapcounter <= 7) ccapcounter++;//如果小于7就增加,等于7后不再增加
}
else if(poweron && ledmode>2){
if(ccapcounter <= 5) ccapcounter++;
}
break;
case DOUBLEKEY:
if(poweron && ledmode<=2){
if(ccapcounter > 0) ccapcounter--;//如果大于0就減小,等于0后不再減小
}
else if(poweron && ledmode>2){//不能寫成>=0,否則當(dāng)為0時(shí)再減1...好吧這是無符號(hào)字符,不會(huì)小于0
if(ccapcounter > 0) ccapcounter--;
}
break;
case TRIPLEKEY:
switch(ledmode){
case 0:
case 1:
case 2:
if(ccapcounter == 7){
ccapcounter = 0;
}
else{
ccapcounter = 7;
}
break;
case 3:
case 4:
case 5:
if(ccapcounter == 5){
ccapcounter = 0;
}
else{
ccapcounter =5;
}
}
break;
}
}
/////////////////////定時(shí)器中斷
void TM0_ROUTINE(void) interrupt 1{//timer0中斷服務(wù)函數(shù),20ms一次
keydet = 1;
}
歡迎光臨 (http://m.zg4o1577.cn/bbs/)
Powered by Discuz! X3.1
主站蜘蛛池模板:
久久机热这里只有精品
|
国产超碰在线观看
|
在线免费观看日韩av
|
成人免费视屏
|
视频一区二区在线播放
|
欧美日韩免费视频
|
国产色视频一区二区三区qq号
|
午夜在线视频观看
|
久久久久免费
|
日韩和的一区二区
|
法国极品成人h版
|
成人短视频在线观看
|
欧美日韩国产精品
|
中国农村毛片免费播放
|
天天干天天做
|
毛片视频免费观看
|
日韩在线免费播放
|
欧美精品久久99
|
中文字幕综合
|
午夜在线影院
|
国产成人一区
|
日韩精品免费在线观看
|
久久国产精品免费视频
|
五月婷婷激情综合
|
日本精品在线视频
|
wwwxxx欧美
|
久热国产精品
|
中文字幕偷拍
|
色黄视频在线观看
|
国产第一页在线
|
精品免费
|
成年人免费视频网站
|
欧美激情免费
|
日本一级片在线观看
|
欧美精品日韩少妇
|
欧美一级色
|
国产超碰在线观看
|
欧美成人精品
|
又黄又爽又色视频
|
精品国产99久久久久久宅男i
|
男人的天堂在线视频
|