#include <Arduino.h>
#include <iostream>
// Константы для конфигурации
#define LED_PIN 39 // Пин к которому присоединён светодиод
const int BUTTON_PUSH_NUMBER = 3; // Количество нажатий для включения светодиода
const unsigned int LIGHT_ON_MILLIS = 1000; // Длительность свечения 1000 миллисекунд (1 секунда)
const unsigned long MAX_MILLIS = ~0ul; // После этого значения millis() начинает с 0
// Переменные для сохранения состояний и передачи значений между функциями
bool light_on; // Состояние светодиода на текущем вызове loop()
bool prev_light_on; // Состояние светодиода на предыдущем вызове loop()
uint8_t gpio_num_18_state; // Состояние порта кнопки на текущем вызове loop()
uint8_t prev_gpio_num_18_state; // Состояние порта кнопки на предыдущем вызове loop()
int num_pressed; // Подсчёт нажатий кнопки
void dump_state(void)
{
std::cout << "Функция: " << __func__ << std::endl
<< " light_on : " << light_on << std::endl
<< " prev_light_on : " << prev_light_on << std::endl
<< " gpio_num_18_state : " << ( gpio_num_18_state == HIGH ? "HIGH" : "LOW") << std::endl
<< " prev_gpio_num_18_state : " << (prev_gpio_num_18_state == HIGH ? "HIGH" : "LOW") << std::endl
<< " num_pressed : " << num_pressed << std::endl;
}
void setup() {
pinMode(LED_PIN, OUTPUT);
// Установка начального состояния
light_on = false; // Светодиод не светит
prev_light_on = false; // Светодиод не светил
gpio_num_18_state = LOW; // Кнопка не нажата
prev_gpio_num_18_state = LOW; // Кнопка не была нажата
num_pressed = 0; // При включении ещё не было нажатий
// dump_state(); // Отладочная печать состояний
}
void loop() {
static unsigned int time_light_on = 0; // Переменная для хранения времени, когда включили светодиод
// dump_state(); // Отладочная печать состояний
// Считываем состояние порта кнопки
gpio_num_18_state = digitalRead(GPIO_NUM_18);
// Блок подсчёта нажатий кнопки. Считаем нажатия только при выключенном светодиоде
if( ! light_on && gpio_num_18_state == HIGH && prev_gpio_num_18_state == LOW)
{
++num_pressed;
}
// Блок установки флага включения светодиода
if ( num_pressed >= BUTTON_PUSH_NUMBER ) // Нажали заданное количество раз
{
light_on = true; // устанавливаем флаг включения светодиода
num_pressed = 0; // Сбросили счётчик количества нажатий
time_light_on = millis(); // Сохранили время когда включили светодиод
}
// Блок сброса флага включения светодиода через заданное время
if ( light_on == true )
{
unsigned long current_time = millis();
unsigned long time_on = (current_time < time_light_on) // Вычисляем сколько уже светится диод, учитывая переполнение
? (MAX_MILLIS - time_light_on) + current_time
: current_time - time_light_on;
if ( time_on > LIGHT_ON_MILLIS )
{
light_on = false;
}
}
// Блок смены состояния светодиода. Пишем в порт только если нужно сменить состояние
if ( light_on != prev_light_on )
{
digitalWrite(LED_PIN, light_on ? HIGH : LOW);
}
prev_gpio_num_18_state = gpio_num_18_state; // Сохранили состояние кнопки для следующего вызова loop()
prev_light_on = light_on; // Сохранили состояние светодиода для следующего вызов loop()
delay(1); // А вот это загадка. Как будто не успевают записаться переменные prev_* между вызовами loop().
}