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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

非常完備的按鍵操作系統,單擊、雙擊、N擊,長按。移植性良好

  [復制鏈接]
ID:391730 發表于 2019-12-9 19:15 | 顯示全部樓層 |閱讀模式
本帖更新內容詳見:http://www.zg4o1577.cn/bbs/dpj-176186-1.html

#define BaseTime 10        //時間基準10 ms ,如果設計的時基是5ms 則前面的10就用該變成5
#define number_init          0xfffffffd  // 初始化相關的utime(unsigned long)變量(如果是unsigned int 就應該是0xfffd),采用這個值的好處是,即使發生時鐘計數器溢出,也不影響其他的程序

typedef unsigned long utime;  //這個類型是為了方便移植專門給時間相關變量使用
typedef unsigned long ulong;
typedef unsigned int uint;
typedef unsigned char uchar;

enum ButtonModel{noneClick=0,singalClick,doubleClick,repeatClick,longPress}; //doubleClick目前未定義完整動作 pressDownHold,按下保持
enum ButtonStaus{nonePress=1,pressDown,pressUp,pressDownHold};        /


struct button
{
    uchar outPutEn:1; //發送數據使能
    uchar lastButton:1; //按鍵上次變動后的狀態 默認 1
    uchar init_leavel:1; //設置默認按鍵電平
        uchar longPressFlag:1;            //長按釋放標志 默認0,一旦開始長按則置1
        uchar Gpio_level :3;
        uchar applyUseOpenMaxPwm:1;         //在關機狀態下,若本按鍵按下啟動了系統,則需要申請全局變量標明,禁止其他按鍵關閉被本按鍵打開的系統(自己打開自己負責關閉)

        uchar ticks;            //按鍵按下次數
    enum ButtonStaus lastButtonStaus;   //按鍵上個循環的狀態
    enum ButtonStaus thisButtonStaus;   //按鍵本循環的狀態
    enum ButtonModel lastButtonModel; //按鍵上個循環所處的模式
    enum ButtonModel thisButtonModel; //按鍵本循環應該所處的模式

    uint changeModelTime;  //10ms基準              //長按時間定義
    uint pressLongTime;    //10ms基準              //多擊時間定義

    utime lastPressDownMoment;     //上次按鍵按下所處的時刻
    utime thisPressDownMoment; //本次按鍵按下所處的時刻
    uint tempTime;           //緩存按鍵兩次按下之間的時長

    utime buttonConfir;     //按鍵防抖時長


    utime getTimer; //獲取時鐘精準時刻,用于設定按鍵掃描周期
    utime acquisitionMoment; //獲取時鐘精準時刻,用于記錄相同按鍵狀態持續時長

