AD按鍵-矩陣按鍵-獨立按鍵:


原理:利用數組分壓+AD采集;

優點:一個IO口可以做成多個按鍵,節省IO口(矩陣鍵盤在>4時優點才能體現出來);可備用作為AD基准輸入。

缺點:不能做成組合按鍵(或者電阻要精確選擇);且離IO口越近優先級越高。按鍵的識別收到精度的影響(消兜:抖動時間幾毫秒到幾十毫秒,所以連續讀4次(每次8ms)直到讀到值都相同。按鍵的識別是靠AD值的容差范圍而非具體的AD值來識別)。基准電壓的獲得(IO或TL431)

 

參考http://www.ednchina.com/ART_46350_11_0_OA_6f4d5e96.HTM

http://blog.sina.com.cn/s/blog_7a9b7c4c0100sohh.html

http://wenku.baidu.com/link?url=-vUPz14ryQnsrXNIJdfbOn1qw1JsJqIFRG9VUhxbaGjy80GEzZz8judHw1WRubzAsb-KOUzGfZQ-zVpOKu2PVH-SvRerysWsd-F_kTzivwS

--------------------------矩陣按鍵程序---------------------------------------------

矩陣鍵盤是否接上拉電阻:網友說法對於哪些弱上拉驅動能力弱的准3態IO的需要加,為了抗干擾也需要加;否則就不需要加。

/**************************************************************
*按鍵的鍵值分布圖:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
***************************************************************/
/**************************************************************
* 功能:P3外接4×4按鍵, 按照查表法讀出鍵值,使用時需要添加延時消抖動
* 返回:按鍵值0~15/如無鍵按下, 返回16
***************************************************************/
/*uchar keyscan(void)
{
uchar code K_Tab[4][4] = {
0xee, 0xde, 0xbe, 0x7e, //掃描碼為0xfe時(僅第一行為0)第一行4列4個按鍵可能按下時的值
0xed, 0xdd, 0xbd, 0x7d, //掃描碼為0xfd時(僅第二行為0)第二行4列4個按鍵可能按下時的值
0xeb, 0xdb, 0xbb, 0x7b,
0xe7, 0xd7, 0xb7, 0x77};
uchar temp1 = 0xfe, temp2, i, j;
for(i = 0; i < 4; i++)
{ //掃描低四位
P3 = temp1; //輸出一行0
temp2 = P3; //馬上就讀入
if((temp2 & 0xf0) != 0xf0) //如果有鍵按下
{
for(j = 0; j < 4; j++) //就掃描高四位
if(temp2 == K_Tab[i][j]) //查表
return i * 4 + j; //查到了就返回按鍵的數值
}
else temp1 = _crol_(temp1, 1);//非51的循環移位處理:(uchar)~(1<<i)
}
return 16; //沒有查到,返回按鍵松開的代碼
} */ //呵呵,實質性的語句不過9行,就是這么簡練!

/**************************************************************
* 功能: 按照反轉計算法讀出鍵值(IO必須是雙向的或能切換),不用循環結構
* 輸出:按鍵值0~15/如無鍵按下, 返回16
***************************************************************/
uchar keyscan(void)
{
uchar temH, temL,hang,lie;
uchar key_value;
P3 = 0xf0;
if(P3 != 0xf0)
{
delay(5); //消抖
if(P3 != 0xf0) //的確是有按鍵被按下
{
P3 = 0xf0; temH = P3; //低四位先輸出0;讀入,高四位含有按鍵信息
P3 = 0x0f; temL = P3; //然后反轉輸出0;讀入,低四位含有按鍵信息
switch(temH) {
case 0xe0: lie = 0; break;
case 0xd0: lie = 1; break;
case 0xb0: lie = 2; break;
case 0x70: lie = 3; break;
default: lie = 16;//按下的不是上述按鍵,就當是沒有按鍵
}
switch(temL)
{
case 0x0e: hang = 0; break;
case 0x0d: hang = 1; break;
case 0x0b: hang = 2; break;
case 0x07: hang = 3; break;;
default: hang = 16;//按下的不是上述按鍵,就當是沒有按鍵
}
retrun (hang -1)*4 + lie;
}
}
}

定時器的消抖法(裸奔程序):初始化keyvalue=一個不可能存在的值。

1當有按鍵按下時(keyolder),啟動定時器定時10MS(systick),然后退出;

2定時到后置位Flag_10MS,並讀按鍵值keynew

3if((Flag_10MS)&&(keyoder==keynew)) keyvalue=keynew;

4鍵值使用:

  if(keyvalue!=一個不可能存在的值)

  {

          ....

    }

 獨立按鍵的經典算法:可以簡潔的識別長按和短按,對於彈式按鍵和鎖式按鍵都適合(鎖式相當於長按)

PB0表示第一個按鍵

長按(2s):ReadData = 0x01;Trg = 0x00;Cont = 0x01;

短按:ReadData = 0x01;Trg = 0x01;Cont = 0x01;

無按鍵或彈起:ReadData = 0x00;Trg = 0x00;Cont = 0x00;

 

 

http://blog.csdn.net/caiyunfreedom/article/details/6543256#comments

核心算法

unsigned char Trg;

unsigned char Cont;

void KeyRead( void )/*每20MS調用一次*/

{

    unsigned char ReadData = PINB^0xff;   // 1

    Trg = ReadData & (ReadData ^ Cont);      // 2

    Cont = ReadData;                                // 3

}

 單片機按鍵識別篇---單擊---雙擊----長按:對按下和抬起都消抖,消抖后先記下按下的時間,如果按下的時間超過一定值說明為長按(長按累加重點是顯示),;如果抬起后超過一定時間沒有檢測到再次按下則為單擊否則為雙擊。

http://www.cnblogs.com/UPUPDay2152/p/9673886.html 

分享一個mini板按鍵KEY0單擊、雙擊(連續返回2個相同的值)、長按和串口實現燈的控制狀態

http://www.openedv.com/forum.php?mod=viewthread&tid=274729&extra=

 

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

    key_press = KEY0;                    // 讀按鍵IO電平

    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
        {
             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;
}

/*=============
在定時器10ms中斷中設立標志,在主程序中查詢標志,到了就執行該操作(即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;               // 第一次單擊,不返回,到下個轉態判斷后面是否出現雙擊
                 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內肯定讀到的都是無鍵事件,
                 if(++key_time_1 >= 50)        //因為長按>1000ms,低層返回都是無按鍵
                 {
                      key_return = S_key;      // 500ms內沒有再次出現單鍵事件,返回上一次的單鍵
                      key_m = key_state_0;     // 返回初始狀態
                 }
             }
             break;
    }
    return key_return;  
    }

 思考:外中斷按鍵的消抖。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM