В прошлом примере #1, на предыдущей странице, предложил совместить в скетче два варианта управления светодиодом. Получается, что добавив внешнюю кнопку, по её нажатию, мы будем управлять кодом скетча (программы). Ниже рассмотрим этот пример.
Начнём с того, что добавим в схему ещё кнопку SB2, сигнал с который мы будем подавать на pin4. Для этой кнопки так же добавим стягивающий резистор R3 на 10...18 кОм. Схема представлена на рисунке ниже.
Как и в предыдущем уроке #1 воспользуемся инверсной логикой управления и под неё изменим схему. Как видим ниже, схема упростилась на два резистора: R1, R3.
Реализуем схему 1. Кнопка SB2 одним контактом подключена к +5V, а второй контакт к стягивающему резистору R3. От их соединения идёт подключение к контакту pin4. Второй свободный вывод резистора R3 подключен к контакту GND. Светодиод VD1(HL1) подключаем через ограничивающий резистор 330...1000 Ом.
Всё, подключения сделаны, переходим к программе.
Добавим в скетч переменную switchPin, которая будет определять pin для управления режимами работы светодиода.
Добавим переменные currentSwitch и lastSwitch для хранения состояния этой переключающей кнопки. Добавим переменную flag, через неё мы будем переключать код программы.
В настроечную функцию setup() добавим инициализацию новой кнопки, определив её как вход (INPUT). В рабочей функции loop() мы совместим коды разных режимов работы светодиода.
В начале работы функции loop() мы опрашиваем кнопку выбора режима, и если она была нажата, то выбираем тот код программы, который будет задавать определённый режим работы кнопки SB1, управляющей работой светодиода.
Так как у нас всего два режима работы светодиода, то достаточно использовать конструкцию if-else.
Вот полный скетч, его можно скопировать и вставить в свой Arduino IDE:
/************************************************************* * 2018-03-11 Mr.ALB Тренировка в программировании Ардуино *************************************************************/ // Переменные с пинами подключенных устройств int buttonPin = 2;// Подключаем кнопку SB1 на 2-й pin int switchPin = 4;// Подключаем кнопку SB2 на 4-й pin // Подключаем светодиод на 5-й pin, можно на любой с PWM int ledPin = 5; // Переменные для хранения состояния кнопки и светодиода boolean lastButton = LOW; boolean currentButton = LOW; boolean lastSwitch = false; boolean currentSwitch = false; boolean flag = false;// Изначально установлен 1-й режим int ledLevel = 0; // Настройка изменения яркости int deltaLevel = 10; // Шаг изменения яркости int sign = 1; // Знак шага int step_delay = 120;// Здержка в шаге изменения яркости светодиода // Настройка сигнализатора окончания изменения яркости // Число морганий светодиода на pin13 (LED_BUILTIN) int max_blink = 3; // Задержка состояния светодиода, немного уменьшил int blink_delay = 250; /************************************************************* * Настроечная функция, выполняется один раз вначале *************************************************************/ void setup() { pinMode(buttonPin, INPUT); pinMode(switchPin, INPUT);// Pin устанавливаем как вход pinMode(ledPin, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); // Потушим светодиод на pin13 (LED_BUILTIN) digitalWrite(LED_BUILTIN, LOW); } /************************************************************* * При нажатии на кнопку SB1: * Режим 1: Светодиод медленно увеличивает яркость * При повторном нажатии на кнопку, * светодиод медленно гаснет. * Режим 2: Светодиод медленно увеличивает яркость до максимума, * а затем уменьшает яркость до полного потухания. * При нажатии на кнопку SB2 * происходит смена режимов действия кнопки SB1 * *************************************************************/ void loop() { // Опрос кнопки SB2 currentSwitch = fn_debounce(lastSwitch,switchPin); // Переключаем режимы работы программы if(lastSwitch == LOW && currentSwitch == HIGH) { if(flag == false) flag = true; else flag = false; // Сигнализируем о смене режима программы fn_blink(1, blink_delay); } // Опрос кнопки SB1 currentButton = fn_debounce(lastButton,buttonPin); // Управляем работой светодиода по указанному режиму if(lastButton == LOW && currentButton == HIGH) { if(flag) { if(ledLevel == 0) sign = 1; if(ledLevel == 255) sign = -1; // Изменяем яркость светодиода fn_stepBrightness(step_delay,deltaLevel,sign); } else { fn_stepBrightness(step_delay,deltaLevel,1);// Зажигается fn_stepBrightness(step_delay,deltaLevel,-1);// Тухнет } // Сигнализируем об окончании изменения fn_blink(max_blink, blink_delay); } lastButton = currentButton;// Переписываем состояние кнопки SB1 lastSwitch = currentSwitch;// Переписываем состояние кнопки SB2 } /************************************************************* * Функция для подавления дребезга * Модифицирована, добавлен опрос конкретного pin-а *************************************************************/ boolean fn_debounce(boolean last,int btnPin) { // Читаем состояние кнопки boolean current = digitalRead(btnPin); if(last != current) { delay(5); current = digitalRead(btnPin); } return current; } /************************************************************* * Функция сигнализации окончания цикла * изменения яркости светодиода *************************************************************/ void fn_blink(int blink_max, int blink_delay) { for(int i = 0; i < blink_max; i++) { digitalWrite(LED_BUILTIN, HIGH); delay(blink_delay); digitalWrite(LED_BUILTIN, LOW); delay(blink_delay); } } /************************************************************* * Функция изменения яркости светодиода *************************************************************/ void fn_stepBrightness(int step_delay, int deltaLevel, int sign) { for(int i = 0; i < (int(256 / deltaLevel) + 1); i++) { ledLevel = ledLevel + deltaLevel * sign; // Ограничиваем диапазон значений ledLevel = constrain(ledLevel, 0, 255); delay(blink_delay); analogWrite(ledPin, ledLevel); delay(step_delay); } }
Как вы видели, в скетче немного модифицировал функцию устранения дребезга debounse в fn_debounce, добавил ещё один аргумент для указания какой pin опрашивать, так как у нас уже две кнопки, а в дальнейшем их может быть много.
Можно представленный скетч модернизировать: режимы работы кнопки выделить в отдельные функции, или в одну функцию с аргументом выбора режима. Тогда вызывая её в loop(), и определяя номер режима, можно создать очень много режимов работы светодиода или какого другого исполнительного механизма. Конечно, в таком случае портебуется использовать не конструкцию if-else, а, к примеру, switch, и тип переменной flag определить как int.
В этом скетче мы переделываем управление кнопками на инверсную логику в соответствии со схемой 2. Уровень LOW будет указывать на нажатие кнопки. Так же в этом скетче оптимизируем типы переменных, чтобы код занимал как можно меньше байт.
/********************************************************************** 2018-03-11 Mr.ALB Тренировка в программировании Ардуино Скетч 2.1 2022-05-17 Mr.ALB Использование инверсной логики Скетч 2.2 ПОДКЛЮЧЕНИЕ: R2 - pin5 HL1 A - R2 HL1 k - GND SB1 - pin2 и GND SB1 - pin4 и GND Архив: https://disk.yandex.ru/d/Hs0uEvqfGNxcwQ 2022-05-17 Скетч использует 1886 байт **********************************************************************/ #define BT1_PIN 2 // Подключаем кнопку SB1 на 2-й pin #define BT2_PIN 4 // Подключаем кнопку SB2 на 4-й pin #define LED_PIN 5 // Подключаем светодиод на 11-й pin, ; // можно на любой с PWM #define MAX_BLINK 3 // Число морганий светодиода LED_BUILTIN // Переменные для хранения состояния кнопки и светодиода // Не активное состояние = HIGH // Активное состояние = LOW bool lastButton = HIGH; bool currentButton = HIGH; bool lastSwitch = HIGH; bool currentSwitch = HIGH; byte mode = 1; // Изначально установлен 1-й режим int ledLevel = 0; // Настройка изменения яркости byte deltaLevel = 10; // Шаг изменения яркости bool sign = true; // Знак шага // Здержка в шаге изменения яркости светодиода unsigned int step_delay = 120; // Настройка сигнализатора окончания изменения яркости // Задержка состояния светодиода на pin13 unsigned int blink_delay = 250; /********************************************************************** Настроечная функция, выполняется один раз вначале **********************************************************************/ void setup() { pinMode(BT1_PIN, INPUT_PULLUP); // Pin устанавливаем как вход_ pinMode(BT2_PIN, INPUT_PULLUP); // с подтяжкой к +5V pinMode(LED_PIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); // Потушим светодиод на pin13 (LED_BUILTIN) digitalWrite(LED_BUILTIN, LOW); } /********************************************************************** При нажатии на кнопку SB1: Режим 1: Светодиод медленно увеличивает яркость При повторном нажатии на кнопку, светодиод медленно гаснет. Режим 2: Светодиод медленно увеличивает яркость до максимума, а затем уменьшает яркость до полного потухания. При нажатии на кнопку SB2 происходит смена режимов действия кнопки SB1 **********************************************************************/ void loop() { // Опрос кнопки SB2 currentSwitch = fnDebounce(lastSwitch, BT2_PIN); // Переключаем режимы работы программы if (lastSwitch == HIGH && currentSwitch == LOW) { if (mode == 1) mode = 2; else mode = 1; fnBlink(1, blink_delay);// Сигнализируем о смене режима программы } // Опрос кнопки SB1 currentButton = fnDebounce(lastButton, BT1_PIN); // Управляем работой светодиода по указанному режиму if (lastButton == HIGH && currentButton == LOW) { fnBlink(1, blink_delay); // Сигнал нажатия кнопки if (mode == 1) { if (ledLevel == 0) sign = true; if (ledLevel == 255) sign = false; // Изменяем яркость светодиода fnStepBrightness(step_delay, deltaLevel, sign); } else { fnStepBrightness(step_delay, deltaLevel, true); // Зажигается fnStepBrightness(step_delay, deltaLevel, false); // Тухнет } // Сигнализируем об окончании изменения fnBlink(MAX_BLINK, blink_delay); } lastButton = currentButton;// Переписываем состояние кнопки SB1 lastSwitch = currentSwitch;// Переписываем состояние кнопки SB2 } /********************************************************************** Функция для подавления дребезга Модифицирована, добавлен опрос конкретного pin-а **********************************************************************/ boolean fnDebounce(boolean last, byte btnPin) { boolean current = digitalRead(btnPin); // Читаем состояние кнопки if (last != current) { delay(10); current = digitalRead(btnPin); } return current; } /********************************************************************** Функция сигнализации окончания цикла изменения яркости светодиода blink_max - сколько мигнуть blink_delay - задержка в мс **********************************************************************/ void fnBlink(int blink_max, int blink_delay) { for (byte i = 0; i < blink_max; i++) { digitalWrite(LED_BUILTIN, HIGH); delay(blink_delay); digitalWrite(LED_BUILTIN, LOW); delay(blink_delay); } } /*********************************************************** Функция изменения яркости светодиода step_delay - Задержка в мс на шаг deltaLevel - На сколько изменить за шаг sign - Знак уменьшение/увеличение: если = true умножаем на 1 если = false умножаем на -1 ***********************************************************/ void fnStepBrightness ( unsigned int step_delay, byte deltaLevel, bool sign ) { for (byte i = 0; i < (byte(256 / deltaLevel) + 1); i++) { ledLevel = ledLevel + deltaLevel * ((sign == true) ? 1 : -1); // Ограничиваем диапазон значений ledLevel = constrain(ledLevel, 0, 255); analogWrite(LED_PIN, ledLevel); delay(step_delay); } }
Для уменьшения кода и более изящной конструкции в скетче применяем функцию ограничения диапазона для переменной ledLevel.
// Ограничиваем диапазон значений ledLevel = constrain(ledLevel, 0, 255);
На первых двух страницах раздела показываю как можно использовать кнопки и объясняю два типа логики: 1 - Прямая, где управляющий сигнал высокого уровня (HIGH) и 2 - Инверсная, где управляющий сигнал низкого уровня (LOW). Какой логикой пользоваться ваш выбор, замечу, что промышленные контроллеры чаще всего используют инверсную логику. Сам я использую разную, но инверсная, как мы видели, требует меньше ресурсов (в нашем случае меньше резисторов).
Программы для повторения: