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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

求程序思路 單片機按鍵次數控制流水燈

[復制鏈接]
跳轉到指定樓層
樓主
ID:895128 發表于 2021-4-7 22:51 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
由于本論壇禁止直接求程序,禁止伸手黨,所以向大家請教一下大致的實現方法與思路,理清頭緒后我自己來寫程序去實現,謝謝大家

例如按一下全亮,連續按兩下流水燈,連續三下換一種流水燈。
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:895128 發表于 2021-4-7 22:53 | 只看該作者
我暫時的思路是定時計數,定時3s內統計按鍵次數在用按鍵次數去控制不同的燈動作。但是這樣的話會有很大的延遲,每次都要等3s才會停止計數的話。太浪費時間了。
回復

使用道具 舉報

板凳
ID:752974 發表于 2021-4-8 08:35 | 只看該作者
對按鍵計數就可以,1全亮,2流水,3換一個流水,并清零變量。

評分

參與人數 1黑幣 +20 收起 理由
admin + 20 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

地板
ID:584814 發表于 2021-4-8 08:36 | 只看該作者
Dieouy 發表于 2021-4-7 22:53
我暫時的思路是定時計數,定時3s內統計按鍵次數在用按鍵次數去控制不同的燈動作。但是這樣的話會有很大的延 ...

那么問題來了:你按了1次或2次后怎么才知道你不是要按3次呢 ?

評分

參與人數 1黑幣 +20 收起 理由
admin + 20 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

5#
ID:592807 發表于 2021-4-8 08:48 | 只看該作者
Dieouy 發表于 2021-4-7 22:53
我暫時的思路是定時計數,定時3s內統計按鍵次數在用按鍵次數去控制不同的燈動作。但是這樣的話會有很大的延 ...

3S?你這個東西是給老年人用的?你自己用個計時器算一下3S你能按多少下按鍵,連續按鍵間隔超過0.5秒都不叫連續。得到按鍵信號0.5秒內,沒有下一個按鍵信號就可以處理了

評分

參與人數 1黑幣 +20 收起 理由
admin + 20 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

6#
ID:487569 發表于 2021-4-8 09:40 | 只看該作者
思路就是松開按鍵執行動作。判斷到按鍵按下,先暫存按鍵的鍵值,按下次數+1,然后給一個變量賦值用作延時判斷。等到判斷按鍵松開延時就開始倒計,倒計為0的時候,把暫存的鍵值取出來,并執行判斷是哪個按鍵,按下幾次。

評分

參與人數 1黑幣 +20 收起 理由
admin + 20 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

7#
ID:895128 發表于 2021-4-8 10:40 | 只看該作者
unsigned char key_read(void)
{
    static unsigned char key_m = key_state_0, key_time_1 = 0;
    unsigned char key_return = N_key,key_temp;
     
    key_temp = key_driver();
     
    switch(key_m)
    {
        case key_state_0:
            if (key_temp == S_key )
            {
                 key_time_1 = 0;               // 第1次單擊,不返回,到下個狀態判斷后面是否出現雙擊
                 key_m = key_state_1;
            }
            else
                 key_return = key_temp;        // 對于無鍵、長鍵,返回原事件
            break;

        case key_state_1:
            if (key_temp == S_key)             // 又一次單擊(間隔肯定<500ms)
            {
                 key_return = D_key;           // 返回雙擊鍵事件,回初始狀態
                 key_m = key_state_0;
            }
            else                                
            {                                  // 這里500ms內肯定讀到的都是無鍵事件,因為長鍵>1000ms,在1s前低層返回的都是無鍵
                 if(++key_time_1 >= 50)
                 {
                      key_return = S_key;      // 500ms內沒有再次出現單鍵事件,返回上一次的單鍵事件
                      key_m = key_state_0;     // 返回初始狀態
                 }
             }
             break;
    }
    return key_return;
}     



這個怎么添加第n次的判斷啊
回復

使用道具 舉報

8#
ID:895128 發表于 2021-4-8 11:03 | 只看該作者
已經做出來了,謝謝各位大佬。



#include<reg52.h>
#define N_key    0              //無鍵
#define S_key    1              //單鍵
#define D_key    2              //雙鍵
#define L_key    3              //長鍵
#define C_key    4              //三擊鍵
#define E_key    5              //四擊鍵
#define key_state_0 0
#define key_state_1 1
#define key_state_2 2
#define key_state_3 3
#define key_state_4 4
#define key_state_5 5
sbit key_input = P2^0;    // 按鍵輸入口
unsigned char time_10ms_ok = 0;
unsigned char key = 0;

