亚洲春色中文字幕久久久-三上亚,一吻二脱三床四吻胸,国产真实伦对白视频全集,在线毛片观看,精品成品入口黄网,国产毛aⅴ片久久久,亚洲AV色香蕉一区二区三区老师,萧皇后A级艳片,色情日本视频更新,99久久亚洲精品日本无码

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 1731|回復(fù): 3
打印 上一主題 下一主題
收起左側(cè)

51單片機通用的按鍵長按單擊雙擊單擊讀寫方式

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:1155837 發(fā)表于 2025-7-3 15:10 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
本代碼參考了https://blog.csdn.net/m0_52596850/article/details/126776765#,在原代碼的基礎(chǔ)上按我的代碼風(fēng)格重寫了,添加了三擊功能。
具體原理在注釋中已經(jīng)給出,通讀一遍便能理解,簡單的概括就是通過switch在各種不同的狀態(tài)之間切換實現(xiàn)按鍵的消抖,長短按識別,相當(dāng)?shù)那擅。其中消抖直接使用了定時器中斷的間隔進(jìn)行消抖,我認(rèn)為這是這個方案最巧思的一點。
如果要復(fù)用,直接根據(jù)你的按鍵IO口改變第一行的keyinput就行了,其他的不需要改變,然后在主循環(huán)中或者定時器中斷調(diào)用就可以了。目前為P32低電平為有效按鍵輸入,如有需求可以改為高電平。
#define KEYINPUT P32//按鍵輸入為P32
#define NOKEY 0//無
#define SINGLEKEY 1//單鍵
#define DOUBLEKEY 2//雙鍵
#define TRIPLEKEY 3//三鍵
#define LONGKEY 4//長鍵
#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),用定時器中斷間隔實現(xiàn)消抖
            if(!keypress){//P32==0
                keystate = KEYSTATE1;//如果無按鍵按下就始終返回為NOKEY
            }
            break;
        case KEYSTATE1:
            if(!keypress){//P32==0
                keytime = 0;
                keystate = KEYSTATE2;}//按鍵仍然處于按下,消抖完成,狀態(tài)轉(zhuǎn)換到計時
            else{
                keystate = KEYSTATE0;//低電平持續(xù)時間過小,只有一個定時器間隔
            }                        //認(rèn)為是無效按鍵,清零狀態(tài),實現(xiàn)消抖
            break;
        case KEYSTATE2:
            if(keypress){//P32==1,按鍵釋放,且間隔2個定時器中斷,認(rèn)為是無抖動的按鍵輸入。
                keyreturn = SINGLEKEY;//返回單擊
                keystate = KEYSTATE0;//清空狀態(tài)
            }
            else if(++keytime >= 64){//P32=0,繼續(xù)按下,計時加一個定時器中斷間隔時間,
                keyreturn = LONGKEY;//在下次定時器中斷直接輸出為長按,不需要等待
                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;//多次按鍵計數(shù)器
    unsigned char keyreturn = NOKEY;
    unsigned char keytemp;
    keytemp = KEY_DRIVER();//讀取按鍵狀態(tài)
    switch(key1){
        case KEYSTATE0:
            if(keytemp == SINGLEKEY){
                keytime1 = 0;//第一次單擊,無返回值,到下個狀態(tài)判斷之后是否有再次單擊
                key1 = KEYSTATE1;//切換單擊
            }
            else{
                keyreturn = keytemp;//對于無鍵,長按時間返回原事件
            }
            break;
        case KEYSTATE1:
            if(keytemp == SINGLEKEY){//再次單擊,間隔小于640ms
                key1 = KEYSTATE2;//切換到狀態(tài)3,等待三擊
            }//不清空計數(shù)器,因為要實現(xiàn)總間隔檢測
            else{
                if(++keytime1 >= 32){//在這里實現(xiàn)等待雙擊
                    keyreturn = SINGLEKEY;//返回單擊
                    key1 = KEYSTATE0;//清空狀態(tài)
                }
            }
            break;
        case KEYSTATE2:
            if(keytemp == SINGLEKEY){//第三次單擊,總間隔小于640ms,沿用state1中的計數(shù)器
                keyreturn = TRIPLEKEY;//輸出為三擊
                key1 = KEYSTATE0;//返回初始狀態(tài)
            }
            else{
                if(++keytime1 >= 32){//沿用之前的計數(shù)器值,繼續(xù)計數(shù)
                    keyreturn = DOUBLEKEY;//超時,輸出雙擊
                    key1 = KEYSTATE0;
                }
            }
        }
    return keyreturn;
    }

下面是測試代碼及調(diào)用功能示范,長按帶點亮led,三擊熄滅led,可以用于測試功能,需要手動
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;//打開定時器電源
    while(1){
        if(timer20msok){
            timer20msok = 0;
            keyevent = KEY_READ();
            if(keyevent == LONGKEY){
                P30 = 0;
            }
            else if(keyevent == TRIPLEKEY)
                P30 = 1;
        }
    }
}

評分

參與人數(shù) 1黑幣 +30 收起 理由
wpppmlah + 30 共享資料的獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏4 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:63317 發(fā)表于 2025-7-4 06:22 | 只看該作者
謝謝分享資料
回復(fù)

使用道具 舉報

板凳
ID:1064915 發(fā)表于 2025-7-4 10:08 | 只看該作者

回復(fù)

使用道具 舉報

地板
ID:1155837 發(fā)表于 2025-7-4 12:50 | 只看該作者
我試了幾次,似乎不能在定時器中斷中直接調(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)時鐘/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;//允許按鍵檢測
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時再減1...好吧這是無符號字符,不會小于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;
            }

        }
/////////////////////定時器中斷
void TM0_ROUTINE(void) interrupt 1{//timer0中斷服務(wù)函數(shù),20ms一次
    keydet = 1;
   }

回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表