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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 5431|回復: 22
收起左側

標準的單片機C語言按鍵檢測代碼格式是什么樣的?

  [復制鏈接]
ID:709761 發表于 2022-5-16 11:41 | 顯示全部樓層 |閱讀模式
//以下兩種單片機C語言代碼,哪個正確

if(k1 == 0)
  {
                Delay6ms();//按鍵消抖
                if(k1 == 0)
                {

                //執行按鍵結果
               }
                while(!k1)//等待按鍵放開
   }

//--------------------------------------------------------

if(k1 == 0)
  {
                Delay6ms();//按鍵消抖
                if(k1 == 0)
                {

                //執行按鍵結果

                while(!k1)//等待按鍵放開
                }  
            }

回復

使用道具 舉報

ID:276663 發表于 2022-5-16 13:09 | 顯示全部樓層
回復

使用道具 舉報

ID:161164 發表于 2022-5-16 13:17 | 顯示全部樓層
都不好,浪費資源

  1. static uint Delay = 0;

  2. if(K1 == 0)

  3. {

  4. if(Delay <= 0xFFFF)Delay++;

  5. if(Delay == 1000)

  6. {

  7. //執行按鍵結果

  8. }

  9. }else{

  10. Delay=0;

  11. }
復制代碼




回復

使用道具 舉報

ID:56665 發表于 2022-5-16 13:47 | 顯示全部樓層
lkc8210 發表于 2022-5-16 13:17
都不好,浪費資源

這個代碼和上面的沒有區別,Delay++一樣在空耗,要想不浪費資源,延時放在定時器中斷里處理。
回復

使用道具 舉報

ID:123289 發表于 2022-5-16 14:01 | 顯示全部樓層
都不標準,贊同地板的說法。
回復

使用道具 舉報

ID:213173 發表于 2022-5-16 14:30 | 顯示全部樓層
沒有標準的按鍵代碼。用什么方式寫按鍵代碼是設計者根據硬件條件、應用場景和編程習慣所采用。最常見的代碼不下20種。樓主所列兩種其實就是同為一種最低水平的入門級寫法,大多見于針對初學者的教材中。優點是初學者容易讀懂,用于極簡單的程序也無不可。其缺點是效率低下,與其它需要快速響應的程序發生沖突.....。
回復

使用道具 舉報

ID:161164 發表于 2022-5-16 14:38 | 顯示全部樓層
m182892 發表于 2022-5-16 13:47
這個代碼和上面的沒有區別,Delay++一樣在空耗,要想不浪費資源,延時放在定時器中斷里處理。

一個Delay++的消耗比的上Delay6ms和while(!k1)的死等?
我的代碼的原理是定時掃描按鍵的電平
確保按鍵保持低電平一段時間才輸出
每掃描一次
if(K1==0)
if(Delay<0xFFFF)
Delay++;
if(Delay==1000)
這四句只用了5.43us(keil debug mode STC89C52RC@11.0592)

求問有沒有更低消耗的消抖算法
回復

使用道具 舉報

ID:624769 發表于 2022-5-16 16:06 來自觸屏版 | 顯示全部樓層
lkc8210 發表于 2022-5-16 14:38
一個Delay++的消耗比的上Delay6ms和while(!k1)的死等?
我的代碼的原理是定時掃描按鍵的電平
確保按鍵保 ...

發現你特別不愛用中斷。
誠然,表面上看,你這段代碼的確只需要5.4us,比起阻塞式while,的確不耗系統資源,但是,你累加1000次,才完成一次按鍵判斷,總共耗費的系統資源,并不比delay6ms節約吧? 隨著你程序復雜度的提升,你要不停地修正1000這個值,來均衡消抖和漏判這個平衡點。某種意義上來講,穩定性還不如阻塞式判斷。用個中斷不好么?硬件放在那里不用,才是真正的浪費,并不是節約。真要效率最大化,個人覺得,外部中斷觸發,定時器中斷消抖,才是最優方案,系統中斷資源不夠了,再去考慮不用中斷的方法。
回復

