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

Arduino UNO R3

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

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

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

 

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

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

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

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

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

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

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

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

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

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

 

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

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

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

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

Класс сканирования матрицы кнопок.

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

Класс должен:

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

Я приведу сразу исходный текст класса MatrixKeys. Как он работает понятно из комментариев.

// описание класса сканирования матрицы кнопок
class MatrixKeys  {
  public:
    boolean flagPress[4][4]; // признаки кнопка в нажатом состоянии
    boolean flagClick[4][4]; // признаки нажатия кнопки (клик)
    void  scanState();    // метод проверки состояния кнопок
    // конструктор
    MatrixKeys(byte verticalPin1, byte verticalPin2, byte verticalPin3, byte verticalPin4,
               byte horizontalPin1, byte horizontalPin2, byte horizontalPin3, byte horizontalPin4,
               byte numAckn);   
  private:
    byte  _verticalPins[4];   // выводы вертикальных линий
    byte  _horizontalPins[4]; // выводы горизонтальных линий
    byte  _buttonCount[4][4]; // счетчики подтверждения состояния кнопок
    byte _numAckn;          // число подтверждений состояния кнопок
    byte  _scanVertLine;    // номер сканируемой вертикальной линии
    byte  _scanHorizLine;    // номер сканируемой горизонтальной линии
} ;

 

//---------------------------- конструктор
MatrixKeys::MatrixKeys(byte verticalPin1, byte verticalPin2, byte verticalPin3, byte verticalPin4,
                       byte horizontalPin1, byte horizontalPin2, byte horizontalPin3, byte horizontalPin4,
                       byte numAckn)  {

  // загрузка массивов выводов
  _verticalPins[0]= verticalPin1; _verticalPins[1]= verticalPin2; _verticalPins[2]= verticalPin3; _verticalPins[3]= verticalPin4;
  _horizontalPins[0]= horizontalPin1; _horizontalPins[1]= horizontalPin2; _horizontalPins[2]= horizontalPin3; _horizontalPins[3]= horizontalPin4;

  // перегрузка остальных аргументов
  _numAckn= numAckn;
 
  // инициализация выводов матрицы
  byte i= 0;
  while (i < 4) {

    if ( _verticalPins[i] != 255 ) {    // если вывод не отключен   
      pinMode(_verticalPins[i], OUTPUT);
      digitalWrite(_verticalPins[i], LOW);
    } 

    if ( _horizontalPins[i] != 255 )     // если вывод не отключен   
      pinMode(_horizontalPins[i], INPUT);
   
    i++;       
  }

    _scanVertLine= 0;   // номер сканируемой вертикальной линии
    _scanHorizLine= 0;  // номер сканируемой горизонтальной линии

  // сброс всех признаков
    i= 0; while (i < 3) {
            flagPress[i][0]= false; flagPress[i][1]= false; flagPress[i][2]= false; flagPress[i][3]= false;
            flagClick[i][0]= false; flagClick[i][1]= false; flagClick[i][2]= false; flagClick[i][3]= false;          
            _buttonCount[i][0]= 0; _buttonCount[i][1]= 0; _buttonCount[i][2]= 0; _buttonCount[i][3]= 0;
            i++;
          }                          
  }
 
//-------------------------------- метод проверки состояния кнопок
// при нажатой кнопке flagPress= true
// при отжатой кнопке flagPress= false
// при нажатии на кнопку flagClick= true
void  MatrixKeys::scanState() {

  if ( _verticalPins[_scanVertLine] != 255 ) {    // если вывод не отключен   

  // опрос кнопок горизонтальных линий
  _scanHorizLine= 0;  while ( _scanHorizLine < 4 ) {
   
 if ( flagPress[_scanVertLine][_scanHorizLine] == digitalRead(_horizontalPins[_scanHorizLine]) )
    //  состояние кнопки осталось прежним
    _buttonCount[_scanVertLine][_scanHorizLine]= 0;  // сброс счетчика подтверждений

  else  {
     // состояние кнопки изменилось
     _buttonCount[_scanVertLine][_scanHorizLine]++;   // +1 к счетчику подтверждений

    if ( _buttonCount[_scanVertLine][_scanHorizLine] >= _numAckn ) {
      // состояние кнопки стало устойчивым
      flagPress[_scanVertLine][_scanHorizLine]= ! flagPress[_scanVertLine][_scanHorizLine]; // инверсия признака состояния
     _buttonCount[_scanVertLine][_scanHorizLine]= 0;  // сброс счетчика подтверждений

      if ( flagPress[_scanVertLine][_scanHorizLine] == true )
        flagClick[_scanVertLine][_scanHorizLine]= true; // признак клика кнопки            
     }      
  }
  _scanHorizLine++; }
 
  }

  // установка следующей вертикальной линии 
    digitalWrite(_verticalPins[_scanVertLine], LOW);
    _scanVertLine++; if (_scanVertLine >3) _scanVertLine= 0;
    digitalWrite(_verticalPins[_scanVertLine], HIGH);        
}

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

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

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

Объект типа MatrixKeys при создании имеет параметры:

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

Пример создания объекта:

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

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

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

 

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

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

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

Аргументы:

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

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

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

 

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

Я оформил класс MatrixKeys библиотекой. Загрузить ее можно по этой ссылке MatrixKeys.h. Как установить библиотеку написано в уроке 9.

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

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

Напишем простую программу для проверки и демонстрации библиотеки  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(); // сканирование матрицы
}

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

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

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

 

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

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

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

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

    • Наверное, ошибка. Спасибо. В принципе, они обнуляются при создании переменных.

      • Зачем тогда лишний код?
        И _scanHorizLine= 0; в конструкторе, если scanState() начинается с этого?

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

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

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

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

            Прежде всего хочу поблагодарить Вас за замечательный сайт. К сожалению, я нарвался на него только сейчас. Уже 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ов

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

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

            ичь

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

            на один порт

            например

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

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

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

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

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

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

  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
    Ошибка компиляции.

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

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

    • Здравствуйте!
      Посмотрите в интернете, что пишут об этой ошибке.
      Пишут, что она бывает с 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 из старой версии программы. В моём случае это решило проблему, и на данный момент всё у меня компилируется без проблем.

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

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

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

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

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

      // возвращает код первой нажатой кнопки
      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); } }

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

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