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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3154|回復: 22
打印 上一主題 下一主題
收起左側

單片機按鍵狀態檢測程序問題,不能雙擊

[復制鏈接]
跳轉到指定樓層
樓主
ID:566214 發表于 2021-9-23 22:17 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
/*      雙擊不行,10ms掃描一次,Key_Double_Period=30,不是Key_Double_Period時間的問題
         現在的問題是:第一次按下的時間大于Key_Double_Period,再快速按一下,就可以識別為雙擊
         但是這樣子太別扭了,雙擊應該是再Key_Double_Period時間內,再次按下,就認為是雙擊
         調了快一個禮拜,還是同樣的問題

*/
uchar Key_Read(void)
{
        static uchar key_state_buffer=key_state_0;
        static uchar key_timer_cnt=0;
        static uchar key_temp=Key_Null;
        uchar key_return=Key_Null;
        uchar key=Key_Null;
        key=Key_Null|Key_Driver();
        switch(key_state_buffer)
        {
                case key_state_0:
                        if(key!=Key_Null)
                        {
                                key_temp=key;
                                key_timer_cnt=0;
                                key_state_buffer=key_state_1;
                        }
                        else
                        {
                                key_return=key;
                        }
                        break;
                case key_state_1:
                        if(key!=Key_Null)
                        {
                                key_return=key|Key_Double;
                                key_state_buffer=key_state_0;
                        }
                        else if(++key_timer_cnt>=Key_Double_Period)
                        {
                                key_return=key_temp;
                                key_state_buffer=key_state_0;
                                key_timer_cnt=0;
                        }
                        break;
        }
        return key_return;
}

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

使用道具 舉報

沙發
ID:566214 發表于 2021-9-23 22:21 | 只看該作者
Key_Null=0x00;Key_Driver()這個函數返回值是單擊的值和長按得值
回復

使用道具 舉報

板凳
ID:190577 發表于 2021-9-24 06:48 | 只看該作者
#include<stc15w202s.h>
#include<stdio.h>
#define key_state_0 0
#define key_state_1 1
#define key_state_2 2
#define key_state_3 3
#define key_no 0
#define key_click 1
#define key_double 2
#define key_long 3
sbit KEY = P3^3;
sbit LED_E1P = P3^1;
sbit LED_G1 = P3^2;
sbit LED2 = P5^5;        //W2OUT
sbit LED3 = P5^4;  
unsigned char flag;
unsigned char cnt = 0;


static unsigned char key_driver(void)
{
        static unsigned char key_state_buffer1 = key_state_0;
        static unsigned char key_timer_cnt1 = 0;
        unsigned char key_return = key_no;
        unsigned char key;
        
        key = KEY;  //read the I/O states
        
        switch(key_state_buffer1)
        {
                case key_state_0:
                        if(key == 0)
                                key_state_buffer1 = key_state_1;
                                //按鍵被按下,狀態轉換到按鍵消抖和確認狀態//
                        break;
                case key_state_1:
                        if(key == 0)
                        {
                                key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                //按鍵仍然處于按下狀態
                                //消抖完成,key_timer開始準備計時
                                //狀態切換到按下時間計時狀態
                        }
                        else
                                key_state_buffer1 = key_state_0;
                                //按鍵已經抬起,回到按鍵初始狀態
                        break;  //完成軟件消抖
                case key_state_2:
                        if(key == 1)
                        {
                                key_return = key_click;  //按鍵抬起,產生一次click操作
                                key_state_buffer1 = key_state_0;  //轉換到按鍵初始狀態
                        }
                        else if(++key_timer_cnt1 >= 100)  //按鍵繼續按下,計時超過1000ms
                        {
                                key_return = key_long;  //送回長按事件
                                key_state_buffer1 = key_state_3;  //轉換到等待按鍵釋放狀態
                        }
                        break;
                case key_state_3:  //等待按鍵釋放
                        if(key == 1)  //按鍵釋放
                                key_state_buffer1 = key_state_0;  //切回按鍵初始狀態
                        break;
        }
        return key_return;
}