unsigned char key_driver(void)
{
    static unsigned char key_state = key_state_0, key_time = 0;
    unsigned char  key_return = N_key;
        bit key_press;

    key_press = key_input;                    // 讀按鍵I/O電平

    switch (key_state)
    {
      case key_state_0:                              // 按鍵初始態
        if (!key_press) key_state = key_state_1;      // 鍵被按下,狀態轉換到按鍵消抖和確認狀態
        break;
      
      case key_state_1:                      // 按鍵消抖與確認態
        if (!key_press)
        {
             key_time = 0;                   //  
             key_state = key_state_2;   // 按鍵仍然處于按下,消抖完成,狀態轉換到按下鍵時間的計時狀態,但返回的還是無鍵事件
        }
        else
             key_state = key_state_0;   // 按鍵已抬起,轉換到按鍵初始態。此處完成和實現軟件消抖,其實按鍵的按下和釋放都在此消抖的。
        break;
      
      case key_state_2:
        if(key_press)
        {
             key_return = S_key;        // 此時按鍵釋放,說明是產生一次短操作,回送S_key
             key_state = key_state_0;   // 轉換到按鍵初始態
        }
        else if (++key_time >= 100)     // 繼續按下,計時加10ms(10ms為本函數循環執行間隔)
        {
             key_return = L_key;        // 按下時間>1000ms,此按鍵為長按操作,返回長鍵事件
             key_state = key_state_3;   // 轉換到等待按鍵釋放狀態
        }
        break;

      case key_state_3:                 // 等待按鍵釋放狀態,此狀態只返回無按鍵事件
        if (key_press) key_state = key_state_0; //按鍵已釋放,轉換到按鍵初始態
        break;
    }
    return key_return;
}

/*=============
中間層按鍵處理函數,調用低層函數一次,處理雙擊事件的判斷,返回上層正確的無鍵、單鍵、雙鍵、長鍵4個按鍵事件。
本函數由上層循環調用,間隔10ms
===============*/

unsigned char key_read(void)
{
    static unsigned char key_m = key_state_0, key_time_1 = 0;
    unsigned char key_return = N_key,key_temp;
     
    key_temp = key_driver();
     
    switch(key_m)
    {
        case key_state_0:
            if (key_temp == S_key )
            {
                 key_time_1 = 0;               // 第1次單擊,不返回,到下個狀態判斷后面是否出現雙擊
                 key_m = key_state_1;
            }
            else
                 key_return = key_temp;        // 對于無鍵、長鍵,返回原事件
            break;

        case key_state_1:
            if (key_temp == S_key)             // 又一次單擊(間隔肯定<500ms)
         
                                                
            {   if( key_temp == S_key)
               
                                                         {
                 key_time_1 = 0;               // 第1次單擊,不返回,到下個狀態判斷后面是否出現雙擊
                 key_m = key_state_4;
               }
                                                        
                                                         else
                                                                          { key_return = D_key;           // 返回雙擊鍵事件,回初始狀態
                     key_m = key_state_0; }
                                                                 
            }
            else                                
            {                                  // 這里500ms內肯定讀到的都是無鍵事件,因為長鍵>1000ms,在1s前低層返回的都是無鍵
                 if(++key_time_1 >= 50)
                 {
                      key_return = S_key;      // 500ms內沒有再次出現單鍵事件,返回上一次的單鍵事件
                      key_m = key_state_0;     // 返回初始狀態
                 }
             }
             break;
       case key_state_4:
            if (key_temp == S_key)             // 又一次單擊(間隔肯定<500ms)
         
                                                
            {   if( key_temp == S_key)
               
                                                         {
                 key_time_1 = 0;               // 第1次單擊,不返回,到下個狀態判斷后面是否出現雙擊
                 key_m = key_state_5;
               }
                                                        
                                                         else
                                                                          { key_return = C_key;           // 返回雙擊鍵事件,回初始狀態
                     key_m = key_state_0; }
                                                                 
            }
            else                                
            {                                  // 這里500ms內肯定讀到的都是無鍵事件,因為長鍵>1000ms,在1s前低層返回的都是無鍵
                 if(++key_time_1 >= 50)
                 {
                      key_return = D_key;      // 500ms內沒有再次出現單鍵事件,返回上一次的單鍵事件
                      key_m = key_state_0;     // 返回初始狀態
                 }
             }
             break;
                        case key_state_5:
            if (key_temp == S_key)             // 又一次單擊(間隔肯定<500ms)
            {
                 key_return = E_key;           // 返回四擊鍵事件,回初始狀態
                 key_m = key_state_0;
            }
            else                                
            {                                  // 這里500ms內肯定讀到的都是無鍵事件,因為長鍵>1000ms,在1s前低層返回的都是無鍵
                 if(++key_time_1 >= 50)
                 {
                      key_return = C_key;      // 500ms內沒有再次出現單鍵事件,返回上一次的單鍵事件
                      key_m = key_state_0;     // 返回初始狀態
                 }
             }
             break;



     }
               
                return key_return;
}     

