久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2426|回復: 4
收起左側

單片機狀態機按鍵程序怎么能響應兩個不同時長的長按?

[復制鏈接]
ID:91521 發表于 2019-10-25 18:25 | 顯示全部樓層 |閱讀模式
我在學習狀態機按鍵程序時遇到一個問題:我用狀態機按鍵方法,只能實現一個長按事件的響應。如果要能夠響應兩個不同時長的長按,程序該怎么修改呢?我試著修改了一下,可是不成功,百思不得其解,只好請各位高人指點迷津!

單片機程序如下(紅色部分是我自己修改的):

#include<reg52.h>

sbit LED0 = P0^7;
sbit LED1 = P0^6;
sbit LED2 = P0^5;
sbit LED3 = P0^4;

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

sbit KEY_INPUT = P2^4;    //  按鍵IO

#define KEY_STATE_0         0       //  按鍵狀態
#define KEY_STATE_1         1
#define KEY_STATE_2         2
#define KEY_STATE_3         3
#define KEY_STATE_4         4

#define SINGLE_KEY_TIME     3       //  SINGLE_KEY_TIME*10MS = 30MS     判定單擊的時間長度,軟件消抖
#define KEY_INTERVAL        30      //  KEY_INTERVAL*10MS    = 300MS 判定雙擊的時間間隔
#define LONG_KEY_TIME       300     //  LONG_KEY_TIME*10MS   = 3S   判定長按的時間長度


#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 L_KEY               10      //  long press

unsigned char g_u8_KeyValue;        // 按鍵值

// ----------------------------------- 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;                      //  讀取當前鍵值

    switch (key_state)     
    {      
        case KEY_STATE_0:                       //  按鍵狀態0:判斷有無按鍵按下
            if (!key_press)                     //  有按鍵按下
            {
                key_time = 0;                   //  清零時間間隔計數
                key_state = KEY_STATE_1;        //  然后進入 按鍵狀態1
            }        
            break;

        case KEY_STATE_1:                       //  按鍵狀態1:軟件消抖(確定按鍵是否有效,而不是誤觸)。按鍵有效的定義:按鍵持續按下超過設定的消抖時間。
            if (!key_press)                     
            {
                key_time++;                     //  一次10ms
                if(key_time>=SINGLE_KEY_TIME)   //  消抖時間為:SINGLE_KEY_TIME*10ms = 30ms;
                {
                    key_state = KEY_STATE_2;    //  如果按鍵時間超過 消抖時間,即判定為按下的按鍵有效。按鍵有效包括兩種:單擊或者長按,進入 按鍵狀態2, 繼續判定到底是那種有效按鍵
                }
            }         
            else key_state = KEY_STATE_0;       //  如果按鍵時間沒有超過,判定為誤觸,按鍵無效,返回 按鍵狀態0,繼續等待按鍵
            break;

        case KEY_STATE_2:                       //  按鍵狀態2:判定按鍵有效的種類:是單擊,還是長按
            if(key_press)                       //  如果按鍵在 設定的長按時間 內釋放,則判定為單擊
            {
                 key_return = S_KEY;            //  返回 有效按鍵值:單擊
                 key_state = KEY_STATE_0;       //  返回 按鍵狀態0,繼續等待按鍵
            }
            else
            {
                key_time++;                     

                if(key_time >= LONG_KEY_TIME)   //  如果按鍵時間超過 設定的長按時間(LONG_KEY_TIME*10ms=300*10ms=3000ms), 則判定為 長按
                {
                    key_return = L_KEY;         //  返回 有效鍵值值:長按
                    key_state = KEY_STATE_3;    //  去狀態3,等待按鍵釋放
                }
            }
            break;

      case KEY_STATE_3:    //我自己添加的代碼開始                     
            if(key_press)                       
            {
                 key_return = L_KEY;            
                 key_state = KEY_STATE_0;      
            }
            else
            {
                key_time++;                     

                if(key_time >= 600)   
                {
                    key_return = 5;         
                    key_state = KEY_STATE_4;   
                }
            }
            break;    //我自己添加的代碼結束


      case KEY_STATE_4:                         //  等待按鍵釋放
          if (key_press)
          {
              key_state = KEY_STATE_0;          //  按鍵釋放后,進入 按鍵狀態0 ,進行下一次按鍵的判定
          }        
          break;

        default:                                //  特殊情況:key_state是其他值得情況,清零key_state。這種情況一般出現在 沒有初始化key_state,第一次執行這個函數的時候
            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:                       //  按鍵狀態0:等待有效按鍵(通過 key_driver 返回的有效按鍵值)
            if (key_temp == S_KEY)          //  如果是[單擊],不馬上返回單擊按鍵值,先進入 按鍵狀態1,判斷是否有[雙擊]的可能
            {
                 key_time1 = 0;                 //  清零計時
                 key_state1 = KEY_STATE_1;
            }            
            else                                //  如果不是[單擊],直接返回按鍵值。這里的按鍵值可能是:[長按],[無效按鍵]
            {
                 key_return = key_temp;         //  返回 按鍵值
            }
            break;

        case KEY_STATE_1:                       //  按鍵狀態1:判定是否有[雙擊]
            if (key_temp == S_KEY)              //  有[單擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內,再次有[單擊],則為[雙擊],但是不馬上返回 有效按鍵值為[雙擊],先進入 按鍵狀態2,判斷是否有[三擊]
            {
                key_time1 = 0;                  //  清零 時間間隔
                key_state1 = KEY_STATE_2;       //  改變 按鍵狀態值
            }
            else                                //  有[單擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內,沒有[單擊]出現,則判定為 [單擊]
            {
                key_time1++;                    //  計數 時間間隔
                if(key_time1 >= KEY_INTERVAL)   //  超過 時間間隔
                 {
                    key_return = S_KEY;         //  返回 有效按鍵:[單擊]
                    key_state1 = KEY_STATE_0;   //  返回 按鍵狀態0,等待新的有效按鍵
                 }              
             }              
             break;

        case KEY_STATE_2:                       // 按鍵狀態2:判定是否有[三擊]
            if (key_temp == S_KEY)              // 有[雙擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內,再次有[單擊],則為[三擊],由于這里只擴展到[三擊],所以馬上返回 有效按鍵值為[三擊]
            {
                 key_return = T_KEY;            // 返回 有效按鍵:[三擊]
                 key_state1 = KEY_STATE_0;      // 返回 按鍵狀態0,等待新的有效按鍵
            }
            else                                // 有[雙擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內,沒有[單擊],則判定為 [雙擊]
            {
                key_time1++;                    // 計數 時間間隔
                if(key_time1 >= KEY_INTERVAL)   // 超過 時間間隔
                 {
                      key_return = D_KEY;       // 返回 有效按鍵:[雙擊]
                      key_state1 = KEY_STATE_0; // 返回 按鍵狀態0,等待新的有效按鍵
                 }              
             }              
             break;

        default:                                //  特殊情況:key_state是其他值得情況,清零key_state。這種情況一般出現在 沒有初始化key_state,第一次執行這個函數的時候
            key_state1 = KEY_STATE_0;
            break;
    }

    return key_return;                          // 返回 按鍵值
}

