找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

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

單片機(jī)實(shí)用按鍵模塊,沒有延時(shí)語句、while()語句,可以直接復(fù)制使用與其他程序不沖突

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:491577 發(fā)表于 2021-6-7 12:30 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
本帖最后由 hhh402 于 2021-6-13 12:55 編輯

單片機(jī)實(shí)用按鍵模塊,沒有延時(shí)語句、while()語句,資源占用小?梢灾苯訌(fù)制使用與其他程序不沖突。
使用時(shí)只需要直接引用全局變量key1和key2就可以。舉例:
1、k1按鍵按下LED1亮,再次按下LED1滅,
if(key1==1)        //k1按鍵按下
{
   key1=0;//必須軟件清零。!
   LED1=~LED1;
}

2、k2按鍵按下LED1亮,K2長(zhǎng)按LED1滅,
if(key1==2) //k2按鍵按下
{
   key1=0;//必須軟件清零。。
   LED1=0; //0開1關(guān)
}
if(key1==20) //k按鍵長(zhǎng)按
{
   key1=0;//必須軟件清零。!
   LED1=1; //0開1關(guān)
}

3、k3按鍵按下LED1亮,K4按下LED1滅,
if(key1==3) //k3按鍵按下
{
   key1=0;//必須軟件清零。!
   LED1=0; //0開1關(guān)
}
if(key1==4) //k4按鍵按下
{
   key1=0;//必須軟件清零。。
   LED1=1; //0開1關(guān)
}

4、K3按下一次,數(shù)據(jù)m 增加1,長(zhǎng)按k3兩秒以上每隔500ms數(shù)據(jù)m 增加10;K4按下一次,數(shù)據(jù)m 減少1,長(zhǎng)按k4兩秒以上每隔500ms數(shù)據(jù)m 減少10;
if(key1==3) //k3按鍵按下
{
   key1=0;//必須軟件復(fù)位
   m++; //數(shù)據(jù)m 增加1
}
if(key2==3) //k3按鍵按下兩秒以上,注意key2不需要清零,key1必須清零。!
{
   if(ms1>2000&&ms1%500==0) m=m+10; //長(zhǎng)按k3兩秒以上每隔500ms數(shù)據(jù)m 增加10,ms1是毫秒變量,需要放在定時(shí)器1ms中斷中自加,ms1++;
}
else ms1=0;        //復(fù)位

if(key1==4) //k4按鍵按下
{
   key1=0;//必須軟件復(fù)位
   m--; //數(shù)據(jù)m -1
}
if(key2==4) //k4按鍵按下兩秒以上 ,注意key2不需要清零,key1必須清零!。
{
   if(ms2>2000&&ms2%500==0)  m=m-10; //長(zhǎng)按k4兩秒以上每隔500ms,ms2是毫秒變量,需要放在定時(shí)器1ms中斷中自加,ms2++;
}
else ms2=0;//復(fù)位

//下面是完整程序代碼:
#include "stc8.h"
#include "intrins.h"
#define u8  unsigned char
#define u16 unsigned int
sbit k1=P0^0;//按鍵1,四個(gè)按鍵可以是任意I/O口。按鍵按下時(shí)k1=0,按鍵釋放k1=1
sbit k2=P0^1;//按鍵2
sbit k1=P0^2;//按鍵3
sbit k1=P0^3;//按鍵4
sbit LED1=P1^0;//LED1