unsigned char key_read(void)
{
        static unsigned char key_state_buffer2 = key_state_0;
        static unsigned char key_timer_cnt2 = 0;
        unsigned char key_return = key_no;
        unsigned char key;
        
        key = key_driver();
        
        switch(key_state_buffer2)
        {
                case key_state_0:
                        if(key == key_click)
                        {
                                key_timer_cnt2 = 0;  //第一次單擊,不返回,到下個狀態判斷是否會出現雙擊
                                key_state_buffer2 = key_state_1;
                        }
                        else
                                key_return = key;  //對于無鍵、長按,返回原事件
                        break;
                case key_state_1:
                        if(key == key_click)  //又一次單擊,時間間隔小于500ms
                        {
                                key_return = key_double;  //返回雙擊事件,回到初始狀態
                                key_state_buffer2 = key_state_0;
                        }
                        else if(++key_timer_cnt2 >= 50)
                        {   
                        //這里在下一次的按鍵來臨之前,并且時間是小于500ms的時候,就會一直執行的是這個key_timer_cnt2++.直到下一次的按鍵到來,再判斷看是雙擊還是單擊。
                                //這里500ms內肯定讀到的都是無鍵事件,因為長按大于1000ms
                                //在1s前底層返回的都是無鍵
                                                                        
                                key_return = key_click;  //500ms內沒有再次出現單擊事件,返回單擊事件
                                key_state_buffer2 = key_state_0;  //返回初始狀態
                                       
                        }
                        break;
        }
        
        return key_return;
}

void Timer0Init(void)                //1毫秒@11.0592MHz
{
        AUXR |= 0x80;                //定時器時鐘1T模式
        TMOD &= 0xF0;                //設置定時器模式
        TL0 = 0xCD;                //設置定時初值
        TH0 = 0xD4;                //設置定時初值
        TF0 = 0;                //清除TF0標志
        TR0 = 1;                //定時器0開始計時
        ET0 = 1;

}
void IO_init()
{
   
    P3M0 = 0x01;
    P3M1 = 0x01;
    P5M0 = 0x00;
    P5M1 = 0x00;
   
}


void main(void)
{         
       unsigned char key = 1;
             Timer0Init();
           IO_init();
           LED_E1P = 1;
           LED_G1 = 1;
           LED2 = 1;
           LED3 = 0;
                   EA = 1;
           while(1)
           {
             if(flag)
                 {
                   flag=0;
           key = key_read();
                   switch(key)
                   {
                            case key_click:LED2 = !LED2; break;
                         case key_double:LED2 = !LED2;LED3 = !LED3; break;
                         case key_long: LED2 = 1; LED3 = 1; LED_G1 = 0; LED_E1P = 0; break;
                         default : break;
                   }
                 }
           }
}

void Timr0_ISR() interrupt 1
{
   cnt++;
   if(cnt>=10)
   {
       cnt = 0;
              flag = 1;
   }
}
回復

使用道具 舉報

地板
ID:123289 發表于 2021-9-24 08:52 | 只看該作者
1、按鍵有彈動,如果沒有防彈動過慮則,則無法界定按了幾下(按一下,彈N次)。
2、防彈動的過慮時間,既要能慮除彈動時間,又不能錯將雙擊過慮掉。這就要求過慮時間設置適當。
建議過慮時間設置為32ms。
3、為了能識別按了幾次,就需要有一個計數器JN。
4、JN何時起計,何時結束,也是有講究的。JN計數完成之前,你不要做界定,因為還不確定是連續按了幾次。
建議的做法是:雙擊的間隔時間定義為:0.08-0.6秒之間。
界定開始時間(JN計數結束時間):這個0.6秒就是JN界定的時間,它的意思是:當按鍵彈起后0.6秒后,開始界定JN。這時JN=幾,就是連續擊鍵幾次。
如此:無論連續擊幾次都能識別。
短按:JN=1
雙擊:JN=2。
N擊:JN=N。
JN計時的開始時間(復0):JN被識別后,就清0,準備下次使用。當然,初始化也清0。
由于涉及多種計時,所以,建議做個定時中斷,如4ms中斷一次,中斷服務程序中做以下事件:
1、掃鍵:
彈動過慮計時器JT:
鍵按下時:+1,本次鍵值THIS_KEY與上次鍵值LAST_KEY不同時清0(不同,就是彈動),相同時+1。>8時(彈動過慮時間)不再增加。
彈起時界定:JT>=8時(32ms),鍵值有效(可以做個標記:KEY_P=1),即認為按了一次。
2、擊鍵次數界定計時器JC:
鍵按下時:+1,>150(0.6秒)時不再增加。
彈起時界定:JC>=150時(600ms),去界定JN。隨即將JC清0。
3、擊鍵次數JN:
鍵值被認定有效(KEY_P=1)時+1,>多少時不再增加,自己去定。將KEY_P清0。