使用道具 舉報

ID:203661 發表于 2022-5-16 16:22 | 顯示全部樓層
你那個是標準教科書寫法
回復

使用道具 舉報

ID:213173 發表于 2022-5-16 16:43 | 顯示全部樓層
本帖最后由 wulin 于 2022-5-16 17:21 編輯
lkc8210 發表于 2022-5-16 14:38
一個Delay++的消耗比的上Delay6ms和while(!k1)的死等?
我的代碼的原理是定時掃描按鍵的電平
確保按鍵保 ...

“這四句只用了5.43us”不如 if(K1==0){if(++Delay>=1000).....} 效率更高。常見的按鍵多為選用輕觸開關,其抖動時間在2~10ms范圍。5.43us的時間難以確保避開抖動時段。在特定的應用場景,消抖不是必須的。諸如某大佬的經典代碼,完成長短按就三條語句。
unsigned char Trg;
unsigned char Cont;
void KeyRead( void )
{
    unsigned char ReadData = PINB^0xff;
    Trg = ReadData & (ReadData ^ Cont);
    Cont = ReadData;
}
回復

使用道具 舉報

ID:161164 發表于 2022-5-16 16:46 | 顯示全部樓層
188610329 發表于 2022-5-16 16:06
發現你特別不愛用中斷。
誠然,表面上看,你這段代碼的確只需要5.4us,比起阻塞式while,的確不耗系統資 ...

大佬你好

我沒說不用中斷啊~
如果把代碼放到1ms中斷中
直接寫個if(Delay==20)就可以濾掉99.99%的抖動而不用調節
Delay更可以改用unsigned char更節約步驟

我是考慮到有些新手還沒學定時器中斷
就推薦一個低消耗,不阻塞,可以不用定時器中斷,簡單易懂的按鍵消抖代碼

至于關于累積消耗,我更考慮每次大循環的消耗
經常有貼子求問按鍵令數碼管閃爍
就是一些新手用了delayms和while(!K1)這種阻塞式消抖

比起突然來個大消耗,我更愿意選連續而均勻的小消耗

更正:
之前說的5.43 us消耗是沒有鍵按時的計時
有按鍵時是17.36 us(keil debug mode STC89C52RC@11.0592)
回復

使用道具 舉報

ID:161164 發表于 2022-5-16 17:11 | 顯示全部樓層
wulin 發表于 2022-5-16 16:43
“這四句只用了5.43us”和只用一句if(K1==0)沒有什么區別。常見的按鍵多為選用輕觸開關,其抖動時間在2~1 ...

大佬你好

之前我仿真錯了
5.43 us是沒有鍵按時的耗時
有按鍵時是17.36 us

如果是if(Delay == 1)當然沒有用
但用的是if(Delay == 1000)在只計算自己的耗時都有17.36ms
足以濾掉99.99%的抖動

我也知道消抖不是必須的
如一些有自保的開關,限位器等
按著就是按著
不用理會按了多少下

那大佬的代碼我也拜讀過
第一次看時驚為天人
連說三字妙妙妙
我只知道他可以檢測電平的改變來觸發短按
但如何觸發長按。。。愿聞其詳
回復

使用道具 舉報

ID:213173 發表于 2022-5-16 17:38 | 顯示全部樓層
lkc8210 發表于 2022-5-16 17:11
大佬你好

之前我仿真錯了

不好意思,只看了前面“這四句只用了5.43us”就望文生義,確為不妥,帖子已改。長短按就三條語句是真是的。我特別強調的是應用場景。 一款精巧的按鍵處理程序.doc (36.5 KB, 下載次數: 13)

回復

使用道具 舉報

ID:624769 發表于 2022-5-17 14:52 | 顯示全部樓層
lkc8210 發表于 2022-5-16 16:46
大佬你好

我沒說不用中斷啊~

