вторник, 19 мая 2015 г.

Arduino и матричная клавиатура

Эта статья посвящена матричной клавиатуре. Я расскажу об устройстве клавиатуры, её возможностях. И, конечно, статья содержит программный код с подробными пояснениями.


Собственно матричная клавиатурка.


Схема.


Все предельно просто. Если ни одна из кнопок не нажата, то между вертикальными линиями (1, 2, 3, 4) и горизонтальными линиями (5, 6, 7, 8) нет контакта. Нажатие кнопочки приводит к возникновению контакта между одной из вертикальных линий (1, 2, 3, 4) и одной из горизонтальных линий (5, 6, 7, 8). Например, нажатие кнопки S1 приводит к возникновению контакта между линиями 4 и 5.

Единственное, я бы добавил токоограничительные резисторы.


Впрочем, никто не запрещает подключать эту клавиатурку к контроллеру через резисторы ом в 500. Это поспособствует защите контроллера от ошибок при подключении, а также программных ошибок.

Как работать с этой клавиатурой? Самая первая мысль, что приходит в голову, заключается в том, чтобы сконфигурировать выводы ардуино к которым подключены линии 1, 2, 3 и 4 как вход с включенным подтягивающим резистором. А выводы ардуино к которым подключены линии 5, 6, 7 и 8 сконфигурировать как выход и установить на них логический ноль. Пока ни одна из кнопок не нажата, на выводах ардуино связанных с линиями 1, 2, 3 и 4 будет логическая единица. Если кнопку нажать, то на одном из выводов ардуино связанном с линией 1, 2, 3 или 4 установится логический ноль. Но с любой из этих линий связано сразу четыре кнопки. Чтобы узнать какая конкретно кнопка нажата нужно изменить настройки. Выводы ардуино к которым подключены линии 1, 2, 3 и 4 следует сконфигурировать как выход и установить на них логический ноль. А выводы ардуино к которым подключены линии 5, 6, 7 и 8 необходимо сконфигурировать как вход с включенным подтягивающим резистором. Теперь логический ноль будет на одном из выводов ардуино связанном с линией 5, 6, 7 или 8. С каждой из этих линий также связано сразу четыре кнопки. Однако у каждой из линий 5, 6, 7 и 8 есть лишь одна общая кнопка с каждой из линий 1, 2, 3 и 4.  Кнопка, которая нажата, находится на пересечении линий на которых читается логический ноль при первом и при втором варианте настроек.

Для наглядности опишу как это все будет работать при нажатии кнопки S2. Выводы ардуино к которым подключены линии 1, 2, 3 и 4 сконфигурированы как вход с включенным подтягивающим резистором. Выводы ардуино к которым подключены линии 5, 6, 7 и 8 сконфигурированы как выход и на них установлен логический ноль. На выводах ардуино связанных с линиями 1, 2 и 4 будет читаться логическая единица. На выводе ардуино связанном с линией 3 будет читаться логический ноль. Такое возможно при нажатии одной из кнопок S2, S6, S10 и S14. Теперь настройки меняются. Выводы ардуино к которым подключены линии 1, 2, 3 и 4 сконфигурированы как выход и на них установлен логический ноль. Выводы ардуино к которым подключены линии 5, 6, 7 и 8 сконфигурированы как вход с включенным подтягивающим резистором. На выводах ардуино связанных с линиями 6, 7 и 8 будет читаться логическая единица. На выводе ардуино связанном с линией 5 будет читаться логический ноль. Такое возможно при нажатии одной из кнопок S1, S2, S3 или S4. У линий 3 и 5 есть лишь одна общая кнопка. Это кнопка S2. Нажатая кнопка находится на пересечении линий 3 и 5.

Программа.

////////////////////////
//
// Arduino Uno
//
////////////////////////
//
// Sketch: Matrix Keyboard
//

// Keyboard --- Arduino Uno
//
// 1 --- D11
// 2 --- D10
// 3 --- D9
// 4 --- D8
// 5 --- A0 (D14)
// 6 --- A1 (D15)
// 7 --- A2 (D16)
// 8 --- A3 (D17)

#include <util/delay.h>

void setup()
{
    DDRB = 0b00000000;
    PORTB = 0b00000000;
    DDRC = 0b00000000;
    PORTC = 0b00000000;
    DDRD = 0b00000000;
    PORTD = 0b00000000;

    Serial.begin(9600);
}

void loop()
{
    unsigned char x = 4, y = 4;

    DDRB = 0b00000000;
    PORTB = 0b00001111;
    _delay_us(10); // Wait 10 us
    DDRC = 0b00001111;
    PORTC = 0b00000000;
    _delay_us(10); // Wait 10 us

    if ((PINB & 0b00000001) == 0) x = 0;
    if ((PINB & 0b00000010) == 0) x = 1;
    if ((PINB & 0b00000100) == 0) x = 2;
    if ((PINB & 0b00001000) == 0) x = 3;

    DDRC = 0b00000000;
    PORTC = 0b00001111;
    _delay_us(10); // Wait 10 us
    DDRB = 0b00001111;
    PORTB = 0b00000000;
    _delay_us(10); // Wait 10 us

    if ((PINC & 0b00000001) == 0) y = 0;
    if ((PINC & 0b00000010) == 0) y = 1;
    if ((PINC & 0b00000100) == 0) y = 2;
    if ((PINC & 0b00001000) == 0) y = 3;

    if ( x != 4 && y != 4 )
        Serial.println(((y*4)+x+1));

    _delay_ms(1000); // Wait 1000 ms
}

//
// End
//
////////////////////////

Результат работы программы можно наблюдать в мониторе порта Arduino IDE.


Основным недостатком описанного алгоритма является некорректная работа при одновременном нажатии нескольких кнопок. Здесь нужно сказать, что есть алгоритм для матричной клавиатуры позволяющий корректно обрабатывать одновременное нажатие двух кнопок. Но про него я расскажу как нибудь позже.