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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2648|回復: 14
收起左側

5個按鍵分別接在MCU單片機P1 P3 P4 IO口上,如何用狀態機檢測?

  [復制鏈接]
ID:686513 發表于 2022-8-20 14:50 | 顯示全部樓層 |閱讀模式
/*******************************************************************************
* 文件名:單片機MCU按鍵函數
* 描  述:
* 功  能:
* 參  數:無
*******************************************************************************/                                                                       
#define PD 0xe0|(P1<<4&0x10)|(P4&0x0c)|(P3&0x03)   //P1.0/P3.0 p3.1/P4.2 p4.3組合5個按鍵為1個字節數據
//   1110 0000 |0000 0001   |0000 1100 |0000 0011
//   移位后    |0001 0000   |0000 1100 |0000 0011  

#define S0 0   //狀態0
#define S1 1   //狀態1
#define S2 2   //狀態2
#define S3 3   //狀態3
                                          
void key_scan()     //放在10ms的定時器中掃描
{
        static u8 state=S0,key_time;
        u8 key;
        key=PD&0xff;                                
       switch(state)                                 
            {
         case S0:                                     //狀態0
                  if(key!= 0xff) state = S1; break;        //判斷輸入是否為0,為0轉入狀態1
               
        case S1:                                    //狀態1
                if(key==0xff) state = S0;                //判斷輸入是否為1,為1返回狀態0
                else                                     //否則,轉入狀態2,執行按鍵程序
                 {
                         state=S2;  
                switch(key)
                 {
                                 case 0xfe:
                                  //執行任務1; break;                                                                                          
                                
                                                                                                        
                                 case 0xef:
                                        //執行任務2; break;        
                                       
                                 case 0xfd:
                                        //執行任務3; break;        
                                                        
                                 case 0xfb:
                                //執行任務4; break;        
                                                
                                 case 0xf7:
                                //執行任務5; break;                                                                        
                                 default:break;                                                   
                     }
                     break;

       case S2:                                                  //狀態2
               if(key==0xff) state = S0;                              //判斷輸入是否為1,為1返回狀態0
               else if(++key_time==60) {key_time=0;state=S3;}        //否則開始計時,計時結束轉入狀態3
                 break;

        case S3:                                                  //狀態3
                    if(key==0xff)  state=S0;                               //判斷輸入是否為1,為1返回狀態0
                    else if(++key_time==5)                                 //否則開始計時,計時結束按鍵連擊
                             {
                                key_time=0;
                                switch(key)
                                        {
                                        case 0xfe:                                                                                                                                       
                                                //執行任務6; break;               
                                                
                                        case 0xfd:
                                                //執行任務1; break;                                                                                                                                                                                                                                                                                                
                                      }
                         }
                   break;
  }
}                                                                                                                                                                                                                    如果5個按鍵都接同一組IO口,沒問題,但分別接在不同組IO上(如分別接在P1 P3 P4某個IO口上),目前重定義把5個按鍵組成為1個字節數據,再判斷就不能識別了,我也明白switch(key)中的key值不能識別是P1 P3 P4上某個真正的IO口導致的,但我不知道怎么還原到P1 P3 P4上具體識別出哪個IO為有效。
回復

使用道具 舉報

ID:213173 發表于 2022-8-20 21:17 | 顯示全部樓層
換一種寫法可能比較好理解

  1. #define PD 0x80   | (P1<<3&0x60)|(P2>>1&0x18)|(P3&0x07)//P1.2~3/P2.4~5/P3.0~2組合7個按鍵為1個字節數據
  2. //      1000 0000    0000 1100    0011 0000   0000 0111
  3. //
  4. /*******************************************************************************
  5. * 文件名:按鍵函數
  6. * 描  述:
  7. * 功  能:
  8. * 參  數:無
  9. *************************************************/
  10. void key_scan()     //放在10ms的定時器中掃描
  11. {
  12.         static u8  key_time=0;
  13.         static bit key_sign=0;
  14.         u8 key;
  15.         key=PD&0xff;
  16.         if(key!=0xff)//有鍵按下
  17.         {
  18.                 if(++key_time>=2 && !key_sign)//
  19.                 {
  20.                         key_sign=1;
  21.                         switch(key)
  22.                         {
  23.                                 case 0xfe:/*執行任務1;*/ break;
  24.                                 case 0xfd:/*執行任務2;*/ break;
  25.                                 case 0xfb:/*執行任務3;*/ break;
  26.                                 case 0xf7:/*執行任務4;*/ break;
  27.                                 case 0xef:/*執行任務5;*/ break;
  28.                                 //case 0xdf:/*執行任務6;*/ break;
  29.                                 //case 0xbf:/*執行任務7;*/ break;
  30.                                   //case 0x7f:/************/ break;
  31.                                 default:break;
  32.                         }
  33.                 }
  34.         }
  35.         else                 //松手
  36.         {
  37.                 key_time=0;
  38.                 key_sign=0;
  39.         }
  40. }

復制代碼
回復

使用道具 舉報

ID:146878 發表于 2022-8-20 22:59 | 顯示全部樓層
sbit P_KEY1= P1^2;
sbit P_KEY2= P1^3;
sbit P_KEY3......
sbit P_KEY4......
sbit P_KEY5......
void key_scan()     //放在10ms的定時器中掃描
{
        static u8 state=S0,key_time;
        u8 key=0;
        if(P_KEY1)  key|=0x01;
        if(P_KEY2)  key|=0x02;
        if(P_KEY3)  key|=0x04;
        if(P_KEY4)  key|=0x08;
        if(P_KEY5)  key|=0x10;                             
       switch(state)   
       ......
       .......
       .......
}
回復

使用道具 舉報

ID:146878 發表于 2022-8-20 23:01 | 顯示全部樓層
這點彎都轉不過來的話,那你路還很長啊,小伙子。。
回復

使用道具 舉報

ID:686513 發表于 2022-8-21 08:24 | 顯示全部樓層
本帖最后由 zhth1979 于 2022-8-21 09:05 編輯
wulin 發表于 2022-8-20 21:17
換一種寫法可能比較好理解

上面5個按鍵為:P1.0/P3.0 p3.1/P4.2 p4.3  現在改過來了。 #define PD 0xe0|(P1<<4&0x10)|(P4&0x0c)|(P3&0x03)   //P1.0/P3.0 p3.1/P4.2 p4.3組合5個按鍵為1個字節數據 //   1110 0000 |0000 0001   |0000 1100 |0000 0011
//   移位后    |0001 0000   |0000 1100 |0000 0011  
switch(key)中key判斷是PD的值,怎么能說明case 0xfe(1111 1110)中0xfe代表是P3.2口?而不是P1或P2中的某個IO口。  
回復

使用道具 舉報

ID:686513 發表于 2022-8-21 08:38 | 顯示全部樓層
本帖最后由 zhth1979 于 2022-8-21 09:05 編輯
pdwdzz 發表于 2022-8-20 22:59
sbit P_KEY1= P1^2;
sbit P_KEY2= P1^3;
sbit P_KEY3......

上面5個按鍵為:P1.0/P3.0 p3.1/P4.2 p4.3  現在改過來了。 #define PD 0xe0|(P1<<4&0x10)|(P4&0x0c)|(P3&0x03)   //P1.0/P3.0 p3.1/P4.2 p4.3組合5個按鍵為1個字節數據 //   1110 0000 |0000 0001   |0000 1100 |0000 0011
//   移位后    |0001 0000   |0000 1100 |0000 0011  
switch(key)中key判斷是PD的值,怎么能說明case 0xfe(1111 1110)中0xfe代表是P3.2口?而不是P1或P2中的某個IO口。  
回復

使用道具 舉報

ID:686513 發表于 2022-8-21 08:38 | 顯示全部樓層
本帖最后由 zhth1979 于 2022-8-21 09:04 編輯
pdwdzz 發表于 2022-8-20 23:01
這點彎都轉不過來的話,那你路還很長啊,小伙子。。
上面5個按鍵為:P1.0/P3.0 p3.1/P4.2 p4.3  現在改過來了。 #define PD 0xe0|(P1<<4&0x10)|(P4&0x0c)|(P3&0x03)   //P1.0/P3.0 p3.1/P4.2 p4.3組合5個按鍵為1個字節數據 //   1110 0000 |0000 0001   |0000 1100 |0000 0011
//   移位后    |0001 0000   |0000 1100 |0000 0011  
switch(key)中key判斷是PD的值,怎么能說明case 0xfe(1111 1110)中0xfe代表是P3.2口?而不是P1或P2中的某個IO口。      
回復

使用道具 舉報

ID:213173 發表于 2022-8-21 18:16 | 顯示全部樓層
zhth1979 發表于 2022-8-21 08:24
上面5個按鍵為:P1.0/P3.0 p3.1/P4.2 p4.3  現在改過來了。 #define PD 0xe0|(P1

1.jpg
單片機源程序如下:

  1. #include <reg51.H>
  2. sfr P4   =   0xC0;   //1111,1111 端口4
  3. sfr AUXR =   0x8E;   //0000,0000 輔助寄存器
  4. #define u8 unsigned int
  5. #define u16 unsigned char
  6. #define PD (P1<<4&0x10)|(P4&0x0c)|(P3&0x03)

  7. void Timer0Init()                //10毫秒@12.000MHz
  8. {
  9.         AUXR &= 0x7F;                //定時器時鐘12T模式
  10.         TMOD &= 0xF0;                //設置定時器模式
  11.         TMOD |= 0x01;                //設置定時器模式
  12.         TL0 = 0xF0;                //設置定時初始值
  13.         TH0 = 0xD8;                //設置定時初始值
  14.         TF0 = 0;                //清除TF0標志
  15.         TR0 = 1;                //定時器0開始計時
  16.         EA  = 1;
  17.         ET0 = 1;

  18. }

  19. /***********************************************
  20. * 文件名:按鍵函數
  21. * 描  述:
  22. * 功  能:
  23. * 參  數:無
  24. *************************************************/
  25. void key_scan()     //放在10ms的定時器中掃描
  26. {
  27.         static u8  key_time=0;
  28.         static bit key_sign=0;
  29.         u8 key;
  30.         key=PD&0x1f;
  31.         if(key!=0x1f)//有鍵按下
  32.         {
  33.                 if(++key_time>=2 && !key_sign)//
  34.                 {
  35.                         key_sign=1;
  36.                         switch(key)
  37.                         {
  38.                                 case 0x1e:P2=0xfe; break;
  39.                                 case 0x1d:P2=0xfd; break;
  40.                                 case 0x1b:P2=0xfb; break;
  41.                                 case 0x17:P2=0xf7; break;
  42.                                 case 0x0f:P2=0xef; break;
  43.                                 default:break;
  44.                         }
  45.                 }
  46.         }
  47.         else                 //松手
  48.         {
  49.                 key_time=0;
  50.                 key_sign=0;
  51.         }
  52. }


  53. void main()
  54. {
  55.         Timer0Init();
  56.         while(1)
  57.         {
  58.         
  59.         }
  60. }

  61. void Timer0Interrupt(void) interrupt 1
  62. {
  63.         TH0 = 0xD8;                //設置定時初始值
  64.         TL0 = 0xF0;                //設置定時初始值
  65.         key_scan();
  66. }
復制代碼
回復

使用道具 舉報

ID:161164 發表于 2022-8-22 09:42 | 顯示全部樓層
  1. u8 bdata GPIO = 0xff;
  2. sbit Key0 = GPIO^0;
  3. sbit Key1 = GPIO^1;
  4. sbit Key2 = GPIO^2;
  5. sbit Key3 = GPIO^3;
  6. sbit Key4 = GPIO^4;
  7. u8 PD()
  8. {
  9.         Key4 = (bit)(P0 & 0x01);
  10.         Key3 = (bit)(P4 & 0x08);
  11.         Key2 = (bit)(P4 & 0x04);
  12.         Key1 = (bit)(P3 & 0x02);
  13.         Key0 = (bit)(P3 & 0x01);
  14.         return GPIO;
  15. }
復制代碼
回復

使用道具 舉報

ID:686513 發表于 2022-8-22 10:14 | 顯示全部樓層
本帖最后由 zhth1979 于 2022-8-22 12:39 編輯

找到原因了,這個單機的P4有ADC輸入,不能做普通的雙向口接按鍵了。把P4去除掉就好了。
回復

使用道具 舉報

ID:1034262 發表于 2022-8-22 10:36 | 顯示全部樓層
按鍵都是按時隙讀取,我常用32ms,即每隔32ms讀一次按鍵,值需要花費1~2us。
回復

使用道具 舉報

ID:686513 發表于 2022-8-22 12:41 | 顯示全部樓層
coody_sz 發表于 2022-8-22 10:36
按鍵都是按時隙讀取,我常用32ms,即每隔32ms讀一次按鍵,值需要花費1~2us。

它的速度不是很快嗎?10ms檢測,剛好同時也做按鍵的消抖了。
回復

使用道具 舉報

ID:509408 發表于 2022-8-22 14:21 | 顯示全部樓層
zhth1979 發表于 2022-8-21 08:38
上面5個按鍵為:P1.0/P3.0 p3.1/P4.2 p4.3  現在改過來了。 #define PD 0xe0|(P1

key讀到case :0xfe 把它換成二進制1111 1110 對應到你的PD宏定義,不就是P3口的P3.0=0?即P30被按下?
說白了還是對位操作不熟練 轉不過彎來
回復

使用道具 舉報

ID:123289 發表于 2022-8-22 14:43 | 顯示全部樓層
1、一位一位讀出來判斷。
2、各個IO口讀出來,按位分析。
你認為哪個方法適合你,就用哪個方法,都行。
回復

使用道具 舉報

ID:509408 發表于 2022-8-22 14:43 | 顯示全部樓層
tzs233 發表于 2022-8-22 14:21
key讀到case :0xfe 把它換成二進制1111 1110 對應到你的PD宏定義,不就是P3口的P3.0=0?即P30被按下?
說 ...

先掌握好二進制和16進制轉換關系。我再問你如果KEY= 0xf9,是哪幾個按鍵被按下了 你想得清楚嗎? 代碼精簡了是好事,但犧牲了可讀性。在你不熟練或思路不清晰的時候,還是按樓上的做法封裝成一個函數。通過變量或返回值讀出來。精簡代碼那是最后的事情。調試的時候也時如此的,哪能一步到位。
回復

使用道具 舉報

ID:190577 發表于 2022-8-24 09:05 | 顯示全部樓層

// 按鍵
#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 = P0^4;
sbit key1=P5^0;// 紅光
sbit key2=P3^0;//綠光開關
sbit key3=P0^2;        //藍
sbit key4=P4^0;        //白
sbit key5=P0^3; //加濕度
sbit key6=P5^2;//自動

static unsigned char key_read(void)
{
        static unsigned char key_state_buffer1 = key_state_0;
        static unsigned char key_timer_cnt1 = 0;
                static         unsigned char temp=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)||(key1 == 0)||(key2==0)||(key3==0)||(key4==0)||(key5==0)||(key6==0))
                         {  key_state_buffer1 = key_state_1; temp=0;
                                                         return 0;
                                                 }
                                //按鍵被按下,狀態轉換到按鍵消抖和確認狀態//
                        break;
                case key_state_1:
                        if(KEY== 0)
                        {
                                temp=1;
                                                            key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                //按鍵仍然處于按下狀態
                                //消抖完成,key_timer開始準備計時
                                //狀態切換到按下時間計時狀態
                        }
                                                else if(key1==0)
                                                {
                                                           temp=2;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                                                else if(key2==0)
                                                {
                                                            temp=4;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                                                else if(key3==0)
                                                {
                                                            temp=5;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                                                else if(key4==0)
                                                {
                                                            temp=6;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                                                else if(key5==0)
                                                {
                                                            temp=7;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                                                else if(key6==0)
                                                {
                                                            temp=8;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                        else
                                                {
                                key_state_buffer1 = key_state_0; temp=0;
                                                }
                                //按鍵已經抬起,回到按鍵初始狀態
                        break;  //完成軟件消抖
                case key_state_2:
                                                 if((KEY == 0)||(key1 == 0)||(key2==0)||(key3==0)||(key4==0)||(key5==0)||(key6==0))
                                                {
                                                         key_state_buffer1 = key_state_2;
                                                         if(temp==1)
                                                         {
                                                                 if(++key_timer_cnt1 >= 100)  //按鍵繼續按下,計時超過1000ms
                                                                 {
                                                                    
                                        key_return = key_long;  //送回長按事件
                                        key_state_buffer1 = key_state_3;  //轉換到等待按鍵釋放狀態
                                                                 }
                                                          }
                                                }
                                                else
                                                {
                                                         key_return = temp;  //按鍵抬起,產生一次click操作
                             key_state_buffer1 = key_state_0;  //轉換到按鍵初始狀態
                                                }
                       /* 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 == 0)||(key1 == 0)||(key2==0)||(key3==0)||(key4==0)||(key5==0)||(key6==0)) //按鍵釋放
                                key_state_buffer1 = key_state_3;  //切回按鍵初始狀態
                                                 else //按鍵釋放
                                key_state_buffer1 = key_state_0;  //切回按鍵初始狀態
                        break;
        }
        return key_return;
}
回復

使用道具 舉報

ID:686513 發表于 2022-8-24 10:24 | 顯示全部樓層
tzs233 發表于 2022-8-22 14:43
先掌握好二進制和16進制轉換關系。我再問你如果KEY= 0xf9,是哪幾個按鍵被按下了 你想得清楚嗎? 代碼精簡 ...

KEY= 0xf9      1111 1001  對應我上面的是控制P3.1和P4.2對嗎?不過現在已經可以了。
回復

使用道具 舉報

ID:624769 發表于 2022-8-24 16:09 來自手機 | 顯示全部樓層
恕我才疏學淺,       key=PD & 0xff;    這種寫法的意義何在?  為什么不寫成  key=PD | 0x00;    或者  key=PD % 0x100;    ?
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 免费精品 | 色综合久 | 国产在线永久免费 | 国产亚洲第一页 | 国产毛片视频 | 人人草天天草 | 色婷婷综合在线观看 | 久久久.com | 日韩成人在线观看 | www.一级毛片| 亚洲精品久久久蜜桃 | 国产二区在线播放 | 国产精品区二区三区日本 | 在线成人免费视频 | 欧美日韩国产一区二区三区 | 成人在线视频网 | 亚洲大片 | 精品免费国产视频 | 麻豆精品久久久 | 91高清视频在线观看 | 亚洲精品在线免费 | 激情五月婷婷综合 | 91网站视频在线观看 | 日韩精品一区二区三区在线观看 | 交专区videossex农村 | 亚洲国产精品日本 | 特黄毛片视频 | 国产在线小视频 | 一区二区三区欧美大片 | 蜜桃精品视频在线 | 国产免费va| 成人三级在线播放 | 亚洲交性 | 亚洲欧美精品 | 欧美精品一区二区在线观看 | 桃花av在线 | www.日本精品| 久久久久久亚洲精品 | 久久久久1 | 亚洲一区二区综合 | 中文字幕av在线播放 |