抱歉,沒有別的意思,就是看過不少你的回帖,發現你大多都刻意的回避使用中斷,之前,也看了你關于旋轉編碼器的一個回帖(構思很好,非常簡潔,但是,因為刻意回避中斷,所以有漏洞,當然普通使用是沒有什么問題的,這里就不展開了),而此帖,樓主又刻意強調“標準”二字,雖然按鍵判斷,沒有幾百種都有幾十種方式,但是,要說標準的話,排除衍生出來的組合按鍵,矩陣按鍵不說,比較有代表性的獨立按鍵而言,用外部中斷判斷,才是能算比較“標準”的用法吧?
“標準”按鍵,應該硬件消抖,算了,標準是被不斷的拉低的,就當是軟件消抖是“標準”吧。竊以為,外部中斷+定時器中斷,占用系統少。無漏判誤判,歡迎指正。

bit    Key_Press;
void main()
{
       TMOD = 0x00;            //13位定時器模式 (不設初值,就用從默認的 0 開始計時 12Mhz 約 8.192Ms 溢出)
       IT0 = 1;               //下降沿觸發
       EX0 = 1;
       ET0 = 1;
       EA  = 1;
       while(1)
       {
                if(Key_Press)
                {
                        Key_Press = 0;   //清按鍵標志
                        //按鍵后需要執行的代碼。
                }
       }
}

void EX0_INT  interrupt 0
{
        Key_Press = 1;    //置位按鍵標志
        EX0 = 0;       //關外部中斷
        TR0 = 1;        //開定時器消抖
}

void T0_INT  interrupt 1
{
        if(IE0)
        {
               IE0 = 0;   //繼續消抖
        }
        else
        {
               EX0 = 1;   //消抖完成,重開外部中斷
               TR0 = 0;  //關定時器
        }
}
回復

使用道具 舉報

ID:883242 發表于 2022-5-17 15:16 | 顯示全部樓層
lkc8210 發表于 2022-5-16 17:11
大佬你好

之前我仿真錯了

新開關一般不需要消抖,但是用舊了一般都會抖。

曾經遇到過一個水平挺高的高手,居然跟我說按鍵不需要消抖,后來聽熟悉他的人說,畢業之后只做過單片機原廠FAE,給要用單片機的廠家做個demo就行了,從來沒有做過一個產品的全壽命周期測試。然后我就找了幾個新按鍵,果然一個抖的都沒有。
回復

使用道具 舉報

ID:824490 發表于 2022-5-17 17:35 | 顯示全部樓層
Hephaestus 發表于 2022-5-17 15:16
新開關一般不需要消抖,但是用舊了一般都會抖。

曾經遇到過一個水平挺高的高手,居然跟我說按鍵不需要 ...

這里的“抖”不一定是按鍵產生的,還可能是外部電磁環境產生的尖脈沖。。
回復

使用道具 舉報

ID:161164 發表于 2022-5-17 17:40 | 顯示全部樓層
wulin 發表于 2022-5-16 17:38
不好意思,只看了前面“這四句只用了5.43us”就望文生義,確為不妥,帖子已改。長短按就三條語句是真是的 ...

文件收藏了,感謝分享
回復

使用道具 舉報

ID:161164 發表于 2022-5-17 17:48 | 顯示全部樓層
188610329 發表于 2022-5-17 14:52
抱歉,沒有別的意思,就是看過不少你的回帖,發現你大多都刻意的回避使用中斷,之前,也看了你關于旋轉編 ...

代碼很巧妙,但為了一個按鍵占用了一個外中斷和一個定時器,算不上占用系統少吧?
而且只能濾掉按下那一剎那的抖動,濾不掉放開那一剎那的抖動吧?
稍微修改一下
  1. bit    Key_Press;
  2. sbit Key_XX = P3^2;
  3. void main()
  4. {
  5.         TMOD = 0x00;            //13位定時器模式 (不設初值,就用從默認的 0 開始計時 12Mhz 約 8.192Ms 溢出)
  6.         IT0 = 1;               //下降沿觸發
  7.         EX0 = 1;
  8.         ET0 = 1;
  9.         EA  = 1;
  10.         while(1)
  11.         {
  12.                 if(Key_Press)
  13.                 {
  14.                         Key_Press = 0;   //清按鍵標志
  15.                         //按鍵后需要執行的代碼。
  16.                 }
  17.         }
  18. }

  19. void EX0_INT  interrupt 0
  20. {
  21.         EX0 = 0;       //關外部中斷
  22.         TR0 = 1;        //開定時器消抖
  23. }

  24. void T0_INT  interrupt 1
  25. {
  26.         if(IE0)
  27.         {
  28.                 IE0 = 0;   //繼續消抖
  29.         }
  30.         else
  31.         {
  32.                 if(!Key_XX)Key_Press = 1;    //置位按鍵標志
  33.                 EX0 = 1;   //消抖完成,重開外部中斷
  34.                 TR0 = 0;  //關定時器
  35.         }
  36. }