//u8 key1[4];//按鍵變量數(shù)組,4個(gè)按鍵互不影響,如果用key1,一次只能夠按一個(gè)按鍵,不允許同時(shí)按鍵。
u8 key1;//按鍵變量1,輸出按鍵單擊,長(zhǎng)按。每單擊或長(zhǎng)按一次只輸出一次,由調(diào)用函數(shù)清零。//key1=1/2/3/4是對(duì)應(yīng)的按鍵單擊,key1=10、20、30、40是對(duì)應(yīng)的按鍵長(zhǎng)按。key1=0表示沒有按鍵按下。
//key1主要用途是:判斷某一個(gè)按鍵是單擊還是長(zhǎng)按.注意調(diào)用函數(shù)需要將key1清零。。
//u8 key2[4];//按鍵變量數(shù)組,4個(gè)按鍵互不影響,如果用key2,一次只能夠按一個(gè)按鍵,不允許同時(shí)按鍵。
u8 key2;//按鍵變量2,輸出按鍵單擊,每10ms輸出一次,key1=1/2/3/4是對(duì)應(yīng)的按鍵單擊。
//key2主要用途是:長(zhǎng)按按鍵時(shí)快速增加或減少數(shù)值。
u16 ms1,ms2;//毫秒計(jì)時(shí)
u16 m;//
void key() //按鍵處理模塊,需要放在10ms中斷中運(yùn)行。!
/* 說明:1、按鍵單擊,指按下100-1000ms內(nèi)釋放,加入時(shí)間限制是為了防止干擾。
             2、按鍵長(zhǎng)按,指按下3-10s內(nèi)釋放,加入時(shí)間限制是為了防止干擾。
              3、函數(shù)運(yùn)行后,按鍵值保存在key1、key2。用戶直接調(diào)用key1、key2即可。

*/
{
  //靜態(tài)變量,必須要static
  u16 static kgr[4];    //必須要static,抗干擾時(shí)間數(shù)組
  u8  static kanggr[4]; //中間變量1
  u8  static anjtem[4]; //按鍵釋放中間變量。
  u8 i;
  u8 L_anj[4];
  L_anj[0]=k1;
  L_anj[1]=k2;
  L_anj[2]=k3;
  L_anj[3]=k4;
  for(i=0;i<3;i++)  //4個(gè)按鍵處理,key1,
   {
         if(L_anj[ i]==0)        //按鍵按下                                       
          { if(kanggr[ i]==0)        //中間變量1,與下面互鎖
             { kgr[ i]=0;                //抗干擾時(shí)間清零,每次按鍵只寫1次。
               kanggr[ i]=1;         //中間變量1
               anjtem[ i]=1;         //按鍵釋放中間變量。與下面互鎖
             }

           if(anjtem[ i]==1)
           {
                  kgr[ i]++;//10毫秒計(jì)時(shí)。
                  if(kgr[ i]>1000) //按鍵按下大于10秒,強(qiáng)制復(fù)位,防止誤按。
                   { anjtem[ i]=0; //按鍵釋放中間變量。與上面互鎖
                     kgr[ i]=0;
//                  key1[ i]=0;//數(shù)組,4個(gè)按鍵獨(dú)立
                   }
           }
         }

     else    //按鍵釋放
     { kanggr[ i]=0;           //中間變量1,與上面互鎖
           if(kgr[ i]>9&&kgr[ i]<99) //按鍵間隔100--1000毫秒才有效,防止電磁干擾。時(shí)間可以修改
                 key1=i+1;   //單擊,按鍵間隔100--1000毫秒,每次釋放只寫1次。一次只能夠按一個(gè)按鍵,不允許同時(shí)按鍵。
           //key1[ i]=i+1;//數(shù)組,4個(gè)按鍵獨(dú)立
           else if(kgr[ i]>300&&kgr[ i]<1000) //按鍵間隔3000--10000毫秒才有效,防止電磁干擾。時(shí)間可以修改
                 key1=(i+1)*10;//長(zhǎng)按,按鍵間隔3--10秒,每次釋放只寫1次。
           //key1[ i]=(i+1)*10;//數(shù)組,4個(gè)按鍵獨(dú)立
     }
  }

//下面是處理:key2是有按鍵按下就輸出鍵值。        
    for(i=0;i<3;i++)
         { if(L_anj[ i]==0)
           key2=i+1;//一次只能夠按一個(gè)按鍵,不允許同時(shí)按鍵。
         //key2[ i]=i+1;//數(shù)組,4個(gè)按鍵獨(dú)立.
         }
}


void timer0() interrupt 1                 //計(jì)時(shí)器T0中斷1ms。
{
  //靜態(tài)變量,必須要static
  u8  static time=0;   //毫秒變量。
  time++;//毫秒計(jì)時(shí)。
  if(time>9) //10ms運(yùn)行一次按鍵處理函數(shù),不需要防抖程序。
  {
       time=0;
        key();//按鍵處理模塊,需要放在10ms中斷中運(yùn)行。!
  }
//下面的語句不是按鍵模塊需要的,可以刪除。
    ms1++;ms2++;//毫秒計(jì)時(shí)
}

