Урок 18. Подключение матрицы кнопок к Ардуино. Библиотека MatrixKeys. Функция tone().

 

Lesson18_0

Научимся подключать к плате Ардуино матрицу кнопок, использовать для генерации звука стандартную функцию tone().

Предыдущий урок     Список уроков     Следующий урок

В предыдущих уроках мы подключали кнопки к контроллеру, используя для каждой отдельный вывод. Если необходимо использовать в системе большое число кнопок, такое решение может оказаться неприемлемым. Просто не хватит выводов микроконтроллера.

 

Существует другой способ подключения кнопок к плате Ардуино – объединение кнопок в матрицу.

Подключение матрицы кнопок к микроконтроллеру.

Вот пример схемы такой матрицы.  Для подключения 16 кнопок требуется только 8 выводов микроконтроллера.

Схема матрицы кнопок

Кнопки подключены к вертикальным и горизонтальным линиям матрицы. Состояние кнопок для каждой вертикальной линии проверяется отдельно. На вертикальную линию подается сигнал высокого уровня (5 В) и считываются состояния горизонтальных линий. Высокий уровень в горизонтальной линии покажет, что соответствующая кнопка нажата. Далее проверяются остальные вертикальные линии.

Резисторы обеспечивают нулевое напряжение на входах микроконтроллера при разомкнутых кнопках.

Такая схема часто используется для подключения матрицы кнопок к плате Ардуино в практических приложениях. Что меня удивляет. Ведь эта схема работает некорректно при одновременном нажатии двух и более кнопок из одной горизонтальной линии. В этом случае:

  • Результат будет непредсказуемым. Через горизонтальную линию и две нажатые кнопки замкнутся вертикальные линии с высоким и низким уровнями сигнала. Какая вертикальная линия перетянет, такой уровень и будет на горизонтальной линии.
  • Произойдет замыкание выводов микроконтроллера с разными уровнями сигналов. В лучшем случае повысится потребляемый ток, и микроконтроллер будет нагреваться.

Схема замыкания

Для устранения этой проблемы достаточно подключить вертикальные линии через диоды. Тогда замыкание выводов контроллера невозможно при любом количестве одновременно нажатых кнопок. Также схема с диодами позволит корректно определять состояние матрицы с двумя одновременно нажатыми кнопками. При нажатых трех соседних кнопках произойдет замыкание четвертой.

Схема замыкания

 

Подключение матрицы кнопок к плате Ардуино.

Подключим матрицу кнопок 3x4 к плате Ардуино по такой схеме.

Схема подключения матрицы кнопок к АрдуиноХороший стиль - нажатие каждой кнопки сопровождать коротким звуковым сигналом. Для это подключим к плате звуковой пьезоизлучатель.  У меня все это выглядит так.

Подключение матрицы кнопок к Ардуино

 

Библиотека сканирования матричной клавиатуры 4 x 4.

Я разработал библиотеку для сканирования матричной клавиатуры MatrixKey.h.

Загрузить ее можно по ссылке:

Зарегистрируйтесь и оплатитеВсего 60 руб. в месяц за доступ ко всем ресурсам сайта!

Как установить написано в уроке 9.

Библиотека MatrixKey:

  • определяет текущее состояние каждой кнопки;
  • вырабатывает признаки “была нажата” для каждой кнопки (клики);
  • устраняет дребезг контактов кнопок;
  • сканирование матрицы происходит параллельным процессом, основная программа работает только с готовыми признаками.

Библиотека имеет конструктор и только одну функцию.

MatrixKeys(byte verticalPin1, byte verticalPin2, byte verticalPin3, byte verticalPin4, byte horizontalPin1, byte horizontalPin2, byte horizontalPin3, byte horizontalPin4, byte numAckn)

Конструктор, создает объект с заданными параметрами.

  • verticalPin1, verticalPin2, verticalPin3, verticalPin4 - номера выводов подключения вертикальных линий матрицы 1, 2, 3 ,4;
  • horizontalPin1, horizontalPin2, horizontalPin3, horizontalPin4 - номера выводов подключения горизонтальных линий матрицы 1, 2, 3 ,4;
  • numAckn - число подтверждений состояния контактов.

