Button Keypad 4x4 module Assembled_RU - dimaatmelodromru/techdoc GitHub Wiki

Button Keypad 4x4 module (Assembled)

Клавиатура Button Keypad 4x4 module (Assembled) очень похожа на очень распространенную клавиатуру Matrix Membrane Keypad 16 Key (4x4), но на самом деле работает совсем иначе. На клавиатуре Matrix Membrane Keypad 16 Key (4x4) кнопки образуют матрицу 4x4 и чтобы подключить данную клавиатуру к микроконтроллеру необходимо использовать 8 контактов, что для некоторых проектов очень расточительно. Клавиатура Button Keypad 4x4 module (Assembled) имеет всего 3 контакта (VCC, GND, Out) и для подключения к микроконтроллеру (например, Arduino) достаточно одного аналогового входа.

img

Как же такое возможно? Для этого посмотрим на электрическую схему данной клавиатуры.

Схема электрическая

Схема электрическая клавиатуры Button Keypad 4x4 module (Assembled):

img

Напряжение подается на контакты 3 (VCC) и 2 (GND). Нажатие одной из кнопок SW1-SW16 образует на выходе 1 (Out) делитель напряжения, причем для каждой кнопки получается свой уникальный делитель напряжения. Например для кнопки SW2 – 1/10, для кнопки SW10 – 11/10. Подключив данный контакт к аналоговому входу микроконтроллера при нажатии кнопок будем получать разные значения, по которым сможем идентифицировать нажатую кнопку.

Подключение к плате Arduino

Подключим клавиатуру Button Keypad 4x4 module (Assembled) к плате Arduino и напишем скетч определения нажатой клавиши.

Будем использовать следующие компоненты:

  • Плата Arduino UNO – 1;

  • Клавиатура Button Keypad 4x4 module (Assembled) – 1;

  • Провода FM – 3.

Схема подключения:

img

На обратной стороне клавиатуры приведены примерные аналоговые значения при нажатии кнопок клавиатуры.

img

Проверим на практике. Подключаем плату Arduino к компьютеру. В Arduino IDE создаем новый скетч и заносим в него следующий код:

void setup() {
  // запуск последовательного порта
  Serial.begin(9600);
}

void loop() {
 // получение данных на аналоговом входе A1
 int valueA1=analogRead(A1);
 // вывод данных в последовательный порт
 Serial.println(valueA1);
 // пауза
 delay(500);
}

Загружаем скетч на плату Arduino, открываем монитор последовательного порта и смотрим значения на аналоговом входе при нажатии клавиш клавиатуры:

img

Схема в сборе:

img

Результаты измерений (сравнение ожидаемых и реальных значений на аналоговом входе при нажатии клавиш) представлены в таблице:

Кнопка Ожидаемое значение Среднее реальное Кнопка Ожидаемое значение Среднее реальное
SW1 1023 1023 SW9 512 517
SW2 930 934 SW10 487 492
SW3 850 859 SW11 465 470
SW4 790 796 SW12 445 450
SW5 680 686 SW13 410 412
SW6 640 645 SW14 330 333
SW7 600 607 SW15 277 278
SW8 570 574 SW16 238 240

Необходимо знать, что значение на аналоговом входе принимает значение 0-1023 относительно опорного напряжения. По умолчанию – это напряжение питания микроконтроллера. Опорное напряжение играет главную роль в измерении аналогового сигнала, потому что именно от него зависит максимальное измеряемое напряжение и вообще возможность и точность перевода полученного значения 0-1023 в Вольты. Изучим следующую функцию – analogReference(mode), где mode:

  • DEFAULT: опорное напряжение равно напряжению питания МК. Активно по умолчанию;

  • INTERNAL: встроенный источник опорного на 1.1V для ATmega168 или ATmega328P и 2.56V на ATmega8;

  • INTERNAL1V1: встроенный источник опорного на 1.1V (только для Arduino Mega);

  • INTERNAL2V56: встроенный источник опорного на 2.56V (только для Arduino Mega);

  • EXTERNAL: опорным будет считаться напряжение, поданное на пин AREF.