void main()
{
//1毫秒@12.000MHz,下面是STC單片機(jī)定時(shí)器0代碼,如果是別的單片機(jī)請(qǐng)根據(jù)手冊(cè)修改
        AUXR |= 0x80;                //定時(shí)器時(shí)鐘1T模式
        TMOD &= 0xF0;                //設(shè)置定時(shí)器模式
        TL0 = 0x20;                //設(shè)置定時(shí)初值,1毫秒@12.000MHz
        TH0 = 0xD1;                //設(shè)置定時(shí)初值,1毫秒@12.000MHz
        TF0 = 0;                //清除TF0標(biāo)志        
        ET0 = 1;        //使能定時(shí)器中斷
       EA = 1;                    //打開總中斷
        TR0 = 1;                //定時(shí)器0開始計(jì)時(shí)
while(1)
  {
//1、k1按鍵按下LED1亮,再次按下LED1滅,
    if(key1==1)        //k1按鍵按下
     {
       key1=0;//必須軟件清零。!
       LED1=~LED1;
     }

//2、k2按鍵按下LED1亮,K2長(zhǎng)按LED1滅,
    if(key1==2) //k2按鍵按下
     {
       key1=0;//必須軟件清零!。
       LED1=0; //0開1關(guān)
     }
   if(key1==20) //k按鍵長(zhǎng)按
     {
       key1=0;//必須軟件清零。!
       LED1=1; //0開1關(guān)
     }

//3、k3按鍵按下LED1亮,K4按下LED1滅,
   if(key1==3) //k3按鍵按下
    {
      key1=0;//必須軟件清零。!
      LED1=0; //0開1關(guān)
    }
   if(key1==4) //k4按鍵按下
    {
      key1=0;//必須軟件清零!!
      LED1=1; //0開1關(guān)
    }

//4、K3按下一次,數(shù)據(jù)m 增加1,長(zhǎng)按k3兩秒以上每隔500ms數(shù)據(jù)m 增加10;K4按下一次,數(shù)據(jù)m 減少1,長(zhǎng)按k4兩秒以上每隔500ms數(shù)據(jù)m 減少10;
//m的范圍:0-60000
   if(key1==3) //k3按鍵按下
    {
      key1=0;//必須軟件清零。。
      if(m<60000) m++; //數(shù)據(jù)m 增加1
    }
   if(key2==3) //k3按鍵按下兩秒以上,注意key2不需要清零,key1必須清零!!
    {
      if(ms1>2000&&ms1%500==0)
           {if(m<=59990) m=m+10;} //長(zhǎng)按k3兩秒以上每隔500ms數(shù)據(jù)m 增加10,ms1是毫秒變量,需要放在定時(shí)器1ms中斷中自加,ms1++;
    }
   else ms1=0;        //復(fù)位

   if(key1==4) //k4按鍵按下
    {
      key1=0;//必須軟件復(fù)位
      if(m>0) m--; //數(shù)據(jù)m -1
    }
   if(key2==4) //k4按鍵按下兩秒以上 ,注意key2不需要清零,key1必須清零。!
    {
      if(ms2>2000&&ms2%500==0)
          {if(m>9)  m=m-10;} //長(zhǎng)按k4兩秒以上每隔500ms,ms2是毫秒變量,需要放在定時(shí)器1ms中斷中自加,ms2++;
    }
   else ms2=0;//復(fù)位
}
}


評(píng)分

參與人數(shù) 2黑幣 +60 收起 理由
x84s09t28 + 10 贊一個(gè)!
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

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

使用道具 舉報(bào)

沙發(fā)
ID:491577 發(fā)表于 2021-6-7 15:52 | 只看該作者
本帖最后由 hhh402 于 2021-6-13 12:56 編輯