/создаем объект матрица кнопок keys
// подключаем вертикальные линии к выводам 9, 10, 11, 12
// подключаем горизонтальные линии к выводам 4, 5, 6, 7
// число подтверждений состояния контактов = 6
MatrixKeys  keys(9, 10, 11, 12, 4, 5, 6, 7, 6);

Отдельные выводы матрицы можно отключить, задав для них в конструкторе номера  равные 255. Это может потребоваться при подключении матрицы меньшей размерности.

void  scanState()

Метод сканирует состояние кнопок матрицы. Не имеет параметров, ничего не возвращает.

Для устранения дребезга кнопок используется способ ожидания стабильного состояния контактов, описанный в уроке 6. В параллельном процессе должен регулярно вызываться метод scanState().

//-------------------------------------- обработчик прерывания 2 мс
void  timerInterrupt() {
  keys.scanState(); // сканирование матрицы
}

В результате формируются признаки массивов flagPress[4][4] и flagClick[4][4]:

  • при нажатой кнопке flagPress= true;
  • при отжатой кнопке flagPress= false;
  • при нажатии на кнопку flagClick= true.

Признак flagPress показывает текущее состояние кнопки и изменяет свое значение в зависимости от состояния кнопки.

Признак flagClick становится активным в момент нажатия кнопки и остается в таком состоянии до тех пор, пока не будет сброшен программой. Класс MatrixKeys только устанавливает его в активное состояние.

Типичная работа с флагом flagClick – это проверка признака в основном цикле, сброс его и выполнение определенного действия, запланированного по нажатию кнопки. Этот флаг запоминает, что было нажатие и хранит информацию об этом до его сброса.

В отличие от известной библиотеки Keypad библиотека MatrixKeys:

  • значительно компактнее и быстрее;
  • ориентирована на использование в параллельном процессе, основная программа работает только с готовыми признаками;
  • надежно обрабатывает дребезг контактов, позволяет задавать число подтверждений состояния кнопок.
  • сканирование матрицы происходит регулярно, с определенным периодом без пропусков и задержек.

 

Стандартная функция генерации звука tone().

Для формирования звукового сигнала по нажатию кнопок можно использовать стандартную функцию tone(). Функция генерирует на заданном выводе сигнал прямоугольной формы.

void tone(pin, frequency)
void tone(pin, frequency, duration)

Аргументы:

  • pin – номер вывода;
  • frequency – частота сигнала в Гц;
  • duration – длительность сигнала в миллисекундах.

Если длительность сигнала не задана третьим аргументом, то  сигнал вырабатывается до тех пор пока не будет вызвана функция noTone().

Необходимо помнить, что для генерации сигнала функция tone() использует Таймер 2 платы Ардуино. Поэтому, если этот таймер уже используется в программе, например для формирования прерывания, то функция tone() приведет к конфликту обращения к таймеру 2. По этой причине я не создал в классе возможности сопровождения нажатия кнопок звуковым сигналом. Лучше это желать вне класса, используя в каждом конкретном случае свой способ.

 

Практическое использование библиотеки MatrixKeys.

Напишем простую программу для проверки и демонстрации библиотеки  MatrixKeys.h. Программа передает на компьютер по последовательному порту состояние матрицы кнопок:

  • нажатая кнопка отображается как ”*”;
  • отжатая – ”.”;
  • момент нажатия кнопки (клик) отображается символом ”=” в течение 0,5 секунд.

// матрица кнопок
#include <MatrixKeys.h>
#include <MsTimer2.h>

// создаем объект матрица кнопок keys
// подключаем вертикальные линии к выводам 9, 10, 11, 12
// подключаем горизонтальные линии к выводам 4, 5, 6, 7
// число подтверждений состояния контактов 6
MatrixKeys  keys(9, 10, 11, 12, 4, 5, 6, 7, 6);

