找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

單片機(jī)按鍵狀態(tài)檢測程序問題,不能雙擊

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:566214 發(fā)表于 2021-9-23 22:17 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
/*      雙擊不行,10ms掃描一次,Key_Double_Period=30,不是Key_Double_Period時(shí)間的問題
         現(xiàn)在的問題是:第一次按下的時(shí)間大于Key_Double_Period,再快速按一下,就可以識(shí)別為雙擊
         但是這樣子太別扭了,雙擊應(yīng)該是再Key_Double_Period時(shí)間內(nèi),再次按下,就認(rèn)為是雙擊
         調(diào)了快一個(gè)禮拜,還是同樣的問題

*/
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空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

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

使用道具 舉報(bào)

板凳
ID:190577 發(fā)表于 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;
                                //按鍵被按下,狀態(tài)轉(zhuǎn)換到按鍵消抖和確認(rèn)狀態(tài)//
                        break;
                case key_state_1:
                        if(key == 0)
                        {
                                key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                //按鍵仍然處于按下狀態(tài)
                                //消抖完成,key_timer開始準(zhǔn)備計(jì)時(shí)
                                //狀態(tài)切換到按下時(shí)間計(jì)時(shí)狀態(tài)
                        }
                        else
                                key_state_buffer1 = key_state_0;
                                //按鍵已經(jīng)抬起,回到按鍵初始狀態(tài)
                        break;  //完成軟件消抖
                case key_state_2:
                        if(key == 1)
                        {
                                key_return = key_click;  //按鍵抬起,產(chǎn)生一次click操作
                                key_state_buffer1 = key_state_0;  //轉(zhuǎn)換到按鍵初始狀態(tài)
                        }
                        else if(++key_timer_cnt1 >= 100)  //按鍵繼續(xù)按下,計(jì)時(shí)超過1000ms
                        {
                                key_return = key_long;  //送回長按事件
                                key_state_buffer1 = key_state_3;  //轉(zhuǎn)換到等待按鍵釋放狀態(tài)
                        }
                        break;
                case key_state_3:  //等待按鍵釋放
                        if(key == 1)  //按鍵釋放
                                key_state_buffer1 = key_state_0;  //切回按鍵初始狀態(tài)
                        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;  //第一次單擊,不返回,到下個(gè)狀態(tài)判斷是否會(huì)出現(xiàn)雙擊
                                key_state_buffer2 = key_state_1;
                        }
                        else
                                key_return = key;  //對(duì)于無鍵、長按,返回原事件
                        break;
                case key_state_1:
                        if(key == key_click)  //又一次單擊,時(shí)間間隔小于500ms
                        {
                                key_return = key_double;  //返回雙擊事件,回到初始狀態(tài)
                                key_state_buffer2 = key_state_0;
                        }
                        else if(++key_timer_cnt2 >= 50)
                        {   
                        //這里在下一次的按鍵來臨之前,并且時(shí)間是小于500ms的時(shí)候,就會(huì)一直執(zhí)行的是這個(gè)key_timer_cnt2++.直到下一次的按鍵到來,再判斷看是雙擊還是單擊。
                                //這里500ms內(nèi)肯定讀到的都是無鍵事件,因?yàn)殚L按大于1000ms
                                //在1s前底層返回的都是無鍵
                                                                        
                                key_return = key_click;  //500ms內(nèi)沒有再次出現(xiàn)單擊事件,返回單擊事件
                                key_state_buffer2 = key_state_0;  //返回初始狀態(tài)
                                       
                        }
                        break;
        }
        
        return key_return;
}

void Timer0Init(void)                //1毫秒@11.0592MHz
{
        AUXR |= 0x80;                //定時(shí)器時(shí)鐘1T模式
        TMOD &= 0xF0;                //設(shè)置定時(shí)器模式
        TL0 = 0xCD;                //設(shè)置定時(shí)初值
        TH0 = 0xD4;                //設(shè)置定時(shí)初值
        TF0 = 0;                //清除TF0標(biāo)志
        TR0 = 1;                //定時(shí)器0開始計(jì)時(shí)
        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;
   }
}
回復(fù)

使用道具 舉報(bào)

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





回復(fù)

使用道具 舉報(bào)

5#
ID:332444 發(fā)表于 2021-9-24 14:36 | 只看該作者
現(xiàn)在認(rèn)為不用雙擊,用組合鍵更簡單靈活,程序設(shè)計(jì)也相對(duì)容易實(shí)現(xiàn).
回復(fù)

使用道具 舉報(bào)

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