這是按鍵檢測(cè)模塊函數(shù):要認(rèn)真看才能夠理解。
void key() //按鍵處理模塊,需要放在10ms中斷中運(yùn)行。!
/* 說明:1、按鍵單擊,指按下100-1000ms內(nèi)釋放,加入時(shí)間限制是為了防止干擾。
             2、按鍵長(zhǎng)按,指按下3-10s內(nèi)釋放,加入時(shí)間限制是為了防止干擾。
             3、函數(shù)運(yùn)行后,按鍵值保存在key1、key2。用戶直接調(diào)用key1、key2即可。
*/
{
  u16 static kgr[4];    //必須要static,抗干擾時(shí)間數(shù)組
  u8  static kanggr[4]; //中間變量1
  u8  static anjtem[4]; //按鍵釋放中間變量。
  u8 i;
  u8 L_anj[4];
  L_anj[0]=k1;
  L_anj[1]=k2;
  L_anj[2]=k3;
  L_anj[3]=k4;
  for(i=0;i<3;i++)  //4個(gè)按鍵處理,key1,
   {
         if(L_anj[ i]==0)        //按鍵按下                                       
          { if(kanggr[ i]==0)        //中間變量1,與下面互鎖
             { kgr[ i]=0;                //抗干擾時(shí)間清零,每次按鍵只寫1次。
               kanggr[ i]=1;         //中間變量1
               anjtem[ i]=1;         //按鍵釋放中間變量。與下面互鎖
            }

           if(anjtem[ i]==1)
           {
                  kgr[ i]++;//10毫秒計(jì)時(shí)。
                  if(kgr[ i]>1000) //按鍵按下大于10秒,強(qiáng)制復(fù)位,防止誤按。
                   { anjtem[ i]=0; //按鍵釋放中間變量。與上面互鎖
                     kgr[ i]=0;
                   }
           }
         }

     else    //按鍵釋放
     { kanggr[ i]=0;           //中間變量1,與上面互鎖
           if(kgr[ i]>9 && kgr[ i]<99) //按鍵間隔100--1000毫秒才有效,防止電磁干擾。時(shí)間可以修改
                 key1=i+1;   //單擊,按鍵間隔100--1000毫秒,每次釋放只寫1次。一次只能夠按一個(gè)按鍵,不允許同時(shí)按鍵。
           else if(kgr[ i]>300 && kgr[ i]<1000) //按鍵間隔3000--10000毫秒才有效,防止電磁干擾。時(shí)間可以修改
                 key1=(i+1)*10;//長(zhǎng)按,按鍵間隔3--10秒,每次釋放只寫1次。
     }
  }

//下面是處理:key2是有按鍵按下就輸出鍵值。        
    for(i=0;i<3;i++)
         { if(L_anj[ i]==0)
           key2=i+1;//一次只能夠按一個(gè)按鍵,不允許同時(shí)按鍵。
         }
}

評(píng)分

參與人數(shù) 1黑幣 +20 收起 理由
admin + 20 回帖助人的獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

板凳
ID:299626 發(fā)表于 2021-6-7 17:15 | 只看該作者
本帖最后由 nqwang 于 2021-6-7 17:46 編輯

mark下,好東西,節(jié)省資源的按鍵處理,但是建議做個(gè)完整的工程這樣好些。
回復(fù)

使用道具 舉報(bào)

地板
ID:229641 發(fā)表于 2021-6-7 23:30 來自觸屏版 | 只看該作者
有完整的沒我白嫖一下…
回復(fù)

使用道具 舉報(bào)

5#
ID:820198 發(fā)表于 2021-6-8 08:18 | 只看該作者
感謝分享, 有完整工程例子學(xué)習(xí)嗎
回復(fù)

使用道具 舉報(bào)

6#
ID:491577 發(fā)表于 2021-6-8 09:55 | 只看該作者
最上面就是完整的程序,只需要改一下IO口設(shè)置,直接復(fù)制就可以用,與別的程序沒有沖突,沒有延時(shí)語句,while語句,資源占用很小。
回復(fù)

使用道具 舉報(bào)

7#
ID:491577 發(fā)表于 2021-6-8 09:58 | 只看該作者
注意:1、必須定義全局變量key1、key2。
          2、按鍵處理模塊,需要放在10ms中斷中運(yùn)行。!
          3、直接調(diào)用key1、key2就好。
回復(fù)

使用道具 舉報(bào)

8#
ID:914666 發(fā)表于 2021-6-10 04:57 | 只看該作者
要是客戶一起按了按鍵怎么辦。
回復(fù)

使用道具 舉報(bào)

