標(biāo)題: 5個(gè)按鍵分別接在MCU單片機(jī)P1 P3 P4 IO口上,如何用狀態(tài)機(jī)檢測(cè)? [打印本頁(yè)]

作者: zhth1979    時(shí)間: 2022-8-20 14:50
標(biāo)題: 5個(gè)按鍵分別接在MCU單片機(jī)P1 P3 P4 IO口上,如何用狀態(tài)機(jī)檢測(cè)?
/*******************************************************************************
* 文件名:?jiǎn)纹瑱C(jī)MCU按鍵函數(shù)
* 描  述:
* 功  能:
* 參  數(shù):無(wú)
*******************************************************************************/                                                                       
#define PD 0xe0|(P1<<4&0x10)|(P4&0x0c)|(P3&0x03)   //P1.0/P3.0 p3.1/P4.2 p4.3組合5個(gè)按鍵為1個(gè)字節(jié)數(shù)據(jù)
//   1110 0000 |0000 0001   |0000 1100 |0000 0011
//   移位后    |0001 0000   |0000 1100 |0000 0011  

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

       case S2:                                                  //狀態(tài)2
               if(key==0xff) state = S0;                              //判斷輸入是否為1,為1返回狀態(tài)0
               else if(++key_time==60) {key_time=0;state=S3;}        //否則開(kāi)始計(jì)時(shí),計(jì)時(shí)結(jié)束轉(zhuǎn)入狀態(tài)3
                 break;

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

作者: wulin    時(shí)間: 2022-8-20 21:17
換一種寫(xiě)法可能比較好理解

  1. #define PD 0x80   | (P1<<3&0x60)|(P2>>1&0x18)|(P3&0x07)//P1.2~3/P2.4~5/P3.0~2組合7個(gè)按鍵為1個(gè)字節(jié)數(shù)據(jù)
  2. //      1000 0000    0000 1100    0011 0000   0000 0111
  3. //
  4. /*******************************************************************************
  5. * 文件名:按鍵函數(shù)
  6. * 描  述:
  7. * 功  能:
  8. * 參  數(shù):無(wú)
  9. *************************************************/
  10. void key_scan()     //放在10ms的定時(shí)器中掃描
  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:/*執(zhí)行任務(wù)1;*/ break;
  24.                                 case 0xfd:/*執(zhí)行任務(wù)2;*/ break;
  25.                                 case 0xfb:/*執(zhí)行任務(wù)3;*/ break;
  26.                                 case 0xf7:/*執(zhí)行任務(wù)4;*/ break;
  27.                                 case 0xef:/*執(zhí)行任務(wù)5;*/ break;
  28.                                 //case 0xdf:/*執(zhí)行任務(wù)6;*/ break;
  29.                                 //case 0xbf:/*執(zhí)行任務(wù)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. }

復(fù)制代碼

作者: pdwdzz    時(shí)間: 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的定時(shí)器中掃描
{
        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)   
       ......
       .......
       .......
}
作者: pdwdzz    時(shí)間: 2022-8-20 23:01
這點(diǎn)彎都轉(zhuǎn)不過(guò)來(lái)的話(huà),那你路還很長(zhǎng)啊,小伙子。。
作者: zhth1979    時(shí)間: 2022-8-21 08:24
本帖最后由 zhth1979 于 2022-8-21 09:05 編輯
wulin 發(fā)表于 2022-8-20 21:17
換一種寫(xiě)法可能比較好理解

上面5個(gè)按鍵為:P1.0/P3.0 p3.1/P4.2 p4.3  現(xiàn)在改過(guò)來(lái)了。 #define PD 0xe0|(P1<<4&0x10)|(P4&0x0c)|(P3&0x03)   //P1.0/P3.0 p3.1/P4.2 p4.3組合5個(gè)按鍵為1個(gè)字節(jié)數(shù)據(jù) //   1110 0000 |0000 0001   |0000 1100 |0000 0011
//   移位后    |0001 0000   |0000 1100 |0000 0011  
switch(key)中key判斷是PD的值,怎么能說(shuō)明case 0xfe(1111 1110)中0xfe代表是P3.2口?而不是P1或P2中的某個(gè)IO口。  
作者: zhth1979    時(shí)間: 2022-8-21 08:38
本帖最后由 zhth1979 于 2022-8-21 09:05 編輯
pdwdzz 發(fā)表于 2022-8-20 22:59
sbit P_KEY1= P1^2;
sbit P_KEY2= P1^3;
sbit P_KEY3......