void main()
{
        P0 = 0xff;        //IO口初始化
        P2 = 0xff;
                        //定時器的初始化                                                   
        TMOD = 0x01;                           //選擇定時器的工作模式:定時器0,方式1
        TH0 = (65535 - 10000)/256; //定時器的初值
        TL0 = (65535 - 10000)%256;
        EA = 1;                                           //開打總中斷使能
        ET0 = 1;                                   //打開定時器0 的使能
        TR0 = 1;                                   //打開定時器0 ,開始工作

        while(1)
        {
                if(time_10ms_ok)          //time_10ms_ok = 1,表示計時到了10MS。(10MS掃描一次按鍵)
                {
                        time_10ms_ok = 0; //清除計時10MS標志
                        key = key_read(); //調用掃描按鍵程序,返回一個鍵值

                        if (key == L_key) //長按:點亮P1口上的8個LED燈。(低電平點亮)
                        {
                                P0 = 0x00;
                        }  
            else if(key == D_key)//雙擊:點亮P1口上第二個LED燈。(低電平點亮)  
            {
                                P0 = 0xfd;
                        }  
            else if(key == S_key)//單擊:點亮P1口上第一個LED燈。(低電平點亮)  
            {
                                P0 = 0xfe;
                        }
                              else if(key == C_key)//單擊:點亮P1口上第1個和第二個LED燈。(低電平點亮)  
            {
                                P0 = 0xfc;//11111100
                        }
                              else if(key == E_key)//單擊:點亮P1口上第1個和第二個LED燈。(低電平點亮)  
            {
                                P0 = 0xf0;//11110000
                        }
                }
        }
}

void timer0(void) interrupt 1        //用的是定時器0, 這個“interrupt 1”中的“1”代表1號中斷即是定時器0中斷。如果是“0”就是外部中斷0;“2“=外部中斷1;”3“定時器1中斷;”4“=串行口中斷
{
        TH0 = (65535 - 10000)/256;
        TL0 = (65535 - 10000)%256; //定時器0的方式1,得在中斷程序中重復初值。
        time_10ms_ok = 1;  //定時10MS 的標志
}

在原代碼基礎上修改      原代碼鏈接:https://blog.csdn.net/Sun19910114/article/details/53810110
回復

使用道具 舉報

9#
ID:451718 發表于 2021-4-8 12:04 | 只看該作者
本帖最后由 robinsonlin 于 2021-4-8 13:54 編輯

1,在1ms定時器中斷里面建一個 unsigned long SysTick++;
2,當檢測到按鍵響應時,變量TKey = SysTick,采集此時的系統時鐘,同時KeyCount變量+1;
3,在SysTick - Tkey<=1500時,如果還有按鍵響應,就KeyCount++;
4,當SysTick - TKey>1500時,執行switch(KeyCount), break后KeyCount變量清零。
附長短周期判斷,長短周期判斷,實際是檢測按鍵的連續性, 需要再加一個10ms的定時器做按鍵判斷。在10ms定時器中,設定按鍵檢測標志,并記錄SysTick,如按下時,TFlag = 1; KeyDelay = SysTick;這個操作記得加鎖,只執行一次。 當檢測到按鍵彈起,TFlag = 0;  然后判斷 SysTick - KeyDelay是否大于500,如果大于就是長按鍵,KeyCount += 10;如果SysTick - KeyDelay小于500ms,就是短按鍵,KeyCount ++ ;  KeyCount 十位就是長按次數,個位是短按次數。   SysTick - Tkey > 1500時,記得清理keyCount。

評分

參與人數 1黑幣 +20 收起 理由
admin + 20 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

10#
ID:47286 發表于 2021-4-8 12:32 | 只看該作者
用一個變量當計數器 每按一下按鍵 計數器+一次 然后判斷變量值 運行對應的部分 大致框架如下 細節還需要補上 比如防抖什么的

if(key==1)
{
keynum++;
if(keynum==10)
{
keynum=0;//假設10種流水方式
}
}

if(keynum==0)
{
停止流水或關燈
}
else if(keynum==1)
{
流水1
}
else if(........)
{

}

評分

參與人數 1黑幣 +20 收起 理由
admin + 20 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