Значение 1023 функции analogRead() будет соответствовать выбранному опорному напряжению или напряжению выше его, но не выше 5.5V, что спалит плату. То есть при режиме DEFAULT мы можем оцифровать напряжение от 0 до напряжения питания. Если напряжение питания 4.5 Вольта, и мы подаём 4.5 В – получим оцифрованное значение 1023. Если подаём 5 Вольт – опять же получим 1023, т.к. выше опорного. Это правило работает и дальше, главное не превышать 5.5 Вольт.

Что касается точности: при питании от 5V и режиме DEFAULT мы получим точность измерения напряжения (5 / 1023 ~ 8 мВ) – 8 милливольт. Поставив INTERNAL мы можем измерять напряжение от 0V до 1.1V с точностью (1.1 / 1023 ~ 1.2 мВ) – 1.2 милливольта. Весьма неплохо, особенно если баловаться с делителем напряжения.

Что касается внешнего источника опорного напряжения. Нельзя использовать напряжение меньше 0 В или выше 5.5 В в качестве внешнего опорного в пин AREF. Также при использовании режима EXTERNAL нужно вызвать analogReference(EXTERNAL) до вызова функции analogRead(), иначе можно повредить микроконтроллер.

Написание кода для определения нажатой клавиши

Теперь зная реальные значения на аналоговом входе, напишем скетч, определяющий нажатую клавишу. Содержимое скетча :

void setup() {
 // запуск последовательного порта
 Serial.begin(9600);
}

void loop() {
 // нажата ли кнопка?
 int valueA1=get_button();
 if(valueA1>0) { // если нажатие
   Serial.print("Click button ");
   Serial.println(valueA1);
   delay(500);
 } 
}

// функция определения нажатия кнопки
int get_button() {
 // получение данных на аналоговом воде A1
 int val=analogRead(A1);
 if(val>1000)
   return 1;
 else if(val>900)
   return 2;
 else if(val>820)
   return 3;
 else if(val>750)
   return 4;
 else if(val>660)
   return 5;
 else if(val>620)
   return 6;
 else if(val>585)
   return 7;
 else if(val>540)
   return 8;
 else if(val>500)
   return 9;
 else if(val>475)
   return 10;
 else if(val>455)
   return 11;
 else if(val>425)
   return 12;
 else if(val>370)
   return 13;
 else if(val>300)
   return 14;
 else if(val>260)
   return 15;
 else if(val>200)
   return 16;
 else
   return 0; 
}

Загружаем скетч на плату Arduino, открываем монитор последовательного порта и смотрим значения на аналоговом входе при нажатии клавиш клавиатуры:

img

Заметим, что продолжительное нажатие на клавишу (>500 мсек) приводит к автоповтору.

Пример создания микро-калькулятора

В качестве примера использования клавиатуры, создадим проект мини-калькулятора для арифметических действий (сложение, вычитание, умножение, деление) с двумя числами на плате Arduino и дисплее WH1602 на контроллере HD77480.

Необходимые компоненты

Будем использовать следующие компоненты:

  • Плата Arduino UNO – 1;

  • Клавиатура Button Keypad 4x4 module (Assembled) – 1;

  • Дисплей WH1602 (в нашем случае LCD Keypad shield) – 1;

  • Провода MM – 3.

Схема подключения

Схема соединений для мини-калькулятора на Arduino UNO, клавиатуре Button Keypad 4x4 module (Assembled) и LCD keypad shield:

img

Назначение клавиш клавиатуры в проекте согласно рисунку:

img

Написание скетча

Приступим к написанию скетча.

Все нажатия цифр 0-9 и действий (+,-,/,*) заносим в буфер и выводим на дисплей. При этом вводим ограничения:

  • начинаем ввод с цифры;

  • после ввода арифметического действия ввод другого действия блокирован;

  • кнопку "=" (итого) можно ввести после цифры;

  • клавиша "забой" удаляет предыдущий символ.

Содержимое скетча:

// подключение библиотеки для дисплея
\#include <LiquidCrystal.h>
// создание экземпляра объекта
const int rs = 8, en = 9, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// переменные
int pos=0;   // количество введенных символов
int buf[32];  // массив для введенных данных
int endkey=0; // 1 - цифра, 2 - действие 3 - результат