回復

使用道具 舉報

5#
ID:332444 發表于 2021-9-24 14:36 | 只看該作者
現在認為不用雙擊,用組合鍵更簡單靈活,程序設計也相對容易實現.
回復

使用道具 舉報

6#
ID:566214 發表于 2021-9-24 14:51 | 只看該作者
bbxyliyang 發表于 2021-9-24 06:48
#include
#include
#define key_state_0 0

感謝回復,這個程序是觸摸按鍵的,機械按鍵是可以正常識別雙擊事件的,觸摸按鍵的庫是別提供的,只有一個接口函數
回復

使用道具 舉報

7#
ID:566214 發表于 2021-9-24 14:52 | 只看該作者
xianfajushi 發表于 2021-9-24 14:36
現在認為不用雙擊,用組合鍵更簡單靈活,程序設計也相對容易實現.

觸摸按鍵
回復

使用道具 舉報

8#
ID:566214 發表于 2021-9-24 14:52 | 只看該作者
yzwzfyz 發表于 2021-9-24 08:52
1、按鍵有彈動,如果沒有防彈動過慮則,則無法界定按了幾下(按一下,彈N次)。
2、防彈動的過慮時間,既 ...

感謝回復,我試一下
回復

使用道具 舉報

9#
ID:332444 發表于 2021-9-24 15:36 | 只看該作者

只要是按鍵,不論是何種,都是可以實現組合鍵,有什么不能實現的理由?
回復

使用道具 舉報

10#
ID:332444 發表于 2021-9-24 15:44 | 只看該作者

設定一個比較時間,可以實現組合,當然,雙擊也是.
回復

使用道具 舉報

11#
ID:624769 發表于 2021-9-24 15:47 | 只看該作者
一般情況下, 長按短按, 單擊雙擊。
這兩種區分按鍵的模式,在沒有必要的前提下,不同時使用。
因為,會給你的按鍵判斷復雜程度提高一個級別,如果你采取了 單擊雙擊,還嫌不夠可以增加三擊四擊,沒必要再去搞長按。一個鍵也就算了,鍵多了,你的按鍵判斷邏輯會變得及其混亂,因為一旦牽涉到長按和雙擊,那么你必須考慮,第二擊你達到了長按標準的話,到底算,長按,還是雙擊。諸如此類各種麻煩。
回復

使用道具 舉報

12#
ID:566214 發表于 2021-9-24 19:16 | 只看該作者
xianfajushi 發表于 2021-9-24 15:44
設定一個比較時間,可以實現組合,當然,雙擊也是.

狀態機的邏輯可以實現嗎?我同時檢測5顆按鍵
回復

使用道具 舉報

13#
ID:566214 發表于 2021-9-24 19:19 | 只看該作者
188610329 發表于 2021-9-24 15:47
一般情況下, 長按短按, 單擊雙擊。
這兩種區分按鍵的模式,在沒有必要的前提下,不同時使用。
因為, ...

邏輯不會很亂,因為一次只能檢測一個按鍵
回復

使用道具 舉報

14#
ID:566214 發表于 2021-9-24 19:24 | 只看該作者
yzwzfyz 發表于 2021-9-24 08:52
1、按鍵有彈動,如果沒有防彈動過慮則,則無法界定按了幾下(按一下,彈N次)。
2、防彈動的過慮時間,既 ...

每次單擊都可以檢測到,就是雙擊不行
回復

使用道具 舉報

15#
ID:332444 發表于 2021-9-24 19:25 | 只看該作者
dcjdcj 發表于 2021-9-24 19:16
狀態機的邏輯可以實現嗎?我同時檢測5顆按鍵

可以,在一定時間范圍內對按鍵進行計算得值即可實現組合,計數可實現雙擊,也可實現按次數,這樣寫起來很方便。
回復

使用道具 舉報

