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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

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

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:391730 發(fā)表于 2019-12-9 19:15 | 只看該作者 回帖獎勵 |倒序?yàn)g覽 |閱讀模式
本帖更新內(nèi)容詳見:http://www.zg4o1577.cn/bbs/dpj-176186-1.html

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

typedef unsigned long utime;  //這個類型是為了方便移植專門給時間相關(guān)變量使用
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; //發(fā)送數(shù)據(jù)使能
    uchar lastButton:1; //按鍵上次變動后的狀態(tài) 默認(rèn) 1
    uchar init_leavel:1; //設(shè)置默認(rèn)按鍵電平
        uchar longPressFlag:1;            //長按釋放標(biāo)志 默認(rèn)0,一旦開始長按則置1
        uchar Gpio_level :3;
        uchar applyUseOpenMaxPwm:1;         //在關(guān)機(jī)狀態(tài)下,若本按鍵按下啟動了系統(tǒng),則需要申請全局變量標(biāo)明,禁止其他按鍵關(guān)閉被本按鍵打開的系統(tǒng)(自己打開自己負(fù)責(zé)關(guān)閉)

        uchar ticks;            //按鍵按下次數(shù)
    enum ButtonStaus lastButtonStaus;   //按鍵上個循環(huán)的狀態(tài)
    enum ButtonStaus thisButtonStaus;   //按鍵本循環(huán)的狀態(tài)
    enum ButtonModel lastButtonModel; //按鍵上個循環(huán)所處的模式
    enum ButtonModel thisButtonModel; //按鍵本循環(huán)應(yīng)該所處的模式

    uint changeModelTime;  //10ms基準(zhǔn)              //長按時間定義
    uint pressLongTime;    //10ms基準(zhǔn)              //多擊時間定義

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

    utime buttonConfir;     //按鍵防抖時長


    utime getTimer; //獲取時鐘精準(zhǔn)時刻,用于設(shè)定按鍵掃描周期
    utime acquisitionMoment; //獲取時鐘精準(zhǔn)時刻,用于記錄相同按鍵狀態(tài)持續(xù)時長

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

applyUseOpenMaxPwm 是為多按鍵且按鍵操作有優(yōu)先權(quán)做準(zhǔn)備,,有優(yōu)先權(quán)的操作不會被其他按鍵操作打斷




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

     else
     {
         if(timer-Key->getTimer>=enOutTime) //如果時間足夠“定義的循環(huán)時間” ,則更新時間并允許運(yùn)行
         {
            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)//按鍵防抖,必須再確認(rèn)狀態(tài)
                 {
                     Key->lastButton=Key->Gpio_level;
                                         Key->acquisitionMoment=number_init;
                     Key->buttonConfir=number_init; //二次確認(rèn)標(biāo)志重置



                     if(Key->init_leavel^Key->Gpio_level)//本次按鍵狀態(tài)改變后與定義的電平不一致模塊處理開始
                     {
                         switch(Key->lastButtonStaus)
                         {
                         case nonePress: //上個循環(huán)是定義的初始電平
                         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;
                            }

                         }

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

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

                                }

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

                                break;
                            }

                         }

                     }//本次按鍵狀態(tài)改變后是定義的電平處理結(jié)束//
                 }

             }//按鍵有電平變化模塊處理結(jié)束-------------------------------------------------------------------------------------------------------//
             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 一旦置零,記錄按鍵按下時刻的值都應(yīng)當(dāng)重置
                                         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:          //容錯處理,理論上若上個循環(huán)與本循環(huán)電平不一致,應(yīng)該在電平有變化模塊處理不會在本模塊
                    {

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

             }//按鍵狀態(tài)無改變且是初始電平處理結(jié)束//
             else//按鍵狀態(tài)無改變且是非初始電平處理開始//
             {
                 if(number_init==Key->acquisitionMoment)
                 {
                     Key->acquisitionMoment=timer;
                 }
                 switch(Key->lastButtonStaus)
                 {
/*
                 case nonePress:          //容錯處理,理論上若上個循環(huán)與本循環(huán)電平不一致,應(yīng)該在電平有變化模塊處理不會在本模塊
                 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;  //按鍵鍵緩沖時間不清零,對操作體驗(yàn)影響很不好
                                                                Key->ticks=0;
                            }
                            else
                            {
                                Key->thisButtonModel=singalClick;
                            }
                            Key->thisButtonStaus=pressDown;
                        }



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

評分

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

查看全部評分

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

使用道具 舉報

沙發(fā)
ID:391730 發(fā)表于 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;             //系統(tǒng)默認(rèn)高電平
        Key->Gpio_level=0;
    Key->init_leavel=init_button_leavel;
        if(0==Key->init_leavel)
        {
    Key->lastButtonStaus=pressDownHold;         //系統(tǒng)默認(rèn)電平
    Key->thisButtonStaus=pressDownHold;         //系統(tǒng)默認(rèn)電平
        }
        else
        {
    Key->lastButtonStaus=Key->init_leavel;         //系統(tǒng)默認(rèn)電平
    Key->thisButtonStaus=Key->init_leavel;         //系統(tǒng)默認(rèn)電平
        }
    Key->lastButtonModel=noneClick;
    Key->thisButtonModel=noneClick;
    Key->changeModelTime=changeModelTime;//10ms基準(zhǔn)
    Key->pressLongTime=LongPressTimes;    //10ms基準(zhǔn)
    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;


}
回復(fù)

使用道具 舉報

板凳
ID:98992 發(fā)表于 2019-12-10 19:16 | 只看該作者
看的頭大 暫時還是入門級別
回復(fù)

使用道具 舉報

地板
ID:71535 發(fā)表于 2019-12-10 19:20 | 只看該作者
制作單擊、雙擊、N擊,長按。移植性良好,厲害了,收藏了
回復(fù)

使用道具 舉報

5#
ID:391730 發(fā)表于 2019-12-17 15:17 | 只看該作者
waerdeng 發(fā)表于 2019-12-10 19:20
制作單擊、雙擊、N擊,長按。移植性良好,厲害了,收藏了

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

使用道具 舉報

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

本版積分規(guī)則

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

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

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 国产一区二区三区色淫影院 | 亚洲精品久久久一区二区三区 | 欧美三区在线观看 | 午夜午夜精品一区二区三区文 | 国产精品久久久久久久岛一牛影视 | www.五月天婷婷.com | 国产一级免费在线观看 | 国产视频一视频二 | 欧美xxxx日本 | 成人免费一区二区三区视频网站 | 欧美黄色免费网站 | 亚洲最大的黄色网址 | 在线播放国产一区二区三区 | www.狠狠干 | 国产精久久久久久久 | 一区日韩 | 最新高清无码专区 | 成人三级av | 国产精品毛片一区二区三区 | www性色 | 国产精品久久久久久久午夜片 | 成人国产精品久久 | 亚洲xx在线 | 欧美日韩专区 | 久久久www成人免费精品 | 亚洲国产精品久久久 | 久色网 | 中文字幕成人在线 | 午夜影院在线观看 | 欧州一区二区三区 | 国产精品99久久久久久动医院 | 欧美高清视频一区 | 99国产视频 | 五月综合激情网 | 一区二区三区在线播放视频 | 国产高清精品一区二区三区 | 亚洲精选久久 | www国产成人免费观看视频,深夜成人网 | 国产一区二区三区精品久久久 | 中文字幕在线一区 | 国产一区二区在线免费视频 |