9#
ID:491577 發(fā)表于 2021-6-10 10:13 | 只看該作者
用key1傳遞鍵值是不支持同時(shí)按鍵的,如果同時(shí)按鍵了會(huì)返回最后釋放按鍵的鍵值,如果想四個(gè)按鍵獨(dú)立互不影響可以使用數(shù)組key1[],程序里面有代碼,已經(jīng)注銷了,自己修改一下就可以用。這個(gè)程序最大的特點(diǎn)是沒有延時(shí)語句,while語句,不會(huì)阻塞別的程序,直接復(fù)制粘貼就可以使用了。
回復(fù)

使用道具 舉報(bào)

10#
ID:428114 發(fā)表于 2021-6-10 14:09 | 只看該作者
放在中斷里,是一種手法,當(dāng)然不再需要延時(shí)語句了,和程序沒有關(guān)系.
回復(fù)

使用道具 舉報(bào)

11#
ID:162733 發(fā)表于 2021-6-12 21:38 | 只看該作者
上面的程序只有key2可以讀出數(shù)值,key1始終無法讀出數(shù)值
回復(fù)

使用道具 舉報(bào)

12#
ID:491577 發(fā)表于 2021-6-13 12:59 | 只看該作者
本帖最后由 hhh402 于 2021-6-15 12:16 編輯
x84s09t28 發(fā)表于 2021-6-12 21:38
上面的程序只有key2可以讀出數(shù)值,key1始終無法讀出數(shù)值

程序有點(diǎn)錯(cuò)誤,按鍵檢測(cè)程序中,ket1=0;這一句要去掉就可以了,最上面的程序我已經(jīng)改好了,你再試試。其實(shí)原程序也是可以用的,key1的值只保存10ms就會(huì)變?yōu)?了,人眼是看不到key1的變化,但是10ms時(shí)間足夠了,程序不會(huì)出錯(cuò)。
回復(fù)

使用道具 舉報(bào)

13#
ID:162733 發(fā)表于 2021-7-1 23:34 | 只看該作者
hhh402 發(fā)表于 2021-6-13 12:59
程序有點(diǎn)錯(cuò)誤,按鍵檢測(cè)程序中,ket1=0;這一句要去掉就可以了,最上面的程序我已經(jīng)改好了,你再試試。其 ...

剛試過了程序,在你的key()程序中,else //按鍵釋放,這個(gè)地方需要改成else if(kanggr[i ]==1)  //按鍵釋放;否則的話,按鍵只有第一次按下有用,后面就不能用了
回復(fù)

使用道具 舉報(bào)

14#
ID:491577 發(fā)表于 2021-7-10 11:53 | 只看該作者
“按鍵只有第一次按下有用,后面就不能用了”,就是要這樣的效果。等到按鍵釋放后才會(huì)歸位。每一次按鍵按下、釋放只會(huì)輸出一次鍵值,這樣才方便程序調(diào)用。
回復(fù)

使用道具 舉報(bào)

15#
ID:579174 發(fā)表于 2021-8-4 14:20 | 只看該作者
程序小白,下來學(xué)習(xí)了,感謝分享!
回復(fù)

使用道具 舉報(bào)

16#
ID:845675 發(fā)表于 2021-8-11 19:08 來自觸屏版 | 只看該作者
樓主,你這個(gè)模塊怎么在我的AT89S51上不能正常使用啊
回復(fù)

使用道具 舉報(bào)

17#
ID:491577 發(fā)表于 2021-8-12 10:00 | 只看該作者
這是STC8單片機(jī)的程序,用在其他單片機(jī)需要修改定時(shí)器0部分。按照手冊(cè)修改。
void main()
{
//1毫秒@12.000MHz,下面是STC單片機(jī)定時(shí)器0代碼,如果是別的單片機(jī)請(qǐng)根據(jù)手冊(cè)修改
        AUXR |= 0x80;                //定時(shí)器時(shí)鐘1T模式
        TMOD &= 0xF0;                //設(shè)置定時(shí)器模式
        TL0 = 0x20;                //設(shè)置定時(shí)初值,1毫秒@12.000MHz
        TH0 = 0xD1;                //設(shè)置定時(shí)初值,1毫秒@12.000MHz
        TF0 = 0;                //清除TF0標(biāo)志        
        ET0 = 1;        //使能定時(shí)器中斷
       EA = 1;                    //打開總中斷
        TR0 = 1;                //定時(shí)器0開始計(jì)時(shí)
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

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