11#
ID:895128 發表于 2021-4-8 13:13 | 只看該作者
這個問題解決的,現在新的問題是通過按鍵

比如按鍵中間間隔延時實現兩長一短,或者兩短一長這樣的判斷。

暫時思路是通過延時來實現:
檢測按鍵是否按下,按下后等待500ms又按下后在等待1000ms后按下就是兩短一長。兩長一短同理,但是實現起來有一個代碼我有點蒙蔽。

評分

參與人數 1黑幣 +20 收起 理由
admin + 20 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

12#
ID:895128 發表于 2021-4-8 13:13 | 只看該作者
dzbj 發表于 2021-4-8 12:32
用一個變量當計數器 每按一下按鍵 計數器+一次 然后判斷變量值 運行對應的部分 大致框架如下 細節還需要補 ...

這個實現的不是連續按鍵,是每一次按鍵對應的事件吧。
回復

使用道具 舉報

13#
ID:895128 發表于 2021-4-8 14:31 | 只看該作者
突然想,能不能用按鍵中間時間間隔實現莫爾斯電碼的輸入。
回復

使用道具 舉報

14#
ID:895128 發表于 2021-4-8 14:51 | 只看該作者
#include<reg52.h>
#define N_key    0              //無鍵
#define S_key    1              //單鍵
#define D_key    2              //雙鍵
#define L_key    3              //長鍵
#define C_key    4              //三擊鍵
#define E_key    5              //四擊鍵
#define F_key    6              //兩短一長擊建
#define key_state_0 0
#define key_state_1 1
#define key_state_2 2
#define key_state_3 3
#define key_state_4 4
#define key_state_5 5
sbit key_input = P2^0;    // 按鍵輸入口
unsigned char time_10ms_ok = 0;
unsigned char key = 0;

unsigned char key_driver(void)
{
    static unsigned char key_state = key_state_0, key_time = 0;
    unsigned char  key_return = N_key;
        bit key_press;

    key_press = key_input;                    // 讀按鍵I/O電平

    switch (key_state)
    {
      case key_state_0:                              // 按鍵初始態
        if (key_press) key_state = key_state_1;      // 鍵被按下,狀態轉換到按鍵消抖和確認狀態
        break;
      
      case key_state_1:                      // 按鍵消抖與確認態
        if (key_press)
        {
             key_time = 0;                   //  
             key_state = key_state_2;   // 按鍵仍然處于按下,消抖完成,狀態轉換到按下鍵時間的計時狀態,但返回的還是無鍵事件
        }
        else
             key_state = key_state_0;   // 按鍵已抬起,轉換到按鍵初始態。此處完成和實現軟件消抖,其實按鍵的按下和釋放都在此消抖的。
        break;
      
      case key_state_2:
        if(!key_press)
        {
             key_return = S_key;        // 此時按鍵釋放,說明是產生一次短操作,回送S_key
             key_state = key_state_0;   // 轉換到按鍵初始態
        }
        else if (++key_time >= 100)     // 繼續按下,計時加10ms(10ms為本函數循環執行間隔)
        {
             key_return = L_key;        // 按下時間>1000ms,此按鍵為長按操作,返回長鍵事件
             key_state = key_state_3;   // 轉換到等待按鍵釋放狀態
        }
        break;

      case key_state_3:                 // 等待按鍵釋放狀態,此狀態只返回無按鍵事件
        if (!key_press) key_state = key_state_0; //按鍵已釋放,轉換到按鍵初始態
        break;
    }
    return key_return;
}

/*=============
中間層按鍵處理函數,調用低層函數一次,處理雙擊事件的判斷,返回上層正確的無鍵、單鍵、雙鍵、長鍵4個按鍵事件。
本函數由上層循環調用,間隔10ms
===============*/

