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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 1555|回復: 2
收起左側

51單片機長按短按連擊2-10次函數 帶仿真演示程序

  [復制鏈接]
ID:41347 發表于 2023-12-20 08:24 | 顯示全部樓層 |閱讀模式
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
51hei.png

單片機源程序如下:
#ifndef _KEY_H
#define _KEY_H

//#include"reg51.h"
sbit KEY_INPUT  =        P1^2;    //  按鍵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 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  判定單擊的時間長度,軟件消抖
#define KEY_INTERVAL        70      //  KEY_INTERVAL*10MS    = 300MS 判定雙擊的時間間隔(仿真調慢了700MS)實際30-40
#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 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;                      //  讀取當前鍵值

    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_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;       //  改變 按鍵狀態值
        // key_return = D_KEY;            //  返回 有效按鍵:[雙擊]
   //            key_state1 = KEY_STATE_0;      //  返回 按鍵狀態0,等待新的有效按鍵
            }
            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_time1 = 0;                                                           // 返回 有效按鍵:[三擊]
                 key_state1 = KEY_STATE_3;      // 返回 按鍵狀態0,等待新的有效按鍵
            }
            else                                // 有[雙擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內,沒有[單擊],則判定為 [雙擊]
            {
                key_time1++;                    // 計數 時間間隔
                if(key_time1 >= KEY_INTERVAL)   // 超過 時間間隔
                 {
                      key_return =  D_KEY;       // 返回 有效按鍵 返回 有效按鍵:[2擊】
                      key_state1 = KEY_STATE_0; // 返回 按鍵狀態0,等待新的有效按鍵
                 }              
             }              
             break;
                          case KEY_STATE_3:                       // 按鍵狀態3:判定是否有[4擊]
            if (key_temp == S_KEY)              // 有[3擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內,再次有[單擊],則為[三擊]
            {
               //  key_return = F_KEY;            // 返回 有效按鍵:[4擊]
                                                           key_time1 = 0;  
                 key_state1 = KEY_STATE_4;      // 返回 按鍵狀態0,等待新的有效按鍵
            }
            else                                // 有[3擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內,沒有[4擊],則判定為 [3擊]
            {
                key_time1++;                    // 計數 時間間隔
                if(key_time1 >= KEY_INTERVAL)   // 超過 時間間隔
                 {
                      key_return = T_KEY;         // 返回 有效按鍵:[3擊]
                      key_state1 = KEY_STATE_0; // 返回 按鍵狀態0,等待新的有效按鍵
                 }              
             }              
             break;
                  case KEY_STATE_4:                       // 按鍵狀態4:判定是否有[5擊]
            if (key_temp == S_KEY)              // 有[4擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內,再次有[單擊],則為[5擊],由于這里只擴展到[5擊],
            {
                 //key_return = FIVE_KEY;            // 返回 有效按鍵:[5擊]
                                                           key_time1 = 0;
                 key_state1 = KEY_STATE_5;      // 返回 按鍵狀態0,等待新的有效按鍵
            }
            else                                // 有[4擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內,沒有[5擊],則判定為 [4擊]
            {
                key_time1++;                    // 計數 時間間隔
                if(key_time1 >= KEY_INTERVAL)   // 超過 時間間隔
                 {
                      key_return = F_KEY;         // 返回 有效按鍵:[4擊]
                      key_state1 = KEY_STATE_0; // 返回 按鍵狀態0,等待新的有效按鍵
                 }              
             }              
             break;
                 case KEY_STATE_5:                       // 按鍵狀態5:判定是否有[5擊]
            if (key_temp == S_KEY)              // 有[5擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內,再次有[單擊],則為[6擊]
            {
                // key_return = SIX_KEY;            // 返回 有效按鍵:[6擊]
                                                          // key_state1 = KEY_STATE_0; // 返回 按鍵狀態0,等待新的有效按鍵
                                                           key_time1 = 0;
                 key_state1 = KEY_STATE_6;      // 返回 按鍵狀態0,等待新的有效按鍵
            }
            else                                // 有[5擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內,沒有[6擊],則判定為 [5擊]
            {
                key_time1++;                    // 計數 時間間隔
                if(key_time1 >= KEY_INTERVAL)   // 超過 時間間隔
                 {
                      key_return = FIVE_KEY;         // 返回 有效按鍵:[5擊]
                      key_state1 = KEY_STATE_0; // 返回 按鍵狀態0,等待新的有效按鍵
                 }              
             }              
             break;
                        case KEY_STATE_6:                       // 按鍵狀態6:判定是否有[6擊]
            if (key_temp == S_KEY)              // 有[6擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內,再次有[單擊],則為[7擊]
            {
                // key_return = SEVEN_KEY;            // 返回 有效按鍵:[7擊]
                // key_state1 = KEY_STATE_0;      // 返回 按鍵狀態0,等待新的有效按鍵
                                                           key_time1 = 0;
                 key_state1 = KEY_STATE_7;      // 返回 按鍵狀態0,等待新的有效按鍵
            }
            else                                // 有[6擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內,沒有[7擊],則判定為 [6擊]
            {
                key_time1++;                    // 計數 時間間隔
                if(key_time1 >= KEY_INTERVAL)   // 超過 時間間隔
                 {
                      key_return = SIX_KEY;         // 返回 有效按鍵:[6擊]
                      key_state1 = KEY_STATE_0; // 返回 按鍵狀態0,等待新的有效按鍵
                 }              
             }              
             break;         
                        case KEY_STATE_7:                       // 按鍵狀態7:判定是否有[7擊]
            if (key_temp == S_KEY)              // 有[7擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內,再次有[單擊],則為[8擊]
            {
                // key_return = EIGHT_KEY;            // 返回 有效按鍵:[8擊]
                // key_state1 = KEY_STATE_0;      // 返回 按鍵狀態0,等待新的有效按鍵
                                                                key_time1 = 0;
                key_state1 = KEY_STATE_8;      // 返回 按鍵狀態0,等待新的有效按鍵
            }
            else                                // 有[7擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內,沒有[8擊],則判定為 [7擊]
            {
                key_time1++;                    // 計數 時間間隔
                if(key_time1 >= KEY_INTERVAL)   // 超過 時間間隔
                 {
                      key_return = SEVEN_KEY;         // 返回 有效按鍵:[7擊]
                      key_state1 = KEY_STATE_0; // 返回 按鍵狀態0,等待新的有效按鍵
                 }              
             }              
             break;                 
                        case KEY_STATE_8:                       // 按鍵狀態7:判定是否有[8擊]
            if (key_temp == S_KEY)              // 有[8擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內,再次有[單擊],則為[9擊]
            {
                // key_return = NINE_KEY;            // 返回 有效按鍵:[9擊]
                // key_state1 = KEY_STATE_0;      // 返回 按鍵狀態0,等待新的有效按鍵
                                                          key_time1 = 0;
                key_state1 = KEY_STATE_9;      // 返回 按鍵狀態0,等待新的有效按鍵

            }
            else                                // 有[8擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內,沒有[9擊],則判定為 [8擊]
            {
                key_time1++;                    // 計數 時間間隔
                if(key_time1 >= KEY_INTERVAL)   // 超過 時間間隔
                 {
                      key_return = EIGHT_KEY;         // 返回 有效按鍵:[8擊]
                      key_state1 = KEY_STATE_0; // 返回 按鍵狀態0,等待新的有效按鍵
                 }              
             }              
             break;                 
                          case KEY_STATE_9:                       // 按鍵狀態7:判定是否有[9擊]
            if (key_temp == S_KEY)              // 有[9擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms) 內,再次有[單擊],則為[9擊]
            {
                 key_return = TEN_KEY;            // 返回 有效按鍵:[10擊]
                 key_state1 = KEY_STATE_0;      // 返回 按鍵狀態0,等待新的有效按鍵
            }
            else                                // 有[9擊]后,如果在 設定的時間間隔(KEY_INTERVAL*10ms=30*10ms=300ms)內,沒有[10擊],則判定為 [9擊]
            {
                key_time1++;                    // 計數 時間間隔
                if(key_time1 >= KEY_INTERVAL)   // 超過 時間間隔
                 {
                      key_return = NINE_KEY;         // 返回 有效按鍵:[9擊]
                      key_state1 = KEY_STATE_0; // 返回 按鍵狀態0,等待新的有效按鍵
                 }              
             }              
             break;                                                         
   //=============================================================================================
        default:                                //  特殊情況:key_state是其他值得情況,清零key_state。這種情況一般出現在 沒有初始化key_state,第一次執行這個函數的時候
            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 計時標志