16#
ID:566214 發表于 2021-9-24 20:14 | 只看該作者
xianfajushi 發表于 2021-9-24 19:25
可以,在一定時間范圍內對按鍵進行計算得值即可實現組合,計數可實現雙擊,也可實現按次數,這樣寫起來很 ...

比如,在一段時間內,第一次按下的鍵值是0x80,第二次按下的鍵值是0x01,然后將這兩個值相或,得到0x81,用0x81區判斷是不是組合鍵嗎?
回復

使用道具 舉報

17#
ID:332444 發表于 2021-9-24 20:45 | 只看該作者
dcjdcj 發表于 2021-9-24 20:14
比如,在一段時間內,第一次按下的鍵值是0x80,第二次按下的鍵值是0x01,然后將這兩個值相或,得到0x81, ...

回復

使用道具 舉報

18#
ID:566214 發表于 2021-9-24 21:13 | 只看該作者

還有一個問題,一個無源蜂鳴器,比如4k頻率,定時器中斷125us,要怎么驅動,可否來個例程,謝謝了
回復

使用道具 舉報

19#
ID:624769 發表于 2021-9-24 21:28 | 只看該作者
dcjdcj 發表于 2021-9-24 21:13
還有一個問題,一個無源蜂鳴器,比如4k頻率,定時器中斷125us,要怎么驅動,可否來個例程,謝謝了

中斷里面一句話

Beep_IO = !Beep_IO;
回復

使用道具 舉報

20#
ID:566214 發表于 2021-9-24 21:52 | 只看該作者
188610329 發表于 2021-9-24 21:28
中斷里面一句話

Beep_IO = !Beep_IO;

Beep_IO = ~Beep_IO;不是這個嗎?那么響一聲要怎么寫,要多久才算一聲
回復

使用道具 舉報

21#
ID:624769 發表于 2021-9-24 22:12 | 只看該作者
dcjdcj 發表于 2021-9-24 21:52
Beep_IO = ~Beep_IO;不是這個嗎?那么響一聲要怎么寫,要多久才算一聲

一般,習慣上,  字節 用  ~ 取反, 位 用 !取反。 至少 別人看到我寫的那一行一眼就能知道 Beep_IO 是個位地址。

最后,響一聲,看你打算 長響還是短響, 長響一般 1.5 秒, 短響一般 0.3 秒,(習慣上)。
回復

使用道具 舉報

22#
ID:566214 發表于 2021-9-24 23:16 | 只看該作者
188610329 發表于 2021-9-24 22:12
一般,習慣上,  字節 用  ~ 取反, 位 用 !取反。 至少 別人看到我寫的那一行一眼就能知道 Beep_IO 是 ...

好的,謝謝指教,我試一下
回復

使用道具 舉報

23#
ID:566214 發表于 2021-9-25 19:50 | 只看該作者
bbxyliyang 發表于 2021-9-24 06:48
#include
#include
#define key_state_0 0

觸摸按鍵的,不行,波動按鍵就可以
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 一区二区三区四区在线 | 日韩午夜精品 | 天天干天天干 | 国产区视频在线观看 | 久久一二区 | 久久久久久久综合 | 亚洲精品乱码久久久久v最新版 | 日韩视频在线一区 | 亚洲成人毛片 | 国产日韩欧美一区二区在线播放 | www.亚洲国产精品 | 亚洲欧洲精品成人久久奇米网 | 欧美日韩国产一区二区三区 | 国产乱码精品一区二区三区五月婷 | 一区二区三区在线免费观看 | 91偷拍精品一区二区三区 | 亚洲成人免费电影 | 久久福利电影 | 黄久久久 | 偷拍亚洲色图 | h视频免费看 | 国产91av视频在线观看 | 日韩一区二区在线视频 | 国产精品精品 | 国产玖玖 | 中文字幕视频免费 | 亚洲国产成人精品久久 | 国产96色在线 | 污视频免费在线观看 | 国产综合久久 | 欧美一区二区在线 | 成人动慢 | 日韩精品久久久久 | 久久精品视频一区二区三区 | 中文字幕在线观看日韩 | 免费日韩av | av官网在线 | 草草草网站 | 欧美精品一区在线 | 2020亚洲天堂 | 欧美日韩久 |