    uchar  (*read_gpio)(void); //獲取按鍵狀態方法
};
/*================================
outPutEn 是為后面接收按鍵是單擊、多擊長按函數準備的參數。比如按鍵掃描程序10ms運行一次,輸出的是單擊,如果沒有outPutEn這個參數,后面的接收程序會在10ms內一直都接收的是單擊指令,這樣就會一直執行單擊需要進行的操作,本來單擊一次檔位變化1,結果現在檔位變化了n

applyUseOpenMaxPwm 是為多按鍵且按鍵操作有優先權做準備,,有優先權的操作不會被其他按鍵操作打斷




===============================*/
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) //如果是第一次運行,則更新時間
     {
         Key->getTimer=timer;
     }

     else
     {
         if(timer-Key->getTimer>=enOutTime) //如果時間足夠“定義的循環時間” ,則更新時間并允許運行
         {
            Key->getTimer=timer;
            Key->Gpio_level=Key->read_gpio();
            if(Key->Gpio_level>1);
                        else
            {
                         if(Key->lastButton^Key->Gpio_level)//按鍵有電平變化模塊處理開始----------------------------------------------------------------------------//
             {
                                 if(number_init==Key->buttonConfir)
                                        Key->buttonConfir=timer;

                 if(timer-Key->buttonConfir>=noiseProofTime)//按鍵防抖,必須再確認狀態
                 {
                     Key->lastButton=Key->Gpio_level;
                                         Key->acquisitionMoment=number_init;
                     Key->buttonConfir=number_init; //二次確認標志重置



                     if(Key->init_leavel^Key->Gpio_level)//本次按鍵狀態改變后與定義的電平不一致模塊處理開始
                     {
                         switch(Key->lastButtonStaus)
                         {
                         case nonePress: //上個循環是定義的初始電平
                         case pressUp:
                            {
                                if(number_init==Key->lastPressDownMoment)//是第一次記錄按鍵按下時刻
                                {
                                    Key->thisPressDownMoment=Key->lastPressDownMoment=timer;
                                }
                                else //不第一次記錄
                                {
                                    Key->thisPressDownMoment=timer;
                                    Key->tempTime+=Key->thisPressDownMoment-Key->lastPressDownMoment; //獲取兩次按鍵按下之間的時間間隔
                                    Key->lastPressDownMoment=Key->thisPressDownMoment;  //更新
                                }


                                Key->ticks++;


//不在此處增加pressLongTime判斷的原因是,buftime0記錄的是兩次按鍵按下之間的時長,在兩次按下之間必有彈起,一旦彈起,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)//第三擊的時間也小于定義的改變模式時間
                                        {
                                            Key->thisButtonModel=repeatClick;
                                        }
                                        else                //第三擊的時間大于定義的改變模式時間
                                        {
                                            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;
                            }

                         }

                     } //按鍵狀態改變后是與定義的電平模塊不同處理結束//
                         ///////////////////////////////////////////////////////////////////////////
                     else //按鍵狀態改變與定義的電平模塊相同開始處理//
                     {
                          Key->longPressFlag=0;
                                                  switch(Key->lastButtonStaus)
                         {
                         case pressDown://上個循環是低電平,機器人手速
                         case pressDownHold:
                            {

                                if(Key->tempTime>=Key->changeModelTime)
                                {
                                    Key->tempTime=0;
                                    Key->ticks=0;

                                }

                                Key->thisButtonStaus=pressUp; //按鍵彈起
                                Key->thisButtonModel=noneClick;

                                break;
                            }

                         }

                     }//本次按鍵狀態改變后是定義的電平處理結束//
                 }

             }//按鍵有電平變化模塊處理結束-------------------------------------------------------------------------------------------------------//
             else if(Key->init_leavel==Key->Gpio_level)//按鍵無改變且是初始電平處理開始//
             {
                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 一旦置零,記錄按鍵按下時刻的值都應當重置
                                         Key->thisPressDownMoment=Key->lastPressDownMoment=number_init;
                 }
                                 if(timer-Key->acquisitionMoment>259200000)//一個月都沒有使用了,所以清零
                                 {
                                        Open_timer0;                  //重置timer0 防止一年后溢出
                                 }

                 switch(Key->lastButtonStaus)
                 {
                 case nonePress:
                 case pressUp:
                    {
                        Key->thisButtonStaus=nonePress;
                        Key->thisButtonModel=noneClick;
                        break;
                    }
/*
                 case pressDown:
                 case pressDownHold:          //容錯處理,理論上若上個循環與本循環電平不一致,應該在電平有變化模塊處理不會在本模塊
                    {

                        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;
                    }
*/
                 }

             }//按鍵狀態無改變且是初始電平處理結束//
             else//按鍵狀態無改變且是非初始電平處理開始//
             {
                 if(number_init==Key->acquisitionMoment)
                 {
                     Key->acquisitionMoment=timer;
                 }
                 switch(Key->lastButtonStaus)
                 {
/*
                 case nonePress:          //容錯處理,理論上若上個循環與本循環電平不一致,應該在電平有變化模塊處理不會在本模塊
                 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; //一但超時,所謂的記錄按鍵按下時間間隔就無意義,必須重置
                                                                Key->tempTime=0;  //按鍵鍵緩沖時間不清零,對操作體驗影響很不好
                                                                Key->ticks=0;
                            }
                            else
                            {
                                Key->thisButtonModel=singalClick;
                            }
                            Key->thisButtonStaus=pressDown;
                        }



                    }
*/
                 case pressDown:
                 case pressDownHold:
                    {
                       if(longPress==Key->lastButtonModel||Key->longPressFlag)
                       {
                           Key->thisButtonModel=noneClick;        // 改變了模式,下個循環程序進入其它分支,所以必須在上面加入模式判斷
                           Key->thisButtonStaus=pressDownHold;
                           Key->acquisitionMoment=timer;
                                                   Key->lastPressDownMoment=Key->thisPressDownMoment=timer; //PressDownMoment必須在按鍵按下保持狀態下更新時間,否則tempTime會計算總的按鍵時長,以至于無法進入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 是授時系統,比如每10ms加一位,enOutTime 是循環檢測時間,比如允許每50ms建成運行一次,noiseProofTime是按鍵防抖動時間,程序運行后檢測按鍵的thisButtonModel狀態就能知道是單擊雙擊多擊還是長按。目前在函數中定義了單擊到三擊,三擊以上可自己添加
================================*/

評分

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

查看全部評分

回復

使用道具 舉報

ID:391730 發表于 2019-12-9 19:19 | 顯示全部樓層
void Button_init(struct button *Key,uchar(*get_leavel)(),bit init_button_leavel,uint LongPressTimes,uint changeModelTime)
{

        Key->read_gpio=get_leavel;
        Key->outPutEn=0;
    Key->lastButton=init_button_leavel;             //系統默認高電平
        Key->Gpio_level=0;
    Key->init_leavel=init_button_leavel;
        if(0==Key->init_leavel)
        {
    Key->lastButtonStaus=pressDownHold;         //系統默認電平
    Key->thisButtonStaus=pressDownHold;         //系統默認電平
        }
        else
        {
    Key->lastButtonStaus=Key->init_leavel;         //系統默認電平
    Key->thisButtonStaus=Key->init_leavel;         //系統默認電平
        }
    Key->lastButtonModel=noneClick;
    Key->thisButtonModel=noneClick;
    Key->changeModelTime=changeModelTime;//10ms基準
    Key->pressLongTime=LongPressTimes;    //10ms基準
    Key->lastPressDownMoment=number_init;
    Key->thisPressDownMoment=number_init;
    Key->tempTime=0;
    Key->ticks=0;
    Key->buttonConfir=number_init;
        Key->longPressFlag=0;
        Key->applyUseOpenMaxPwm=0;
    Key->getTimer=number_init;
    Key->acquisitionMoment=number_init;


}
回復

使用道具 舉報

ID:98992 發表于 2019-12-10 19:16 | 顯示全部樓層
看的頭大 暫時還是入門級別
回復

使用道具 舉報

ID:71535 發表于 2019-12-10 19:20 | 顯示全部樓層
制作單擊、雙擊、N擊,長按。移植性良好,厲害了,收藏了
回復

使用道具 舉報

ID:391730 發表于 2019-12-17 15:17 | 顯示全部樓層
waerdeng 發表于 2019-12-10 19:20
制作單擊、雙擊、N擊,長按。移植性良好,厲害了,收藏了

目前程序使用在公司的產品上在,所以暫時沒法發一個完整的DEMO,等過段時間改一個DEMO在討論下。
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 国产清纯白嫩初高生在线播放视频 | 亚洲a毛片 | 精品久久久久久久久久久 | 一区二区三区影院 | 欧美性区 | 欧美三级在线 | 俺去俺来也www色官网cms | 国产精品久久性 | 亚洲成人福利视频 | 在线免费黄色小视频 | 亚洲精品乱码久久久久久蜜桃91 | 在线一区二区三区 | 99久久精品一区二区毛片吞精 | 日日操夜夜操视频 | 色综合久久久久 | www.com久久久 | 人人九九精 | 欧美一级大片免费看 | 日韩字幕 | 九九热精品在线 | 日韩高清中文字幕 | 亚洲久久一区 | 亚洲vs天堂 | 特黄特色大片免费视频观看 | 成人黄色电影免费 | 久精品视频 | 欧美日韩综合精品 | 国产精品中文字幕在线 | 精品国产一区二区三区观看不卡 | 天天拍天天插 | 色婷婷在线视频 | 欧美日韩综合一区 | 中文字幕av在线播放 | 国产女人叫床高潮大片免费 | 毛片站| 成人午夜精品 | 日韩色在线 | 很很干很很日 | 欧美在线观看一区 | 久久精品久久久久久 | 久久综合九色综合欧美狠狠 |