感謝回復(fù),這個(gè)程序是觸摸按鍵的,機(jī)械按鍵是可以正常識(shí)別雙擊事件的,觸摸按鍵的庫是別提供的,只有一個(gè)接口函數(shù)
回復(fù)

使用道具 舉報(bào)

7#
ID:566214 發(fā)表于 2021-9-24 14:52 | 只看該作者
xianfajushi 發(fā)表于 2021-9-24 14:36
現(xiàn)在認(rèn)為不用雙擊,用組合鍵更簡單靈活,程序設(shè)計(jì)也相對(duì)容易實(shí)現(xiàn).

觸摸按鍵
回復(fù)

使用道具 舉報(bào)

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

感謝回復(fù),我試一下
回復(fù)

使用道具 舉報(bào)

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

只要是按鍵,不論是何種,都是可以實(shí)現(xiàn)組合鍵,有什么不能實(shí)現(xiàn)的理由?
回復(fù)

使用道具 舉報(bào)

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

設(shè)定一個(gè)比較時(shí)間,可以實(shí)現(xiàn)組合,當(dāng)然,雙擊也是.
回復(fù)

使用道具 舉報(bào)

11#
ID:624769 發(fā)表于 2021-9-24 15:47 | 只看該作者
一般情況下, 長按短按, 單擊雙擊。
這兩種區(qū)分按鍵的模式,在沒有必要的前提下,不同時(shí)使用。
因?yàn),?huì)給你的按鍵判斷復(fù)雜程度提高一個(gè)級(jí)別,如果你采取了 單擊雙擊,還嫌不夠可以增加三擊四擊,沒必要再去搞長按。一個(gè)鍵也就算了,鍵多了,你的按鍵判斷邏輯會(huì)變得及其混亂,因?yàn)橐坏可娴介L按和雙擊,那么你必須考慮,第二擊你達(dá)到了長按標(biāo)準(zhǔn)的話,到底算,長按,還是雙擊。諸如此類各種麻煩。
回復(fù)

使用道具 舉報(bào)

12#
ID:566214 發(fā)表于 2021-9-24 19:16 | 只看該作者
xianfajushi 發(fā)表于 2021-9-24 15:44
設(shè)定一個(gè)比較時(shí)間,可以實(shí)現(xiàn)組合,當(dāng)然,雙擊也是.

狀態(tài)機(jī)的邏輯可以實(shí)現(xiàn)嗎?我同時(shí)檢測5顆按鍵
回復(fù)

使用道具 舉報(bào)

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

邏輯不會(huì)很亂,因?yàn)橐淮沃荒軝z測一個(gè)按鍵
回復(fù)

使用道具 舉報(bào)

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

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

使用道具 舉報(bào)

15#
ID:332444 發(fā)表于 2021-9-24 19:25 | 只看該作者
dcjdcj 發(fā)表于 2021-9-24 19:16
狀態(tài)機(jī)的邏輯可以實(shí)現(xiàn)嗎?我同時(shí)檢測5顆按鍵

可以,在一定時(shí)間范圍內(nèi)對(duì)按鍵進(jìn)行計(jì)算得值即可實(shí)現(xiàn)組合,計(jì)數(shù)可實(shí)現(xiàn)雙擊,也可實(shí)現(xiàn)按次數(shù),這樣寫起來很方便。
回復(fù)

使用道具 舉報(bào)

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

比如,在一段時(shí)間內(nèi),第一次按下的鍵值是0x80,第二次按下的鍵值是0x01,然后將這兩個(gè)值相或,得到0x81,用0x81區(qū)判斷是不是組合鍵嗎?
回復(fù)

使用道具 舉報(bào)

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

回復(fù)

使用道具 舉報(bào)

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

還有一個(gè)問題,一個(gè)無源蜂鳴器,比如4k頻率,定時(shí)器中斷125us,要怎么驅(qū)動(dòng),可否來個(gè)例程,謝謝了
回復(fù)

使用道具 舉報(bào)

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

中斷里面一句話

Beep_IO = !Beep_IO;
回復(fù)

使用道具 舉報(bào)

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

Beep_IO = !Beep_IO;

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

使用道具 舉報(bào)

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

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

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

使用道具 舉報(bào)

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

好的,謝謝指教,我試一下
回復(fù)

使用道具 舉報(bào)

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

觸摸按鍵的,不行,波動(dòng)按鍵就可以
回復(fù)

使用道具 舉報(bào)

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

本版積分規(guī)則

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

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

快速回復(fù) 返回頂部 返回列表