// массив преобразований клавиш
// 1,2,3,+
// 4,5,6,-
// 7,8,9,/
// зб,0,=,*
int trans[]={0,
​       1,2,3,10,
​       4,5,6,11,
​       7,8,9,12,
​       14,0,15,13,
​      };
// массив перевода клавиши в символ
char sw[]={'0','1','2','3','4','5','6','7','8','9','+','-','/','*',' ','='};      

void setup() {
 // запуск дисплея
 lcd.begin(16,2);
 lcd.clear();
 // вывод заголовка
 lcd.setCursor(3,0);
 lcd.print("Calculator");
 lcd.setCursor(2,1);
 lcd.print("Robotdyn.com");
 delay(3000);
 // очистить дисплей
 lcd.clear();
 // показывать курсор
 lcd.cursor();
}

void loop() {
 // нажата ли кнопка?
 int valueA1=get_button();
 if(valueA1>0) { // если нажатие
   // обработка нажатой клавиши
   add_key(trans[valueA1]);
   delay(500);
 } 
} 

// функция определения нажатия кнопки
int get_button() {
 // получение данных на аналоговом воде A1
 int val=analogRead(A1);
 if(val>1000)
   return 1;
 else if(val>900)
   return 2;
 else if(val>820)
   return 3;
 else if(val>750)
   return 4;
 else if(val>660)
   return 5;
 else if(val>620)
   return 6;
 else if(val>585)
   return 7;
 else if(val>540)
   return 8;
 else if(val>500)
   return 9;
 else if(val>475)
   return 10;
 else if(val>455)
   return 11;
 else if(val>425)
   return 12;
 else if(val>370)
   return 13;
 else if(val>300)
   return 14;
 else if(val>260)
   return 15;
 else if(val>200)
   return 16;
 else
   return 0;  
}

// добавление новой кнопки в массив buf[]
void add_key(int key) {
  // 0-9
  if(key<10) {
   if(endkey==3) { // после вывода суммы// очищение и начало// новых действийstartover();pos=0;
   }
   buf[pos]=key;tolcd(key);endkey=1;
  }
  // + - / *
  else if(key<14) {
​    if(endkey==1) {
​     buf[pos]=key;tolcd(key);endkey=2;
   }
  }
  // забой
  else if(key==14) {
   pos=max(0,pos-1);tolcd(key);
   pos=pos-1;lcd.setCursor(pos%15,pos/15);
   if(pos==0)
​     endkey=0;
   else if(buf[pos-1]>=0 && buf[pos-1]<=9)
​     endkey=1;
   else
​     endkey=2; 
  }
  // = (итог)
  else {
   if(endkey==1) { 
​    buf[pos]=key;tolcd(key);
​    itogo();
​    endkey=3;   
   } 
  }
}

// вывод на дисплей
void tolcd(int s) {
  // позиция курсора
  lcd.setCursor(pos%15,pos/15);
  lcd.print(sw[s]);
  pos=pos+1;
  }

// получить и вывести результат
void itogo() {
  String number1="";
  String number2="";
  char d;
  int i;
  int summa;

  // получить первое число
  for(i=0;i<pos;i++) {
   if(buf[i]>=0 && buf[i]<=9)
​    number1+=sw[buf[i]];
   elsebreak; 
  }
  // действие
  d=buf[i];
  // получить второе число
  for(i=i+1;i<pos;i++) {
   if(buf[i]>=0 && buf[i]<=9)
​     number2+=sw[buf[i]];
   elsebreak; 
  }
  switch(d) {
   // +
   case 10: summa=number1.toInt()+number2.toInt();
​     break;
   // -
   case 11: summa=number1.toInt()-number2.toInt();
​     break;
   // /
   case 12: summa=number1.toInt()/number2.toInt();
​     break;
   // *
   case 13: summa=number1.toInt()*number2.toInt();
​     break;
   default:
​     break;   
   }
  // вывести результат на экран
  lcd.setCursor(pos%15,pos/15);
  lcd.print(summa);
}

// очистка при начале нового набора
void startover() {
  for(int i=0;i<=pos;i++) {
   buf[i]=0;
  }
  lcd.clear();
}

Загружаем скетч на плату Arduino, и начинаем пользоваться мини-калькулятором.

img

img

⚠️ **GitHub.com Fallback** ⚠️