unsigned char key_read(void)
{
    static unsigned char key_m = key_state_0, key_time_1 = 0;
    unsigned char key_return = N_key,key_temp;
     
    key_temp = key_driver();
     
    switch(key_m)
    {
         case key_state_0:
            if (key_temp == S_key )
            {
                 key_time_1 = 0;               // 第1次單擊,不返回,到下個狀態判斷后面是否出現雙擊
                 key_m = key_state_1;
            }
            else
                 key_return = key_temp;        // 對于無鍵、長鍵,返回原事件
            break;

          case key_state_1:
            if (key_temp == S_key)             // 又一次單擊(間隔肯定<500ms)
            {
                 key_return = D_key;           // 返回雙擊鍵事件,回初始狀態
                 key_m = key_state_0;
            }
            else                                
            {                                  // 這里500ms內肯定讀到的都是無鍵事件,因為長鍵>1000ms,在1s前低層返回的都是無鍵
                 if(++key_time_1 >= 50&&++key_time_1 <= 75)
                 {
                      key_return = E_key;      // 500ms內沒有再次出現單鍵事件,返回上一次的單鍵事件
                      key_m = key_state_0;     // 返回初始狀態
                 }
                 else
                                                                         if(++key_time_1 >= 75)

                 {
                      key_return = S_key;      // 500ms內沒有再次出現單鍵事件,返回上一次的單鍵事件
                      key_m = key_state_0;     // 返回初始狀態
                 }

            }
                                                 
                                                 
                                                 
             break;
               
                return key_return;
}     

void main()
{
        P0 = 0xff;        //IO口初始化
        P2 = 0x00;  //定時器的初始化                                                  
        TMOD = 0x01;                           //選擇定時器的工作模式:定時器0,方式1
        TH0 = (65535 - 10000)/256; //定時器的初值
        TL0 = (65535 - 10000)%256;
        EA = 1;                                           //開打總中斷使能
        ET0 = 1;                                   //打開定時器0 的使能
        TR0 = 1;                                   //打開定時器0 ,開始工作

        while(1)
        {
                if(time_10ms_ok)          //time_10ms_ok = 1,表示計時到了10MS。(10MS掃描一次按鍵)
                {
                        time_10ms_ok = 0; //清除計時10MS標志
                        key = key_read(); //調用掃描按鍵程序,返回一個鍵值

                        if (key == L_key) //長按:點亮P1口上的8個LED燈。(低電平點亮)
                        {
                                P0 = 0x00;
                        }  
            else if(key == D_key)//雙擊:點亮P1口上第二個LED燈。(低電平點亮)  
            {
                                P0 = 0xfd;
                        }  
            else if(key == S_key)//單擊:點亮P1口上第一個LED燈。(低電平點亮)  
            {
                                P0 = 0xfe;
                        }
                              else if(key == C_key)//單擊:點亮P1口上第1個和第二個LED燈。(低電平點亮)  
            {
                                P0 = 0xfc;//11111100
                        }
                              else if(key == E_key)//單擊:點亮P1口上第1個和第二個LED燈。(低電平點亮)  
            {
                                P0 = 0xf0;//11110000
                        }
                               else if(key == F_key)//單擊:點亮P1口上第1個和第二個LED燈。(低電平點亮)  
            {
                                P0 = 0x70;//11110000
                        }
                }
        }
}

void timer0(void) interrupt 1        //用的是定時器0, 這個“interrupt 1”中的“1”代表1號中斷即是定時器0中斷。如果是“0”就是外部中斷0;“2“=外部中斷1;”3“定時器1中斷;”4“=串行口中斷
{
        TH0 = (65535 - 10000)/256;
        TL0 = (65535 - 10000)%256; //定時器0的方式1,得在中斷程序中重復初值。
        time_10ms_ok = 1;  //定時10MS 的標志
}


led.c(117): error C141: syntax error near 'void'

報錯,求助。
回復

使用道具 舉報

15#
ID:584814 發表于 2021-4-20 08:23 | 只看該作者
unsigned char key_read(void) 尾巴上少了個 }
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 亚洲一区欧美一区 | 日本a在线| 日韩一区二区在线观看视频 | 欧美黑人一区二区三区 | 日韩精品一区二区三区在线观看 | 精品中文字幕在线观看 | 午夜免费网站 | 麻豆久久久久久久 | 亚洲a视频| 亚洲一区二区三区四区视频 | 日本天堂视频在线观看 | 精品99久久久久久 | 欧美一级黄色网 | 亚洲欧美日韩精品久久亚洲区 | 国产真实乱对白精彩久久小说 | 91免费观看国产 | 欧美日韩在线一区二区三区 | 亚洲高清在线观看 | 中文字幕一区二区三区四区五区 | 欧美日韩三级 | 91国产视频在线观看 | 青青草原综合久久大伊人精品 | 在线免费观看黄色av | 中文字幕亚洲精品 | 成人av高清 | 欧美国产中文字幕 | 天天干夜夜操 | 亚洲成人在线网 | 亚洲风情在线观看 | 久久久蜜臀国产一区二区 | 亚洲国产精品久久久 | 免费一级黄 | 国产成人精品在线 | 欧美精品日韩精品国产精品 | 亚洲国产一区二区视频 | 亚洲免费一区二区 | 青青操av| 中文字幕一级 | 欧美黄色一区 | 91福利电影在线观看 | 91xx在线观看|