void setup() {
  Serial.begin(9600); // инициализируем порт, скорость 9600
  MsTimer2::set(2, timerInterrupt); // задаем период прерывания по таймеру 2 мс
  MsTimer2::start();               // разрешаем прерывание по таймеру
}

void loop() {

  // перебор строк
  for (int i = 0; i < 4; i++) {
   
    // перебор столбцов
    for (int j = 0; j < 4; j++) {

      if (keys.flagClick[j][i] == true) { Serial.print("="); keys.flagClick[j][i]=false; tone(8,1000,50); }
      else { if (keys.flagPress[j][i] == true) Serial.print("*"); else Serial.print("."); }     
    }      
      Serial.println(" ");    
  }

  Serial.println(" ");
  delay(500);
}

//-------------------------------------- обработчик прерывания 2 мс
void  timerInterrupt() {
  keys.scanState(); // сканирование матрицы
}

Загрузите программу в плату. Не забудьте установить библиотеки MatrixKeys.h и MsTimer2.h. Откройте монитор последовательного порта. На экране, каждые 0,5 секунды, будут пробегать блоки состояния матрицы.

Окно монитора порта

Нажимая на кнопки матрицы можно проверить работу программы.

Если необходимо передавать код нажатой клавиши, то можно преобразовать состояние массива признаков кликов keys.flagClick[4][4] в коды кнопок  codKeys[4][4].

// матрица кнопок
#include <MatrixKeys.h>
#include <MsTimer2.h>

// массив кодов кнопок
const char codKeys[4][4] = 
{ {'1', '4', '7', '*'},
  {'2', '5', '8', '0' },
  {'3', '6', '9', '#'},
  {' ', ' ', ' ', ' '}
};

// создаем объект матрица кнопок keys
// подключаем вертикальные линии к выводам 9, 10, 11, 12
// подключаем горизонтальные линии к выводам 4, 5, 6, 7
// число подтверждений состояния контактов 6
MatrixKeys  keys(9, 10, 11, 12, 4, 5, 6, 7, 6);

void setup() {
  Serial.begin(9600); // инициализируем порт, скорость 9600
  MsTimer2::set(2, timerInterrupt); // задаем период прерывания по таймеру 2 мс
  MsTimer2::start();               // разрешаем прерывание по таймеру
}

void loop() {

  // вычисление кода нажатой кнопки
  // перебор столбцов
  for (int i = 0; i < 4; i++) {
    // перебор строк
    for (int j = 0; j < 4; j++) {
      if (keys.flagClick[i][j] == true) {
        keys.flagClick[i][j]=0; 
        Serial.println(codKeys[i][j]);
        } 
    }      
  }
}

//-------------------------------------- обработчик прерывания 2 мс
void  timerInterrupt() {
  keys.scanState(); // сканирование матрицы
}

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

Окно монитора порта

При необходимости Вы легко сможете переделать библиотеку на матрицу кнопок других размерностей.

 

В следующем уроке будем подключать к плате Ардуино семисегментные светодиодные индикаторы.

 

Предыдущий урок     Список уроков     Следующий урок

2

Автор публикации

не в сети 4 дня

Эдуард

280
Комментарии: 1936Публикации: 197Регистрация: 13-12-2015