上面5個(gè)按鍵為:P1.0/P3.0 p3.1/P4.2 p4.3  現(xiàn)在改過(guò)來(lái)了。 #define PD 0xe0|(P1<<4&0x10)|(P4&0x0c)|(P3&0x03)   //P1.0/P3.0 p3.1/P4.2 p4.3組合5個(gè)按鍵為1個(gè)字節(jié)數(shù)據(jù) //   1110 0000 |0000 0001   |0000 1100 |0000 0011
//   移位后    |0001 0000   |0000 1100 |0000 0011  
switch(key)中key判斷是PD的值,怎么能說(shuō)明case 0xfe(1111 1110)中0xfe代表是P3.2口?而不是P1或P2中的某個(gè)IO口。  
作者: zhth1979    時(shí)間: 2022-8-21 08:38
本帖最后由 zhth1979 于 2022-8-21 09:04 編輯
pdwdzz 發(fā)表于 2022-8-20 23:01
這點(diǎn)彎都轉(zhuǎn)不過(guò)來(lái)的話(huà),那你路還很長(zhǎng)啊,小伙子。。
上面5個(gè)按鍵為:P1.0/P3.0 p3.1/P4.2 p4.3  現(xiàn)在改過(guò)來(lái)了。 #define PD 0xe0|(P1<<4&0x10)|(P4&0x0c)|(P3&0x03)   //P1.0/P3.0 p3.1/P4.2 p4.3組合5個(gè)按鍵為1個(gè)字節(jié)數(shù)據(jù) //   1110 0000 |0000 0001   |0000 1100 |0000 0011
//   移位后    |0001 0000   |0000 1100 |0000 0011  
switch(key)中key判斷是PD的值,怎么能說(shuō)明case 0xfe(1111 1110)中0xfe代表是P3.2口?而不是P1或P2中的某個(gè)IO口。      

作者: wulin    時(shí)間: 2022-8-21 18:16
zhth1979 發(fā)表于 2022-8-21 08:24
上面5個(gè)按鍵為:P1.0/P3.0 p3.1/P4.2 p4.3  現(xiàn)在改過(guò)來(lái)了。 #define PD 0xe0|(P1


單片機(jī)源程序如下:

  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;                //定時(shí)器時(shí)鐘12T模式
  10.         TMOD &= 0xF0;                //設(shè)置定時(shí)器模式
  11.         TMOD |= 0x01;                //設(shè)置定時(shí)器模式
  12.         TL0 = 0xF0;                //設(shè)置定時(shí)初始值
  13.         TH0 = 0xD8;                //設(shè)置定時(shí)初始值
  14.         TF0 = 0;                //清除TF0標(biāo)志
  15.         TR0 = 1;                //定時(shí)器0開(kāi)始計(jì)時(shí)
  16.         EA  = 1;
  17.         ET0 = 1;

  18. }

  19. /***********************************************
  20. * 文件名:按鍵函數(shù)
  21. * 描  述:
  22. * 功  能:
  23. * 參  數(shù):無(wú)
  24. *************************************************/
  25. void key_scan()     //放在10ms的定時(shí)器中掃描
  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;                //設(shè)置定時(shí)初始值
  64.         TL0 = 0xF0;                //設(shè)置定時(shí)初始值
  65.         key_scan();
  66. }
復(fù)制代碼

作者: lkc8210    時(shí)間: 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. }
復(fù)制代碼

作者: zhth1979    時(shí)間: 2022-8-22 10:14
本帖最后由 zhth1979 于 2022-8-22 12:39 編輯
wulin 發(fā)表于 2022-8-21 18:16

找到原因了,這個(gè)單機(jī)的P4有ADC輸入,不能做普通的雙向口接按鍵了。把P4去除掉就好了。
作者: coody_sz    時(shí)間: 2022-8-22 10:36
按鍵都是按時(shí)隙讀取,我常用32ms,即每隔32ms讀一次按鍵,值需要花費(fèi)1~2us。
作者: zhth1979    時(shí)間: 2022-8-22 12:41
coody_sz 發(fā)表于 2022-8-22 10:36
按鍵都是按時(shí)隙讀取,我常用32ms,即每隔32ms讀一次按鍵,值需要花費(fèi)1~2us。

它的速度不是很快嗎?10ms檢測(cè),剛好同時(shí)也做按鍵的消抖了。
作者: tzs233    時(shí)間: 2022-8-22 14:21
zhth1979 發(fā)表于 2022-8-21 08:38
上面5個(gè)按鍵為:P1.0/P3.0 p3.1/P4.2 p4.3  現(xiàn)在改過(guò)來(lái)了。 #define PD 0xe0|(P1

