Fork without short circuits

Dependents:   SaveKeypad

Fork of keypad by HM Yoong

No extra hardware is needed besides the wires and switches. The columns are outputs configured with open drain. The rows are inputs configured with pull up resistors. A key press pulls down its row. With scanning the column is determined thereafter.

See SaveKeypad for an example usage.

keypad.cpp

Committer:
gj_schoneveld
Date:
2012-11-08
Revision:
16:a9feaa7ac039
Parent:
15:873a9a452ef1

File content as of revision 16:a9feaa7ac039:

#include "keypad.h"

Keypad::Keypad(PinName row3, PinName row2, PinName row1, PinName row0,
               PinName col3, PinName col2, PinName col1, PinName col0,
               int debounce_ms):
    _row0(row0), _row1(row1), _row2(row2), _row3(row3),
    _cols(col0, col1, col2, col3)
{
    _debounce = debounce_ms;
    _rows[0] = &_row0;
    _rows[1] = &_row1;
    _rows[2] = &_row2;
    _rows[3] = &_row3;
    for (int r = 0; r < row_count; r++)
        _rows[r]->mode(PullUp);
    _cols.mode(OpenDrain);
    _cols.output();
}

void Keypad::_setupFallTrigger(void)
{
    for (int r = 0; r < row_count; r++)
        _rows[r]->fall(this, &Keypad::_callback);
}

void Keypad::Start(void)
{
    /* make the columns zero so they can pull rows down */
    _cols = 0x00;
}

void Keypad::Stop(void)
{
    /* make the columns one so they cannot pull any rows down anymore */
    _cols = ~0x00;
}

void Keypad::CallAfterInput(uint32_t (*fptr)(uint32_t index))
{
    _input.attach(fptr);
    _setupFallTrigger();
}

int Keypad::DebouncedScan()
{
    /* debounce */
    wait_ms(_debounce);

    return Scan();
}

int Keypad::Scan()
{
    /* lookup row */
    int r = -1;
    for (r = 0; r < row_count; r++) {
        if (*_rows[r] == 0)
            break;
    }

    /* if we didn't find a valid row, return */
    if (!(0 <= r && r < row_count))
        return -1;

    /* scan columns to find out which one pulls down the row */
    int c = -1;
    for (c = 0; c < col_count; c++) {
        _cols = ~(1 << c);
        if (*_rows[r] == 0)
            break;
    }

    /* re-energize all columns */
    Start();

    /* if we didn't find a valid column, return */
    if (!(0 <= c && c < col_count))
        return -1;

    return r * col_count + c;
}

int Keypad::DebouncedScanMultiple()
{
    /* debounce */
    wait_ms(_debounce);

    return ScanMultiple();
}

int Keypad::ScanMultiple()
{
    int res = 0;
    for (int c = 0; c < col_count; c++) {
        _cols = ~(1 << c);
        for (int r = 0; r < row_count; r++) {
            if (*_rows[r] == 0) {
                res |= 1 << (r * col_count + c);
            }
        }
    }

    return res;
}

void Keypad::_callback()
{
    /* lookup */
    int position = DebouncedScan();

    /* call back a valid position */
    if (position >= 0)
        _input.call(position);
}