unsigned char key_read();           // 聲明讀取按鍵函數


void T0_Init_10ms(void)             // timer0,初始化函數 ,定時時間為 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;      
}

// 主函數
void main(void)
{
   // P1^2=1;                                   // P1.0 拉高
    T0_Init_10ms();                             // 定時器0,初始化,定時10ms

    while(1)
    {
        if(g_flag_10ms_key)                     // 等待10ms,定時完成
        {
            g_flag_10ms_key = 0;                // 清零10ms定時標志

            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;       // 單擊 點亮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;      // 長按 熄滅所有LED
            }
        }
    }
}

// timer0 中斷服務程序
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 定時標志
}

        
仿真程序: 按鍵單擊多擊長按掃描演示 -狀態機.7z (135.29 KB, 下載次數: 54)

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

回復

使用道具 舉報

ID:849894 發表于 2024-1-4 15:28 | 顯示全部樓層
這個程序的主要作用是什么?
回復

使用道具 舉報

ID:430492 發表于 2024-1-4 16:04 | 顯示全部樓層
可以用少量的按鍵,實現多個按鈕才能實現的功能。
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 日韩欧美一区二区三区免费看 | 成年人精品视频在线观看 | 91视频网| 福利av在线 | 国产视频久久久 | 九九综合 | 永久免费视频 | 亚洲在线一区二区 | 1区2区3区视频 | 一区二区三区视频免费观看 | 午夜爽爽爽男女免费观看 | 成人影 | 欧美一区二区三区免费电影 | 日本中文字幕一区 | 色天堂影院 | 国产激情一区二区三区 | 天天夜干 | 99精品99| 91成人精品 | 午夜视频免费网站 | 欧美一级www片免费观看 | av在线电影网 | 免费观看黄色一级片 | 91精品一区二区三区久久久久久 | 免费的av | 亚洲国产成人在线观看 | 国产精品成人国产乱一区 | 中文字幕视频在线 | 亚洲一区二区在线 | 免费麻豆视频 | 精品国产精品 | 欧美性大战久久久久久久蜜臀 | h视频在线观看免费 | 亚洲一二三区精品 | 丝袜天堂 | 久久综合激情 | 新疆少妇videos高潮 | 天天爽夜夜操 | 亚洲精品久久久9婷婷中文字幕 | 久久国| 欧美日日|