key讀到case :0xfe 把它換成二進(jìn)制1111 1110 對(duì)應(yīng)到你的PD宏定義,不就是P3口的P3.0=0?即P30被按下?
說(shuō)白了還是對(duì)位操作不熟練 轉(zhuǎn)不過(guò)彎來(lái)

作者: yzwzfyz    時(shí)間: 2022-8-22 14:43
1、一位一位讀出來(lái)判斷。
2、各個(gè)IO口讀出來(lái),按位分析。
你認(rèn)為哪個(gè)方法適合你,就用哪個(gè)方法,都行。
作者: tzs233    時(shí)間: 2022-8-22 14:43
tzs233 發(fā)表于 2022-8-22 14:21
key讀到case :0xfe 把它換成二進(jìn)制1111 1110 對(duì)應(yīng)到你的PD宏定義,不就是P3口的P3.0=0?即P30被按下?
說(shuō) ...

先掌握好二進(jìn)制和16進(jìn)制轉(zhuǎn)換關(guān)系。我再問(wèn)你如果KEY= 0xf9,是哪幾個(gè)按鍵被按下了 你想得清楚嗎? 代碼精簡(jiǎn)了是好事,但犧牲了可讀性。在你不熟練或思路不清晰的時(shí)候,還是按樓上的做法封裝成一個(gè)函數(shù)。通過(guò)變量或返回值讀出來(lái)。精簡(jiǎn)代碼那是最后的事情。調(diào)試的時(shí)候也時(shí)如此的,哪能一步到位。
作者: bbxyliyang    時(shí)間: 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;//綠光開(kāi)關(guān)
sbit key3=P0^2;        //藍(lán)
sbit key4=P4^0;        //白
sbit key5=P0^3; //加濕度
sbit key6=P5^2;//自動(dòng)

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;
                                                 }
                                //按鍵被按下,狀態(tài)轉(zhuǎn)換到按鍵消抖和確認(rèn)狀態(tài)//
                        break;
                case key_state_1:
                        if(KEY== 0)
                        {
                                temp=1;
                                                            key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                //按鍵仍然處于按下?tīng)顟B(tài)
                                //消抖完成,key_timer開(kāi)始準(zhǔn)備計(jì)時(shí)
                                //狀態(tài)切換到按下時(shí)間計(jì)時(shí)狀態(tài)
                        }
                                                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;
                                                }
                                //按鍵已經(jīng)抬起,回到按鍵初始狀態(tài)
                        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)  //按鍵繼續(xù)按下,計(jì)時(shí)超過(guò)1000ms
                                                                 {
                                                                    
                                        key_return = key_long;  //送回長(zhǎng)按事件
                                        key_state_buffer1 = key_state_3;  //轉(zhuǎn)換到等待按鍵釋放狀態(tài)
                                                                 }
                                                          }
                                                }
                                                else
                                                {
                                                         key_return = temp;  //按鍵抬起,產(chǎn)生一次click操作
                             key_state_buffer1 = key_state_0;  //轉(zhuǎn)換到按鍵初始狀態(tài)
                                                }
                       /* 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í)超過(guò)1000ms
                        {
                                key_return = key_long;  //送回長(zhǎng)按事件
                                key_state_buffer1 = key_state_3;  //轉(zhuǎn)換到等待按鍵釋放狀態(tài)
                        } */
                        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;  //切回按鍵初始狀態(tài)
                                                 else //按鍵釋放
                                key_state_buffer1 = key_state_0;  //切回按鍵初始狀態(tài)
                        break;
        }
        return key_return;
}
作者: zhth1979    時(shí)間: 2022-8-24 10:24
tzs233 發(fā)表于 2022-8-22 14:43
先掌握好二進(jìn)制和16進(jìn)制轉(zhuǎn)換關(guān)系。我再問(wèn)你如果KEY= 0xf9,是哪幾個(gè)按鍵被按下了 你想得清楚嗎? 代碼精簡(jiǎn) ...

KEY= 0xf9      1111 1001  對(duì)應(yīng)我上面的是控制P3.1和P4.2對(duì)嗎?不過(guò)現(xiàn)在已經(jīng)可以了。
作者: 188610329    時(shí)間: 2022-8-24 16:09
恕我才疏學(xué)淺,       key=PD & 0xff;    這種寫(xiě)法的意義何在?  為什么不寫(xiě)成  key=PD | 0x00;    或者  key=PD % 0x100;    ?




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1