void main()
{
    ENLED = 0;
    ADDR3 = 1;
    ADDR2 = 1;
    ADDR1 = 1;
    ADDR0 = 0;

    P2 = 0xF7;

    TMOD = 0x01;
    TH0 = 0xDC;
    TL0 = 0x00;
    TR0 = 1;
     
    while(1)
    {
        if(TF0 == 1)                         // 等待10ms,定時完成
        {
            TF0 = 0;                    // 清零10ms定時標志
            TH0 = 0xDC;
            TL0 = 0x00;

            g_u8_KeyValue = key_read();             // 讀取按鍵值

            switch(g_u8_KeyValue)
            {
                case 5: LED1 = !LED1; break;    // 單擊 取反LED1
                case D_KEY: LED2 = !LED2; break;    // 雙擊 取反LED2
                case L_KEY: LED3 = !LED3; break;    // 三擊 取反LED3
//                case L_KEY: LED_ALL_ON(); break;    // 長按 點亮所有的LED
            }
        }
    }
}
回復

使用道具 舉報

ID:94031 發表于 2019-10-26 11:27 | 顯示全部樓層
用了定時0的中斷標志TF0,卻沒有初始化定時器0以及相應的中斷程序,說明沒有理解程序原理。
回復

使用道具 舉報

ID:405193 發表于 2019-10-26 22:09 | 顯示全部樓層
你case KEY_STATE_3不能依照 case KEY_STATE_2這樣復制下來,都有key_time++;    你應該在   case KEY_STATE_2里根據設置key_time  不同的時間來設置功能達到  case KEY_STATE_3的目的。  
回復

使用道具 舉報

ID:192020 發表于 2024-6-28 18:21 | 顯示全部樓層
應該是可以的,但是出現6秒長按時必然先出現一次3秒長按,這兩個沒做互斥。當響應3秒長按功能時別松手繼續按住看看能不能出現6秒的功能
回復

使用道具 舉報

ID:329625 發表于 2024-7-2 09:05 來自觸屏版 | 顯示全部樓層
不同時長后 判斷有無松手檢測 然后再判斷按鍵時長 你可以試試
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 国产女人与拘做受视频 | 亚洲精品久久国产高清情趣图文 | 自拍偷拍亚洲欧美 | 一区在线免费视频 | 99福利在线观看 | 国产一区2区 | 久久视频精品 | 狠狠干狠狠插 | 亚洲精品黑人 | 国产一区二区三区在线 | 欧美a级成人淫片免费看 | 国产成人精品一区二区三区视频 | 久久精品亚洲精品国产欧美 | 欧美mv日韩mv国产网站91进入 | 一区二区三区国产精品 | 伊人伊成久久人综合网站 | 精品久久久精品 | 夜夜草 | 九九色综合 | 国产成人精品区一区二区不卡 | 欧美情趣视频 | 91视频国产一区 | 91色综合 | 亚洲精品成人网 | 中文字幕国产一区 | 国产欧美精品区一区二区三区 | 精品一区二区三区入口 | 天天玩天天操天天干 | 欧美精品一区在线 | 人人操日日干 | 日本中文字幕在线观看 | 欧美激情网站 | 在线免费观看黄色网址 | 亚洲成人精品在线 | 亚洲国产成人精品女人 | 91免费在线视频 | 亚洲成人999| 一级毛片色一级 | 国产亚洲一级 | 不卡av电影在线播放 | 中文字幕视频一区二区 |