Keypad Algorithm

Issues

Debounce

Auto-repeat (typematic)

Composite Key

Shift keys

Click Duration

Short Click
Long Click

Multi-Clicks

Single Click
Double Clicks
Triple Clicks

Detection

1-to-1 GPIO Mapping (for keys <= 4)
Key Scanning (for keys > 4)

Encode

From key detection to key representation

  • Set — bitmap
  • Code — ID
  • Virtual key

Time Constants

Debounce:

typical: 20ms ~ 50ms
max: 100ms

Short Click:

< 500ms (the time from press to release)

Long Press:

> 500ms (the press time)

Interval between clicks:

time between two clicks: < 700ms

A simple 4-stage encoder

Features:

  • Click (short, single), long press, and auto-repeat are supported
  • Composite Key is not supported,
    • although it is easy to be added on.
  • Prefers the key detection of 1-to-1 GPIO mapping
    • although to adopt matrix scanning is possible.
  • Python-like pseudo code is used
  • Easy to be implemented with C-like bit-wise operations

Stages:

S_Initial, S_Debounce, S_PressLong, S_Typematic = range(4)

Key Vectors

real

Generated by Key_real()
Key_real() — to get real press from GPIOs

press — debounced press

pressAcc

longAcc

repeatAcc

click — press (debounced) and free

clear after client's reading via Key_clicked()

click = set() # click.clear()

every debounce cycle (20~50 ms)
real = Key_real()
if stage == S_Initial:
    press = set() # press.clear()
    pressAcc = real
    if len(pressAcc) != 0:
        state = S_Debounce
else: # stage >= S_Debounce
    pressAcc &= real
    press |= pressAcc
    free = ~pressAcc
    if len(pressAcc) == 0: # NOTE: go back to S_Initial only when all keys are released
        state = S_Initial
    if stage != S_Typematic:
        click |= press & free

long — long press

clear after client's reading via Key_long()

long = set() # long.clear()

every long press check cycle (10~100 debounce cycles)
if stage == S_Debounce:
    longAcc = pressAcc.copy()
    if longAcc != 0:
        stage = S_PressLong

repeat — auto repeat (typematic) after a long press

clear after client's reading via Key_repeated()

repeat = set() # repeat.clear()

every repeat cycle (2~ debounce cycles)
if stage == S_PressLong:
    repeatAcc = pressAcc & longAcc
    if repeatAcc != 0:
        stage = S_Typematic
elif stage == S_Typematic:
    repeatAcc &= pressAcc & longAcc
    repeat |= repeatAcc

Prototype of public functions (in C style)

void Key_reset()
void Key_update()
 
Key Key_clicked()
Key Key_long()
Key Key_repeated()

Key matrix scanning

Prototype of public functions (in C style):

void init()
MS getKeyDownTime()
Key getKey()
void flush()
bool hit()

Suggested Readings

《匠人手记》11《按键漫谈》
《匠人手记》12《单个按键多次击键的检测方法》
《匠人手记》21《多种击键类型的处理流程图》
《一个按键的多次击键组合判别技巧》大话篇
《多个按键的连按处理技巧》大话篇
5个IO口扫描25个按键的解决方法

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License