53 комментария на «Урок 18. Подключение матрицы кнопок к Ардуино. Библиотека MatrixKeys. Функция tone().»

  1. Почему у 4 кнопки не обнуляем признак?:
    сброс всех признаков
    i= 0; while (i < 3){…i++}

    0
  2. Надо ли в конструкторе сделать digitalWrite(_verticalPins[_scanVertLine], HIGH); для первой линии,
    а то она при первом обходе пропускается?

    0
    • Здравствуйте!
      В случае применения цифровой фильтрации кнопок или матрицы достоверный результат о состоянии кнопок появляется только через определенное время. Поэтому в реальных программах желательно в течение этого времени не использовать признаки состояния.
      Например, можно в setup() в цикле вызвать несколько раз функцию scanState(). После этого все признаки будут соответствовать реальному состоянию кнопок.

      0
      • Спасибо!
        Ещё.
        «Если необходимо передавать код нажатой клавиши, то можно преобразовать состояние массива признаков кликов keys.flagClick[4][4] в коды кнопок codKeys[4][4].»
        А как же дребезг?

        0
          • Эдуард, Здравствуйте!

            Прежде всего хочу поблагодарить Вас за замечательный сайт. К сожалению, я нарвался на него только сейчас. Уже 5 утра а я оторваться не могу. )))

            Однако с этой конкретной статьей я не совсем согласен в части критики стандартной схемы подключения клавиатуры. Цитата:

            «Ведь эта схема работает некорректно при одновременном нажатии двух и более
            кнопок из одной горизонтальной линии…»

            В свое время я собаку съел на программировании работы с клавиатурой. 4×4 и 3×4

            Программируемое устройство позволяло распознавать любое сочетания любых клавиш с заданной длительностью.
            То есть генерировалось событие

            например

            на 5 сек одновременное нажатие клавиш * 0 #
            на 3 сек одновременное нажатие клавиш * #
            на 0.5 сек е нажатие одиночных клавиш 0 — 9 * #

            Детали я не помню (могу код поискать) но точно помню ЧТО

            1. Клавиатура подключалась просто к одному из портов. Вроде был PortB.
            Важно что он имел внутренние подтягивающие резисторы.

            2. Строки к 4 старшим битам, столбцы к 4 младшим битам (можно и наоборот)

            3. Чтение клавиатуры занимало всего 7-12 строк и было двухтактным.

            4. Не было ни диодов ни резисторов. Пины клавиатуры шли напрямую к пинам контроллера и все
            I.

            4 младших бита 4 переводились в режим приема с включением внутренних подтягивающих резисторов

            4 старших бита переводились в режим передачи и на них подавался логический 0

            далее читались 4 младших бита и помещались в младших 4 бита регистра результата

            II.

            4 старших бита 4 переводились в режим приема с включением внутренних подтягивающих резисторов

            4 младших бита переводились в режим передачи и на них подавался логический 0

            далее читались 4 старших бита и помещались в старших 4 бита регистра результата

            В результате в регистре оказывался скан-код, который показывал произвольно сочетание клавиш

            0 в старших 4-битах показывал строки нажатых клавиш

            0 в младших 4-битах показывал столбцы нажатых клавиш

            Для красоты я его инвертировал. Что бы 0 соответствовал не нажатие ни одной клавиши. а FF нажатие всех клавиш

            Код был очень компактным 7 — 10 команд, из которых было пару NOPов

            Далее этот код помещался в обработчик прерывания таймера
            новое значение сканкода сравнивалось с предыдущим и если оно
            совпадало включался счетчик. Если не совпадал то сбрасывался.
            По достижении счетчика порогового значения генерировалось событие
            такое-то сочетание клавишь с такой-то длительностью наступило.

            Если интересно могу код поискать

            ичь

            (порт имел внутренние подтягивающие регистры) без как либо

            на один порт

            например

            0
  3. Спасибо,увидел:
    if ( flagPress[_scanVertLine][_scanHorizLine] == true )
    flagClick[_scanVertLine][_scanHorizLine]= true; // признак клика кнопки

    0
  4. НАШЕЛ КОД опроса на языке Си
    В силу его тривиальности его можно даже на
    ассемблер переписать

    // Функция производит опрос клавиатуры

    // Клавиатура подключена к 8 битам порта PORTB
    // Биты с 0 по 3 подключены к строкам клавиатуры
    // Биты с 4 по 7 подключены к столбцам клавиатуры

    // возвращает сканкод нажатой клавиши.
    // 1 в битах 0-3 показывает строку нажатой(ых) клавиши
    // 1 в битах 4-7 показывает столбец нажатой(ых) клавиши

    #define PORT_PAUSE_CYCLE 4 // Число операций NOP между подтяжкой резисторов и чтения из порта

    uint08 GetKeyScanCode(void)
    {uint08 c = 0, r = 0, k = 0;

    CLI(); // запрещаем прерывания

    // чтение номера строки
    DDRB = 0xF0; // 0b11110000; // старшие 4 бита на запись младшие на чтение
    PORTB = 0x0F; // 0b00000000; // включаем подтягивающие регистры на всех входах (на выходах они уже выключены)
    PauseNOP(PORT_PAUSE_CYCLE); // делаем паузу в несколько NOP
    r = PINB; // читаем из порта младшие 4 бита (

    // чтение номера столбца
    DDRB = 0x0F; // 0b00001111; // старшие 4 бита на чтение младшие на запись
    PORTB = 0xF0; // 0b00000000; // включаем подтягивающие регистры на всех входах (на выходах они уже выключены)
    PauseNOP(PORT_PAUSE_CYCLE); // делаем паузу в несколько NOP
    c = PINB; // читаем из порта старшие 4 бита

    r = ~r; // обращаем биты строк (что бы нажатие показывалось единицами)
    c = ~c; // обращаем биты столбцов (что бы нажатие показывалось единицами)

    r &= 0x0F; // 0b00001111 // выделяем только младшие 4 бита (строки)
    c &= 0xF0; // 0b11110000 // выделяем только старшие 4 бита (столбцы)

    k = c|r; // объединяем всё (в старших битах столбцы в младших строки)

    SEI(); // разрешаем прерывания

    return k;
    }

    0
    • Здравствуйте Ярослав. Я только начинаю программировать для Ардуино. Ваш код показался мне очень интересным только для меня не совсем понятно что такое unit08 и PORTB. А без понимания этого сложно понять как скетч работает.

      0
      • Здравствуйте!
        Элемент Пельтье вполне допускает работу в качестве нагревателя. Думаю, если делать изменение полярности плавно и не часто, то это безопасный режим.

        0
      • Здравствуйте!
        PORTB это обозначение порта ввода/вывода в микроконтроллере ATMega328. Это то, что в Ардуино мы называем выводами. Посмотрите схему платы Arduino UNO в уроке 2. Вы увидите, что pin 8 соответствует сигналу микроконтроллера PB0 (PORTB разряд 0) и т.д. У ATMega328 существуют PORTB, PORTC и PORTD.
        Что касается unit08. Возможно вы имели в виду uint8_t. Это другое обозначение переменной типа byte.

        0
  5. Забыл дать код вспомогательной функции
    вот он.

    // Вспомогательная функция
    void PauseNOP(uint16 n)
    {
    while (n)
    {
    NOP();
    n—;
    }
    }

    0
  6. Еще нужно обнулить в посл. цикле keys.flagPress[i][j]=0 чтобы одинаковые символы печатались друг за другом

    0
  7. Здравствуйте, спасибо за полезный труд!
    Вопрос: можно-ли избежать конфликта библиотек MatrixKeys.h и Wire.h? Версия Arduino 1.6.5.

    0
  8. Может быть дело в скетче или выборе пинов, посоветуйте, пожалуйста.
    #include
    #include
    #include
    #include
    // массив кодов кнопок
    const int codKeys[4][4] =
    { {1, 4, 7, 14},
    {2, 5, 8, 0 },
    {3, 6, 9, 15},
    {10, 11, 12, 13}
    };

    // создаем объект матрица кнопок keys
    // подключаем вертикальные линии к выводам 9, 10, 11, 12
    // подключаем горизонтальные линии к выводам 4, 5, 6, 7
    // число подтверждений состояния контактов 8
    MatrixKeys keys(5, 4, 3, 2, 9, 8, 7, 6, 8);
    iarduino_I2C_connect I2C2;

    int key = 0; //порядок или количество нажатых клавиш
    int prog = 0; //цель ввода с клавиатуры — номер подпрограммы
    int ones = 0; //единицы
    int tens = 0; //десятки
    int hundrs = 0; //сотни
    byte REG_Array[7]={0,0,0,0,0,0,0}; // объявляем массив, данные которого будут доступны для чтения/записи по шине I2C

    //————————————— обработчик прерывания 2 мс
    void timerInterrupt()
    {
    keys.scanState(); // сканирование матрицы
    }
    void setup() {
    Wire.begin(0x01);
    I2C2.begin(REG_Array);
    // Serial.begin(9600); // инициируем подключение к COM-порту на скорости 9600 бот

    MsTimer2::set(2, timerInterrupt); // задаем период прерывания по таймеру 2 мс
    MsTimer2::start(); // разрешаем прерывание по таймеру
    /*REG_Array[0] = 0; // единицы
    REG_Array[1] = 0; // десятки
    REG_Array[2] = 0; // сотни
    REG_Array[3] = 0; // ввод
    REG_Array[4] = 0; // какая-то кнопка нажата
    REG_Array[5] = 0; // ответ от мастера: ввод произведен, обнуляй массив
    REG_Array[6] = 0; // разрешена обработка клавиатуры при 0*/
    }

    void loop()
    {

    // вычисление кода нажатой кнопки
    // перебор столбцов
    for (int i = 0; i < 4; i++)
    {
    // перебор строк
    for (int j = 0; j < 4; j++)
    {
    if (keys.flagClick[i][j] == true && REG_Array[6] == 0)// если кнопка нажата и есть разрешение от мастера
    {
    keys.flagClick[i][j] = false;
    REG_Array[4] = 1; // разрешение мастеру на считывание числа для индикации
    if (codKeys[i][j] <= 9 && key 0) // стираем последнюю цифру
    {
    prog = prog / 10;
    key—;
    }
    hundrs = prog / 100;
    tens = (prog — hundrs * 100) / 10;
    ones = prog — hundrs * 100 — tens * 10;
    REG_Array[2] = hundrs;
    REG_Array[1] = tens;
    REG_Array[0] = ones;

    if (codKeys[i][j] == 14) // разрешение мастеру на присвоение номера подпрограмме
    {
    REG_Array[3] = 1;
    key = 0;
    }
    // Serial.println(codKeys[i][j]);
    }
    else keys.flagClick[i][j] = 0;
    if (REG_Array[5] == 1) // обнуляем массив если матер ввел номер подпрограммы
    {
    REG_Array[0] = 0; REG_Array[1] = 0; REG_Array[2] = 0; REG_Array[3] = 0; REG_Array[4] = 0; REG_Array[5] = 0;
    }
    }
    }
    }
    Изменена опция сборки, пересобираем все
    collect2.exe: error: ld returned 5 exit status
    Ошибка компиляции.

    0
  9. Почему-то не вставляются названия подключаемых библиотек, они таковы: Wire.h, MatrixKeys.h, MsTimer2.h, iarduino_I2C_connect.h..

    0
  10. Пробую переделать весь скетч для одной ардуинки, уже определил, что MatrixKeys.h не конфликтует с Wire.h, возможно конфликт с iarduino_I2C_connect.h или другие причины.

    0
    • Здравствуйте!
      Посмотрите в интернете, что пишут об этой ошибке.
      Пишут, что она бывает с Windows XP. Советуют, я цитирую:

      Сбой под Windows XP вызывала новая версия файла ld.exe, находящегося по адресу

      c:\Program Files (x86)\Arduino\hardware\tools\avr\avr\bin\

      Для решения была скачана старая версия программы ARDUINO 1.0.6 — Windows ZIP file for non admin install

      Эта и другие старые версии лежат по адресу https://www.arduino.cc/en/Main/OldSoftwareReleases#previous

      После чего подменяем файл ld.exe из старой версии программы. В моём случае это решило проблему, и на данный момент всё у меня компилируется без проблем.

      0
  11. Привет, Эдуард! Я решил попробовать вместо матрицы кнопок использовать ИК пульт. Одна ардуинка slave с пультом хорошо свое отрабатывает, передается на master все правильно, но возникают какие-то ошибки при отображении принятых данных (непрерывно на master передается число до трех разрядов, в каждом байте свой разряд, и еще вспомогательные кое-какие байты для подтверждения и пр., возможно стирание последней цифры и ввод, после нажатия «ввод» на slave принятое мастером значение присваивается рабочей переменной и используется по назначению), вот иногда отображались нули вместо значащих разрядов или совсем непохожее значение, возможно считываться не успевало. Так вот я решил исключить Slave и подключить ИК приемник прямо к Master, но при этом с ИК пультом все нормально, а кнопки считываться перестали. Библиотека IRremote ранней версии. Посмотрел в IRremote.cpp, оказалось — используется Timer2.
    В моей программе используются библиотеки , , , .
    Подскажите, пожалуйста, в чем может быть причина.
    Эдуард, возможно ли решить совместную работу

    0
    • Здравствуйте!
      Я не никогда не использовал эту библиотеку. Попробуйте используйте в своей программе другие таймеры.

      0
  12. Эдуард, я, наверное, неполно описал проблему. Дело в том, для прерываний была использована библиотека Mstimer2, попробовал прерывать через millis()? заработала, но тормозила. Тогда, благодаря вашему уроку, сделал прерывания для опроса кнопок на базе TimerOne, все вроде сносно заработало. Спасибо!

    0
  13. Приветствую!
    Эдуард, как правильно организовать в основном цикле программы, используя MatrixKeys функцию, подобной в библиотеке Keypad, button = Keypad.getKey();
    Мне необходимо узнать какая одна клавиша была нажата.

    0
    • Здравствуйте!
      Перебрать значения флагов, как в примере урока. Функция должна выглядеть как-то так.

      // возвращает код первой нажатой кнопки
      byte getKey() {
      // перебор строк
      for (int i = 0; i < 4; i++) { // перебор столбцов for (int j = 0; j < 4; j++) { if (keys.flagClick[j][i] == true) return(i | (j<<2)); } return(255); } }

      0
  14. Здравствуйте!
    В одних схемах подключения клавиатуры присутствуют резисторы, в других — нет.
    Зачем вообще нужны сопротивления при подачи логических сигналов? И как правильно их рассчитывать?
    Спасибо!

    0
    • Здравствуйте!
      В схеме из урока резисторы нужны обязательно.
      Когда кнопка нажата, на вход поступает напряжение из соответствующей вертикальной линии. На входе формируется логическая 1.
      Если кнопка разомкнута или на вертикальной линии, к которой она подключена, ноль, то вход брошен в воздухе. Его состояние не определено. Резисторы формируют логический ноль для этих случаев.
      Резисторы скорее выбираются, чем рассчитываются. Чем меньше сопротивление резисторов, тем выше помехозащищенность и тем больше нагрузка на выходы микроконтроллера, подключенные к вертикальным линиям.
      Минимальное сопротивление 5 В / 20 мА = 250 Ом.
      Максимальное сопротивление ограничено токами утечки и входной емкостью входов микроконтроллера.
      Я бы рекомендовал выбирать резисторы от 1 до 10 кОм в зависимости от длины линий матрицы кнопок.

      0
      • Вроде понял. Но еще хотелось бы уточнить.
        Если представить гипотетическую коммутацию, в которой мне нужно просто соединить 5в Arduino с одним из входов. Можно это делать без резистора?
        Благодарю!

        0
        • Здравствуйте!
          5 В на вход без ограничительного резистора подавать можно. Но какой смысл? Этот сигнал нельзя замыкать на землю кнопкой или другим сигналом.

          0
  15. Приветствую!
    Возник такой вопрос: будет ли корректно работать одновременное нажатие двух кнопок при подключении вышеизложенной схемы через сдвиговый регистр (по трем проводам) к Ардуине?

    0
    • Здравствуйте!
      Я не понял, как матрицу включить через сдвиговый регистр. Выложите схему на форуме сайта. Обсудим.

      0
    • variator, при правильном программировании можно обнаруживать любое произвольное сочетание кнопок (как и их отсутствие). Берете матрицу кнопок 4×4

      // Биты с 0 по 3 PortB подключаете к строкам клавиатуры
      // Биты с 4 по 7 PortB подключаете к столбцам клавиатуры

      Далее ищите код из моих комментариев. Функция uint08 GetKeyScanCode(void) выдает 8 битный скан-код, который передает любое произвольное сочетание нажатых — не нажатых клавиш.

      Единицы в битах 0-3 означает, что нажата хотя бы одна кнопка в соответствующей строке. Единицы в битах 4-7 означает, что нажата хотя бы одна кнопка в соответствующем столбце. Код простой тривиальный и не надо ни резисторов ни диодов не циклов.

      Цикл используется только для паузы, но можно обойтись и несколькими NOP вместо функции PauseNOP(PORT_PAUSE_CYCLE);

      0
  16. Здравствуйте, Эдуард!
    1. «При одновременном нажатии двух кнопок произойдет замыкание выводов микроконтроллера с разными уровнями сигналов. В лучшем случае повысится потребляемый ток, и микроконтроллер будет нагреваться».
    Не пойму, в чем различие со случаем, если нажимать только одну кнопку? Ведь при этом сигнал также идет с пина на пин. Почему не происходит нагрева?

    2. Если нужно, чтобы клавиатура срабатывала по прерыванию, следует четыре горизонтальных линии через диоды параллельно направить на пин прерывания?

    0
    • Здравствуйте!
      Имеется в виду, что замыкаются два выхода, имеющие разные состояния. При нажатии на одну кнопку замыкается выход со входом.
      На счет прерывания, существуют разные варианты. Я предпочитаю сканирование кнопок.

      0
      • Здравствуйте! Большое спасибо за уроки! Хотел добавить о подключении матрицы. Она подключается только к входам, что по вертикали, что по горизонтали с подтягивающими резисторами. А считывается потенциалы сформированные на входах!

        0
  17. Добрый день.
    В scanState() можно вынести и объединить два обнуления buttonCount. Код уменьшится.

    0
  18. Добрый день.
    Ардуино Мега.
    Добавил в пример с массивом вывод в компорт:
    [code]
    void timerInterrupt() {
    Serial.println(«Scan»);
    keys.scanState(); // сканирование матрицы
    }
    [/code]
    Ожидал увидеть в мониторе бесконечный Scan, но ничего не выводится. Почему так м.б.?

    0
    • Здравствуйте!
      Вы вызываете функцию print каждую миллисекунду. А на передачу текста Scan при скорости 9600 требуется 6 мс. Функция нормально работать не будет.

      0
  19. Здравствуйте! Если у меня имеется 14 кнопок. То лучше переписать библиотеку для матрицы 2х7? Или другой вариант?

    0
    • Здравствуйте!
      Если задача уникальная, то лучше написать свой программный блок обработки кнопок без библиотеки.

      0
  20. Да не очень уникальная. Я сначала сделал матрицу кнопок 2х7 и переписал библиотеку на 2х7, но видимо, не правильно

    0
  21. Здравствуйте!
    «При одновременном нажатии двух кнопок произойдет замыкание выводов микроконтроллера с разными уровнями сигналов. В лучшем случае повысится потребляемый ток, и микроконтроллер будет нагреваться», далее размышления про диоды на линии. Если ставить диоды не на линии, а на каждую кнопку не произойдет замыкания и опрашивать матрицу можно будет только с одной стороны

    0
  22. На uno всё отлично запускается и работает. Но при записи на mega 2560 ничего не происходит: монитор порта пустой, все 8 рабочих пинов без напряжения (нет прогона каждые 2мс). В чём может быть дело?
    Заранее спасибо

    0
  23. Эдуард, а не подскажете немного кода, как сделать так, чтобы в цикле в каждой итерации ожидалось очередное нажатие кнопки ?

    0
    • Здравствуйте! Проверяем флаг, если активен, то сбрасываем его и выполняем действия по нажатию.

      void loop() {

      if( keys.flagClick[0][0] == true ) {
      keys.flagClick[0][0]=false;
      // нажали кнопку 0,0
      }

      }

      0

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Нажимая кнопку "Отправить" Вы даёте свое согласие на обработку введенной персональной информации в соответствии с Федеральным Законом №152-ФЗ от 27.07.2006 "О персональных данных".