復制代碼

回復

使用道具 舉報

ID:509408 發表于 2022-5-17 17:55 | 顯示全部樓層
void CheckSwitchKey(void)
{
               
                if(cgCheckSwitchTime<3)          //3ms掃描一次,該變量可放入定時器中累加
                         return;       
                //檢查前先將該IO口線設置為1
                SWITCH_KEY1 = 1;
                SWITCH_KEY2 = 1;
                cgCheckSwitchTime = 0;
                       
                if( (cgSwitchStatus & 0x01) && (SWITCH_KEY2==0) )
                {
                        //按鍵前狀態=1,目前狀態=0        (首次檢測按鍵按下)
                        cglowVotTime = 0;          //按鍵低電平計時清0
                }
                else
                {
                        if( ((cgSwitchStatus & 0x01)!=0x01) && (SWITCH_KEY2==1) )
                        {
                                //按鍵前狀態=0,目前狀態=1         (按鍵彈起)
                                //低電平時間>5ms 執行按鍵消息函數
                                if(cglowVotTime>5)                 DealKeyInfo();
                        }
                }
               
#if 0          //狀態機寫法
                switch(state)
                 {
                        case S0://狀態0        等待按鍵按下
                                if(bgStatusofKey1==0)
                                        state = S1;                //判斷輸入是否為0,為0轉入狀態1       
                                break;

                        case S1://狀態1        按鍵按下
                                if(bgStatusofKey1)
                                        state = S0;                //按鍵彈起? 返回狀態0(按鍵狀態不穩定)       
                                else{                                //否則開始計時,轉入狀態2
                                        state =        S2;
                                        cgPushKeyTime = 0;
                                }break;
                                       
                        case S2://狀態2        等待短按釋放
                                if(bgStatusofKey1){

                                        state = S0;                        //按鍵彈起?返回狀態0(短按鍵釋放)
                                        bgEv1527Study = 0;
                                        cgFlagBeacon = 0x01;
                                        DealKeyInfo();
                                }
                                else if(cgPushKeyTime>250){ //長按超時?(1s以上)
                                        cgPushKeyTime = 0;
                                        bgEv1527Study = 1;                 //學習狀態。
                                        cgFlagBeacon = 0x02;
                                        DealKeyInfo();
                                        state=S3;                        //否則開始計時,計時結束轉入狀態3
                                }break;
                                               
                        case S3://狀態3        等待長按釋放
                                if(bgStatusofKey1)                 //長按鍵釋放?返回狀態0
                                        state=S0;               
                                else if(++cgPushKeyTime==5)        //否則開始計時,計時結束按鍵連擊
                                {
                                        cgPushKeyTime=0;
                                        /*連擊處理函數*/
                                }break;
                                       
                        default:
                                break;                                                       
                }
#endif
                //備份按鍵口線狀態
                bgStatusofKey1 = SWITCH_KEY1;

                if(SWITCH_KEY2==1)   
                        cgSwitchStatus |= 0x01;
                else
                        cgSwitchStatus &= 0xfe;
       
}
回復

使用道具 舉報

ID:624769 發表于 2022-5-17 18:19 | 顯示全部樓層
lkc8210 發表于 2022-5-17 17:48
代碼很巧妙,但為了一個按鍵占用了一個外中斷和一個定時器,算不上占用系統少吧?
而且只能濾掉按下那一 ...

