Делаем автоматический счетчик отжиманий на ардуино
Содержание:
- Исходный код программы
- Скетч тахометра на arduino
- Работа схемы
- Основы цветовой маркировки резисторов
- Особенности измерения скорости движения и скорости вращения.
- Step 15: Индикация / Data View
- Обратите внимание
- Дребезг кнопки ардуино
- Что такое таймеры
- Редактирование файла boards.txt
- Принципиальные схемы
- Исходный код программы
- Переключение режимов с помощью кнопки
- Подключение кнопки в режиме INPUT_PULLUP
Исходный код программы
Плата Arduino Uno имеет специальную функцию pulseIn, которая позволяет определить длительность положительной или отрицательной части прямоугольной волны:
В представленном примере функция pulseIn измеряет время (в микросекундах), в течение которого на контакте PIN8 присутствует напряжение высокого (Htime) или низкого (Ltime) уровня. Когда мы сложим Htime и Ltime мы получим длительность цикла (периода), инвертировав которую мы получим значение частоты. А зная значение частоты, мы можем определить значение емкости по вышеприведенной формуле.
То есть, в результате, мы будем подсоединять неизвестную емкость к схеме таймера 555, который будет генерировать прямоугольную волну, частота которой будет напрямую зависеть от подсоединенной емкости. Этот сигнал будет подаваться на плату Arduino Uno через триггер Шмидта. Плата Arduino Uno будет измерять частоту этой прямоугольной волны. А определив значение частоты, мы по вышеприведенной формуле рассчитываем значение емкости.
На следующем рисунке показаны результаты измерения емкости. Когда к нашему устройству мы подсоединили электролитический конденсатор емкостью 1 мкФ, результат составил 1091.84 нФ ~ 1 мкФ. А с полиэстеровым конденсатором 0,1 мкФ результат составил 107.70 nF ~ 0.1uF.
Затем мы подсоединили к устройству керамический конденсатор 0,1 мКФ и результат измерения емкости составил 100.25 nF ~ 0.1uF. При подсоединении электролитического конденсатора 4,7 мкФ результат составил 4842.83 nF ~ 4.8uF.
Далее приведен полный текст программы.
Arduino
#include <LiquidCrystal.h> //подключение библиотеки ЖК дисплея
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
int32_t Htime;
int32_t Ltime;
float Ttime;
float frequency;
float capacitance;
void setup()
{
pinMode(8,INPUT); //pin 8 – на ввод данных
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.print(«capacitance =»);
}
void loop()
{
for (int i=0;i<5;i++) // измеряем длительность 5 раз
{
Ltime=(pulseIn(8,HIGH)+Ltime)/2; //вычисляем среднее значение в каждом цикле
Htime=(pulseIn(8,LOW)+Htime)/2;
}
Ttime = Htime+Ltime;
frequency=1000000/Ttime;
capacitance = (1.44*1000000000)/(20800*frequency); // вычисляем емкость в нанофарадах
lcd.setCursor(0,1);
lcd.print(capacitance);
lcd.print(» nF «);
delay(500);
}
1 |
#include <LiquidCrystal.h> //подключение библиотеки ЖК дисплея LiquidCrystallcd(2,3,4,5,6,7); int32_tHtime; int32_tLtime; floatTtime; floatfrequency; floatcapacitance; voidsetup() { pinMode(8,INPUT);//pin 8 – на ввод данных lcd.begin(16,2); lcd.setCursor(,); lcd.print(«capacitance =»); } voidloop() { for(inti=;i<5;i++)// измеряем длительность 5 раз { Ltime=(pulseIn(8,HIGH)+Ltime)2;//вычисляем среднее значение в каждом цикле Htime=(pulseIn(8,LOW)+Htime)2; } Ttime=Htime+Ltime; frequency=1000000Ttime; capacitance=(1.44*1000000000)(20800*frequency);// вычисляем емкость в нанофарадах lcd.setCursor(,1); lcd.print(capacitance); lcd.print(» nF «); delay(500); } |
Скетч тахометра на arduino
Ниже приведен скетч с подробными комментариями, а также его можно скачать себе на компьютер: скачать.
// библиотеки для работы с LCD дисплеем по I2C #include <Wire.h> #include <LiquidCrystal_I2C.h> // инициализация дисплея. // GND - земля // VVC - 5+ вольт // SDA - пин A4 // SCL - пин A5 // 16 столбцов и 2 строки LiquidCrystal_I2C lcd(0x27,16,2); const int pinPhoto = A0; // порт для считывания данных с фоторизистора int light = 0; // переменная для хранения данных с фоторизистора int numTurn = 0; // номер итерации проверки оборотов int valArray; // массив для хранения данных с фоторезистора, нужные для начальной настройки int maxLight = 1024; // порог, при котором будем считать, что светодиод закрыт int sum = -1; // сумма количеств оборотов int count_zamer = 20; // количество итераций, после которых будет высчитано среднее значение скорости unsigned long lastMillis = 0; // переменная для хранения времени предыдущего перекрытия светодиода bool work = true; // флаг, который поднимается после открытия светодиода void setup() { Serial.begin(9600); pinMode( pinPhoto, INPUT ); // ждем пока светодиод прогреется delay(1000); // каждые 10 милисек считаем значение с фоторезистора, 100 раз for(int i = 0; i< 100; i++){ valArray = analogRead( pinPhoto ); delay(10); } // выбераем минимальное значение с фоторезистора for(int i = 0; i< 100; i++){ if(maxLight > valArray) maxLight = valArray; } // немного снизим порог maxLight -= 10; Serial.println( maxLight ); delay(500); Serial.println( "START!" ); lastMillis = millis(); // запускаем дисплей lcd.init(); // включаем подсветку lcd.backlight(); // стираем все лишнее lcd.clear(); // выводим текст lcd.setCursor(0, 0); lcd.print("S"); lcd.setCursor(1, 0); lcd.print("T"); lcd.setCursor(2, 0); lcd.print("A"); lcd.setCursor(3, 0); lcd.print("R"); lcd.setCursor(4, 0); lcd.print("T"); lcd.setCursor(5, 0); lcd.print("!"); } void loop() { // считаем показания с фоторезистора light = analogRead( pinPhoto ); // если значение ниже порога, значит светодиод загорожен if(light < maxLight && work){ // опускаем флаг, чтобы не считать, пока светодиод перекрыт work = false; // если первая итерация, то не считаем ее, чтобы начать отсчет времени if(sum == -1){ // записываем время старта lastMillis = millis(); sum = 0; }else{ unsigned long currentMillis = millis(); // записываем в sum количество миллисекунд между оборотами sum += (currentMillis - lastMillis); numTurn++; // считаем 20 раз, для большей точности if(numTurn == count_zamer){ float sredSpeed = 0; numTurn = 0; // берем среднее и высчитываем количество оборотов для минуты sredSpeed = 60000 / ((float)sum / (float)count_zamer); // оборотов в минуту Serial.print("speed: "); Serial.println(sredSpeed); sum = -1; // вывод данных на LCD дисплей lcd.clear(); lcd.setCursor(0, 0); lcd.print("S"); lcd.setCursor(1, 0); lcd.print("P"); lcd.setCursor(2, 0); lcd.print("E"); lcd.setCursor(3, 0); lcd.print("E"); lcd.setCursor(4, 0); lcd.print("D"); lcd.setCursor(5, 0); lcd.print(":"); // преобразовываем числовое значение в строку // и по одному символу выводим не дисплей char string_turn[] = ""; sprintf(string_turn,"%d", (int)sredSpeed); char *current = string_turn; int count_numbers = 0; while ( *current != '\0' ) { lcd.setCursor(6+count_numbers, 0); lcd.print(*current); count_numbers++; current++; } lcd.setCursor(count_numbers+7, 0); lcd.print("r"); lcd.setCursor(count_numbers+8, 0); lcd.print("/"); lcd.setCursor(count_numbers+9, 0); lcd.print("m"); lcd.setCursor(count_numbers+10, 0); lcd.print("i"); lcd.setCursor(count_numbers+11, 0); lcd.print("n"); } lastMillis = currentMillis; } } // если светодиод не загорожен if(light >= maxLight){ work = true; } }
Работа схемы
Структурно рассматриваемое нами устройство состоит из 4-х модулей: модуль датчиков, модуль управления, модуль отображения и модуль реле.
В модуле датчиков, схема которого представлена на рисунке ниже, мы имеем два инфракрасных датчика с инфракрасными диодами, потенциометр, компаратор (на операционном усилителе) и светодиоды. Потенциометр предназначен для установки опорного напряжения компаратора (для регулировки чувствительности устройства). Инфракрасные датчики обнаруживают отсутствие или присутствие объекта (человека) в поле своего действия и выдают соответствующие сигналы на компаратор. Компаратор сравнивает два напряжения и обеспечивает соответствующий цифровой сигнал на своем выходе. В представленном устройстве мы использовали два компаратора (поскольку у нас два модуля инфракрасных датчиков), реализованных на микросхеме LM358.
Модуль управления построен на основе платы Arduino UNO, которая используется для управления всем устройством. Выходы компараторов подсоединены к цифровым контактам 14 и 19 Arduino. Плата Arduino считывает сигналы с этих цифровых контактов и на их основе выдает соответствующие управляющие сигналы на реле, которое управляет включением и выключением цепи электрической лампочки (bulb).
Модуль отображения состоит из ЖК дисплея 16×2, на котором будет отображаться число людей, находящихся в комнате и статус света (включен/выключен) когда никого нет в комнате.
Модуль реле состоит из транзистора BC547 и реле на 5 В, управляющим включением/выключением электрической лампочки. Транзистор необходим для управления реле поскольку плата Arduino не обеспечивает необходимые значения токов и напряжений для этого. Плата Arduino будет подавать управляющие команды на транзистор, а он с помощью реле будет включать и выключать электрическую лампочку.
Полная схема устройства представлена на следующем рисунке.
Выходы инфракрасных датчиков непосредственно подключены к цифровым контактам Arduino 14(A0) и 19(A5). База транзистора через резистор подключена к контакту 2 Arduino. ЖК дисплей подсоединен к Arduino в 4-битном режиме. Контакты RS и EN ЖК дисплея подключены к контактам 13 и 12 Arduino. Контакты данных ЖК дисплея D4-D7 подключены к контактам 11-8 Arduino.
Основы цветовой маркировки резисторов
Для определения сопротивления резисторов используется следующая формула:
R= { (AB*10c)Ω ± T% }
где
A – значение цвета в первой полоске,
B – значение цвета во второй полоске,
C – значение цвета в третьей полоске,
T – значение цвета в четвертой полоске.
В следующей таблице представлены цветовые коды резисторов.
Цвет | Числовое значение цвета | Множитель (10c) | Допуск |
черный | 10 | — | |
коричневый | 1 | 101 | ± 1% |
красный | 2 | 102 | ± 2% |
оранжевый | 3 | 103 | — |
желтый | 4 | 104 | — |
зеленый | 5 | 105 | — |
синий | 6 | 106 | — |
фиолетовый | 7 | 107 | — |
серый | 8 | 108 | — |
белый | 9 | 109 | — |
золотой | — | 10-1 | ± 5% |
серебряный | — | 10-2 | ± 10% |
нет полоски | — | — | ± 20% |
К примеру, если цветовые коды на резисторе Brown – Green – Red – Silver (коричневый – зеленый – красный – серебро), сопротивление резистора рассчитывается следующим образом:
Исходя из приведенной формулы для расчета сопротивления резистора R = AB*10c получаем:
Четвертая полоска показывает допуск резистора, в нашем случае это ± 10%.
То есть актуальное сопротивление данного резистора будет лежать в диапазоне от 1350 до 1650 Ом.
Также в сети интернет можно найти достаточно много калькуляторов, которые исходя из цветового кода резистора рассчитают вам его сопротивление. Например, вот этот калькулятор, в котором нужно просто ввести цвета колец на резисторе и он вам выдаст сопротивление резистора.
Особенности измерения скорости движения и скорости вращения.
При измерении скорости вращения бензинового двигателя надо обязательно учесть величину К, которая совсем не очевидна. Например, вы намотали провод на кабель свечи и ожидаете, что там будет одна искра на один оборот. Это совсем не так. Во-первых, у 4-тактного двигателя вспышка происходит один раз на два оборота, у 2-тактного один раз на оборот коленвала. Во-вторых, для упрощения системы зажигания коммутатор подаёт искру на неработающие в данный момент цилиндры, типа на выпуске. Для получения правильного К надо почитать документацию на двигатель или подсмотреть показания эталонного тахометра.
При измерении скорости движения частота обновления дисплея не имеет большого значения, особенно, если вы рисуете цифры, а не двигаете стрелку. Даже обновление информации раз в секунду не вызовет отторжения. С оборотами двигателя всё наоборот, индикатор должен откликаться гораздо быстрее на изменение оборотов.
Вывод информации
Типичная обида начинающего разработчика автомобильной и мотоциклетной электроники «стрелки дёргаются, цифры нечитабельны» лечится простым способом — надо обманывать клиента. Вы что думаете, автомобильный тахометр всегда показывает вам правду? Конечно же нет! Хотя вам этот обман нравится и вы хотите, чтобы ваш прибор дурил голову так же.
Стрелки
Если включить зажигание на новом модном автомобиле или мотоцикле, стрелки приборов сделают красивый вжух до максимума и медленнее опадут до нуля. Вот! Вот это нам и надо сделать. Надо, чтобы при показе максимальной величины стрелка не метнулась к ней мгновенно и не упала как акции лохотрона в ноль.
Итак, нам надо учитывать максимальную скорость стрелки на увеличение и максимальную на уменьшение показаний. Совсем хорошо сделать эти скорости нелинейными, чтобы стрелка сначала двигалась быстрее, а потом чуть помедленнее приближалась к заданному значению.
Вот пример с нелинейным выводом показаний:
Цифры
С цифрами всё намного сложнее. Быстрые изменения показаний приводят к тому, что несколько порядков сливаются в мутное пятно. Для скорости, как и писал выше, можно задать интервал раз в секунду и глаз успеет прочитать три цифры.
В мототехнике не зря делают аналоговые индикаторы оборотов, точные цифры не нужны, важна относительная близость к оборотам максимального крутящего момента, к максимальным вообще и холостые.
Я предлагаю менять частоту вывода информации на дисплей в зависимости от степени изменения величины. Если обороты меняются, скажем, на 5% от последнего подсчёта, а не показа — можно затупить и показывать раз в 300-500мс. Если на 20%, то показывать раз в 100мс.
Можно огрубить шкалу и показывать только две значащие цифры
С учётом мототематики, можно довольно точно показывать обороты холостого хода как описано чуть выше и огрублять вывод на оборотах от двух холостых. На высоких оборотах для гонщиков важнее делать блинкеры типа «передачу вниз», «передачу вверх» и «ты спалишь движок». То есть держать двигатель около максимального крутящего момента и не дать ему крутиться выше максимальных разрешённых оборотов. Блинкеры замечательно делаются с помощью SmartDelay когда можно унаследовать от этого класса свой с заданной ногой контроллера и частотой мигания, там есть методы для переопределения и они вызываются раз в заданное время.
Step 15: Индикация / Data View
Со светодиодом всё предельно просто: он загорается при переходе вверх и гаснет при переходе вниз, тем самым дублируя прикрытый сенсором светодиод на счётчике. Буззер привязан таким же образом, лишь с тем отличием, что включается он лишь при превышении порогового значения нагрузки.
А цифровой дисплей на 20×2 символов я захотел использовать по-полной. 🙂 Во время загрузки при сборе статистики в одну строку дисплея я вывожу 3 значения: низ окна, значение сенсора и верх окна. Эту же информацию отображаю во второй строке на шкале шириной в окно.
В рабочем цикле я в одну строку вывожу ток (wattage/220), мощность (wattage) и ширину шкалы, а в другую строку — саму шкалу, масштаб которой изменяется в зависимости от того, не превышен ли порог. Так при пороге в 1000 W и шкала 0-1000 в нормальном режиме и 1000-2000 в режиме превышения.
Обратите внимание
- В этом эксперименте мы впервые используем микросхему, в данном случае — выходной сдвиговый регистр 74HC595. Микросхемы полезны тем, что позволяют решать определенную задачу, не собирая каждый раз стандартную схему.
- Выходной сдвиговый регистр дает нам возможность «сэкономить» цифровые выходы, использовав всего 3 вместо 8. Каскад регистров позволил бы давать 16 и т.д. сигналов через те же три пина.
- На принципиальной схеме нашего эксперимента ножки расположены в другом порядке, чтобы не вышло путаницы в соединениях. Назначения выводов согласно datasheet’у подписаны внутри изображения микросхемы, номера ножек — снаружи.
- Напомним, что на изображении семисегментного индикатора подписаны номера его ножек и их соответствие сегментам.
Дребезг кнопки ардуино
В процессе работы с кнопками мы можем столкнуться с очень неприятным явлением, называемым дребезгом кнопки. Как следует из самого названия, явление это обуславливается дребезгом контактов внутри кнопочного переключателя. Металлические пластины соприкасаются друг с другом не мгновенно (хоть и очень быстро для наших глаз), поэтому на короткое время в зоне контакта возникают скачки и провалы напряжения. Если мы не предусмотрим появление таких “мусорных” сигналов, то будем реагировать на них каждый раз и можем привести наш проект к хаусу.
Для устранения дребезга используют программные и аппаратные решения. В двух словах лишь упомянем основные методы подавления дребезга:
- Добавляем в скетче паузу 10-50 миллисекунд между полкучением значений с пина ардуино.
- Если мы используем прерывания, то программный метд использоваться не может и мы формируем аппаратную защиту. Простейшая из них – RC фильтр с конденсатором и сопротивлением.
- Для более точного подавления дребезга используется аппаратный фильтр с использованием триггера шмидта. Этот вариант позволит получить на входе в ардуино сигнал практически идеальной формы.
Более подробную информацию о способах борьбы с дребезгом вы можете найти в этой статье об устранении дребезга кнопок.
Что такое таймеры
Что же представляют собой таймеры в современной электронике? Фактически это определенный вид прерываний. Это простые часы, которые могут измерять длительность какого-нибудь события. Каждый микроконтроллер имеет встроенные часы (осциллятор), в плате Arduino Uno этот осциллятор работает на частоте 16 МГц. Частота влияет на скорость обработки. Чем выше частота, тем выше скорость обработки. Таймер использует счетчик, который считает с определенной скоростью, зависящей от частоты осциллятора. В плате Arduino Uno состояние счетчика увеличивается на 1 каждые 62 нано секунды (1/16000000 секунды). Фактически, это время за которое плата Arduino Uno переходит от одной инструкции к другой.
Редактирование файла boards.txt
Arduino_dir\hardware\arduino\avr\d:\Arduino\arduino-1.6.12\hardware\arduino\avr\.menu.clock=Тактирование
- скорость загрузки — uno.upload.speed;
- значения фьюзов — uno.bootloader.low_fuses, .high_fuses, .extended_fuses;
- имя файла загрузчика — uno.bootloader.file;
- частоту микроконтроллера — uno.build.f_cpu.
uno.menu.clock.external16=Внешний резонатор 16МГцuno.menu.clock.external16.upload.speed=115200uno.menu.clock.external16.bootloader.low_fuses=0xFFuno.menu.clock.external16.bootloader.high_fuses=0xDEuno.menu.clock.external16.bootloader.extended_fuses=0xFFuno.menu.clock.external16.bootloader.file=optiboot/optiboot_atmega328.hexuno.menu.clock.external16.build.f_cpu=16000000Luno.menu.clock.internal8=Внутренний RC-генератор 8МГцuno.menu.clock.internal8.upload.speed=57600uno.menu.clock.internal8.bootloader.low_fuses=0xE2uno.menu.clock.internal8.bootloader.high_fuses=0xDEuno.menu.clock.internal8.bootloader.extended_fuses=0xFFuno.menu.clock.internal8.bootloader.file=optiboot/optiboot_atmega328_8.hexuno.menu.clock.internal8.build.f_cpu=8000000Luno.menu.clock.internal1=Внутренний RC-генератор 1МГцuno.menu.clock.internal1.upload.speed=4800uno.menu.clock.internal1.bootloader.low_fuses=0x62uno.menu.clock.internal1.bootloader.high_fuses=0xDEuno.menu.clock.internal1.bootloader.extended_fuses=0xFFuno.menu.clock.internal1.bootloader.file=optiboot/optiboot_atmega328_1.hexuno.menu.clock.internal1.build.f_cpu=1000000L
онлайн калькулятораИнструменты->ТактированиеВнутренний RC-генератор 8МГцотсюдаArduino_dir\hardware\arduino\avr\bootloaders\optiboot\
Принципиальные схемы
Передатчик
Передающая часть беспроводного термометра на ATMega328p
(для увеличения масштаба можно кликнуть по картинке правой кнопкой мыши и выбрать «Открыть ссылку/изображение в новой вкладке/новом окне»)
В данном примере я не буду выводить неиспользуемые выводы микроконтроллера на внешние контакты термометра, после чего их можно было бы использовать для дальнейшего усовершенствования устройства. Здесь мы рассматриваем лишь идею для устройства и соберем его только на макетной плате.
Приемник
Приемная часть беспроводного термометра на Arduino Mega
(для увеличения масштаба можно кликнуть по картинке правой кнопкой мыши и выбрать «Открыть ссылку/изображение в новой вкладке/новом окне»)
Пожалуйста, обратите внимание, что приемник построен на базе платы Arduino Mega, которая не изображена на схеме. Для подключения платы Arduino Mega соедините с ней радиочастотный модуль и LCD дисплей согласно метка на схеме
Исходный код программы
В коде программы первым делом необходимо подключить библиотеку для работы с ЖК дисплеем и инициализировать необходимые контакты для работы.
Затем необходимо указать направление работы для инициализированных контактов (на ввод или на вывод) и инициализировать ЖК дисплей для работы.
Далее в цикле программы мы считываем выходы датчиков и инкрементируем и декрементируем значение счетчика посетителей. Также мы проверяем на равенство нулю значение этого счетчика. Если он равен нулю, то это значит что в комнате никого нет – в этом случае мы выключаем свет в комнате (выключаем электрическую лампочку при помощи транзистора и реле).
Если же счетчик посетителей не равен нулю, то включаем свет. Также определим две функции: на вход и на выход посетителя.
Далее представлен полный текст программы.
Arduino
#include<LiquidCrystal.h>
LiquidCrystal lcd(13,12,11,10,9,8);
#define in 14
#define out 19
#define relay 2
int count=0;
void IN()
{
count++;
lcd.clear();
lcd.print(«Person In Room:»);
lcd.setCursor(0,1);
lcd.print(count);
delay(1000);
}
void OUT()
{
count—;
lcd.clear();
lcd.print(«Person In Room:»);
lcd.setCursor(0,1);
lcd.print(count);
delay(1000);
}
void setup()
{
lcd.begin(16,2);
lcd.print(«Visitor Counter»);
delay(2000);
pinMode(in, INPUT);
pinMode(out, INPUT);
pinMode(relay, OUTPUT);
lcd.clear();
lcd.print(«Person In Room:»);
lcd.setCursor(0,1);
lcd.print(count);
}
void loop()
{
if(digitalRead(in))
IN();
if(digitalRead(out))
OUT();
if(count<=0)
{
lcd.clear();
digitalWrite(relay, LOW);
lcd.clear();
lcd.print(«Nobody In Room»);
lcd.setCursor(0,1);
lcd.print(«Light Is Off»);
delay(200);
}
else
digitalWrite(relay, HIGH);
}
1 |
#include<LiquidCrystal.h> LiquidCrystallcd(13,12,11,10,9,8); #define in 14 intcount=; voidIN() { count++; lcd.clear(); lcd.print(«Person In Room:»); lcd.setCursor(,1); lcd.print(count); delay(1000); } voidOUT() { count—; lcd.clear(); lcd.print(«Person In Room:»); lcd.setCursor(,1); lcd.print(count); delay(1000); } voidsetup() { lcd.begin(16,2); lcd.print(«Visitor Counter»); delay(2000); pinMode(in,INPUT); pinMode(out,INPUT); pinMode(relay,OUTPUT); lcd.clear(); lcd.print(«Person In Room:»); lcd.setCursor(,1); lcd.print(count); } voidloop() { if(digitalRead(in)) IN(); if(digitalRead(out)) OUT(); if(count<=) { lcd.clear(); digitalWrite(relay,LOW); lcd.clear(); lcd.print(«Nobody In Room»); lcd.setCursor(,1); lcd.print(«Light Is Off»); delay(200); } else digitalWrite(relay,HIGH); } |
Переключение режимов с помощью кнопки
Для того, чтобы определить, была ли нажата кнопка, надо просто зафиксировать факт ее нажатия и сохранить признак в специальной переменной.
Факт нажатия мы определяем с помощью функции digitalRead(). В результате мы получим HIGH (1, TRUE) или LOW(0, FALSE), в зависимости от того, как подключили кнопку. Если мы подключаем кнопку с помощью внутреннего подтягивающего резистора, то нажатие кнопки приведет к появлению на входе уровня 0 (FALSE).
Для хранения информации о нажатии на кнопку можно использовать переменную типа boolean:
boolean keyPressed = digitalRead(PIN_BUTTON)==LOW;
Почему мы используем такую конструкцию, а не сделали так:
boolean keyPressed = digitalRead(PIN_BUTTON);
Все дело в том, что digitalRead() может вернуть HIGH, но оно не будет означать нажатие кнопки. В случае использования схемы с подтягивающим резистором HIGH будет означать, что кнопка, наоборот, не нажата. В первом варианте (digitalRead(PIN_BUTTON)==LOW ) мы сразу сравнили вход с нужным нам значением и определили, что кнопка нажата, хотя и на входе сейчас низкий уровень сигнала. И сохранили в переменную статус кнопки. Старайтесь явно указывать все выполняемые вами логические операции, чтобы делать свой код более прозрачным и избежать лишних глупых ошибок.
Как переключать режимы работы после нажатия кнопки?
Часто возникает ситуация, когда мы с помощью кнопок должны учитывать факт не только нажатия, но и отпускания кнопки. Например, нажав и отпустив кнопку, мы можем включить свет или переключить режим работы схемы. Другими словами, нам нужно как-то зафиксировать в коде факт нажатия на кнопку и использовать информацию в дальнейшем, даже если кнопка уже не нажата. Давайте посмотрим, как это можно сделать.
Логика работы программы очень проста:
- Запоминаем факт нажатия в служебной переменной.
- Ожидаем, пока не пройдут явления, связанные с дребезгом.
- Ожидаем факта отпускания кнопки.
- Запоминаем факт отпускания и устанавливаем в отдельной переменной признак того, что кнопка была полноценно нажата.
- Очищаем служебную переменную.
Как определить нажатие нескольких кнопок?
Нужно просто запомнить состояние каждой из кнопок в соответствующей переменной или в массиве ардуино. Здесь главное понимать, что каждая новая кнопка – это занятый пин. Поэтому если количество кнопок у вас будет большим, то возможно возникновение дефицита свободных контактов. Альтернативным вариантом является использование подключения кнопок на один аналоговый пин по схеме с резистивным делителем. Об этом мы поговорим в следующих статьях.
Подключение кнопки в режиме INPUT_PULLUP
В указанной выше схеме мы использовали резистор, называемый подтягивающим, для формирования определенного уровня сигнала на цифровом порту. Но есть другой способ подключить кнопку без резистора, используя внутренне сопротивление платы ардуино. В блоке setup мы должны всего лишь определить тип пина, к которому подключим кнопку, как INPUT_PULLUP.
pinMode(PIN_BUTTON, INPUT_PULLUP);
Альтернативным вариантом будет выбрать режим пина как OUTPUT и установить на данный порт высокий уровень сигнала. Встроенный подтягивающий резистор подключиться автоматически.
pinMode(PIN_BUTTON, INPUT_PULLUP); digitalWrite(PIN_BUTTON, HIGH);
И все. Можно собрать вот такую сложную схему и работать с кнопкой в скетче.