跟你交流很開心, 以下純粹探討. 如有空盼回。

為了一個按鍵占用了一個外中斷和一個定時器,算不上占用系統少吧?
我還是那句話,如果中斷空著不用,嚴格意義上來講,不是節約資源,而是資源浪費,而且外部中斷判斷按鍵的話,按鍵未按下時,在主循環中,連1個時鐘的系統時鐘都不會占用,這還不算占用系統資源少么?

只能濾掉按下那一剎那的抖動,濾不掉放開那一剎那的抖動吧?
是的,實際上,我自己寫的代碼,不是這樣的,發上來的時候精簡了一下,正常自己使用的時候,主程序也不會有按鍵標志判斷的,代碼如下:
(另,個人愛好,非工作,所以沒有測試設備,大多功能都是自己寫代碼燒錄,然后通過LED狀態來測試驗證,你這邊方便的話可幫忙測試,實際應用中STC15以上系列,IT0 =1 時,釋放按鍵時,只要不是故意手抖,抖不出IE0=1, 即不會觸發中斷,原因不明,可能和 IT0 的判定變更了有關,你那邊有條件的話,不知能否也幫忙驗證一下?)

void EX0_INT  interrupt 0
{
         EX0 = 0;       //關外部中斷
        TR0 = 1;        //開定時器消抖

        //此處按鍵按下后的  需要執行的操作
}


sbit  INT0 = P3^2;
void T0_INT  interrupt 1
{
         if((IE0) || (!INT0))    //判斷按鍵釋放&消抖
        {
                IE0 = 0;   //繼續消抖
        }
         else
         {
                EX0 = 1;   //消抖完成,重開外部中斷
               TR0 = 0;  //關定時器
        }
}
回復

使用道具 舉報

ID:1026496 發表于 2022-5-17 21:34 | 顯示全部樓層
不是是這樣的,標準的是沒有阻塞的也就是沒有while(!key); 標準的就是一個函數返回鍵值根據當前的io 的狀態返回時按鍵值;延時用定時器的tick +狀態機實現
回復

使用道具 舉報

ID:161164 發表于 2022-5-18 10:54 | 顯示全部樓層
188610329 發表于 2022-5-17 18:19
跟你交流很開心, 以下純粹探討. 如有空盼回。

為了一個按鍵占用了一個外中斷和一個定時器,算不上占用 ...

看大佬的貼子和回貼我也學到很多東西
特別是STC EEPROM 的操作

有時間我會試一試放手進中斷的情況
回復

使用道具 舉報

ID:491577 發表于 2022-5-18 12:37 | 顯示全部樓層
這是標準菜鳥寫法,等到不用    Delay6ms(); while(!k1)這兩個語句也可以寫出按鍵程序的時候才算入門啦
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美一区二区在线观看 | 免费毛片网站在线观看 | 国产一区二区在线播放 | 成人av在线播放 | 9999视频 | 青青激情网 | 天堂精品视频 | 国产亚洲成av人片在线观看桃 | 国产精品揄拍一区二区 | 成人免费看黄网站在线观看 | 国产久 | 成人久久一区 | 91精品国产综合久久久久久丝袜 | 亚洲区一区二区 | 欧美午夜视频 | 国产又爽又黄的视频 | 五月激情综合 | 天天拍天天操 | 国产精品高清一区二区 | 亚洲福利视频网 | 亚洲综合在线视频 | 国产欧美一区二区在线观看 | 亚洲精品av在线 | 欧美在线色 | 亚洲毛片一区二区 | av中文字幕在线播放 | 中文av在线播放 | 久久久www | 亚洲高清一区二区三区 | 欧美国产日韩在线观看 | 日韩毛片| 欧美一区二区三区的 | 国产精品99久久久久久动医院 | 日韩综合在线 | 国产一区在线免费观看 | 一级毛片高清 | 天天综合久久 | 在线视频第一页 | a级免费黄色片 | 欧美激情综合五月色丁香小说 | 精品免费视频 |