• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Нужна помощь Запуск функции при долгом зажатии кнопки на ESP8266

Otto17

New member
Такая проблема, вроде и не сложная, но не могу понять как решить. Переделал функцию button1() на кнопке №1, что бы при обычных (коротких) нажатиях переключался regim1 на значения 0 или 1, а при удержании этой кнопки 2 или более секунд включался режим auto с функции pir() (датчика движения). Так вот, кнопка отлично переключается во всех трёх режимах, но почему то при выборе auto режима функция pir() не срабатывает. Возможно где то перепутал с условиями проверок в функции button1()....
Код:
***
boolean Status1 = true;                // объявляем Status1 реле в 0, инверсия...
boolean btnPress1 = false;             // объявляем что кнопка №1 не нажата "0"
boolean lastbtnStat1 = false;          // временная переменная для хранения статуса1

int regim1 = 0;               // Режимы по умолчанию при включении

bool button_long_state = false;   // Булево значение для выбора режима button1()
uint32_t ms_button = 0;           // Беззнаковый тип конкретного размера для выбора режима button1()

***

void button1() {                     // Функция для кнопки №1
  btnPress1 = digitalRead(BUTTON_1);    // Считываем значение кнопки в btnPress1
  Status1 = digitalRead(RELAY_1);       // Считываем значение реле в Status1
  if (btnPress1 && !lastbtnStat1) {     // Если btnPress1 нажата и lastbtnStat1 ИСТИНА...
    delay(30); // защита от дребезга
    btnPress1 = digitalRead(BUTTON_1);  // ... записываем результат в btnPress1
  }

  uint32_t ms = millis();   //Задаём переменную для хранения времени
  // Фиксируем нажатие кнопки (более 10 мкр./сек.)
  if (btnPress1 == false && !lastbtnStat1 && (ms - ms_button) > 10) {
    lastbtnStat1 = true;
    button_long_state = false;
    ms_button = ms;
  }
  // Фиксируем длинное нажатие кнопки (больше или равно 2-м секундам)
  if (btnPress1 == false && !button_long_state && ( ms - ms_button ) >= 2000 ) {
    button_long_state = true;
    regim1 = 2;
    pir();
  }

  // Фиксируем отпускание кнопки (более 10 мкр./сек.)
  if (btnPress1 == true && !lastbtnStat1 && ( ms - ms_button ) > 10) {
    lastbtnStat1 = false;
    ms_button = ms;
    // Цикл проверки/переключения 0 и 1 режима
    if (btnPress1) {                 // Если кнопка нажата, то...
      regim1++;                      // переключаем на слежующий режим
      if (regim1 > 1) {              // если действующий режим > второго, то...
        regim1 = 0;                  // возвращаемся на нулевой режим
      }
    }
    if (regim1 == 0) {                  // Если режим 1=0, то...
      Status1 = true;                   // Status1 ИСТИНА (инверсия для Реле)
      digitalWrite(RELAY_1, Status1);   // Выключаем Реле №1
    }
    if (regim1 == 1) {                  // Если режим 1=1, то...
      Status1 = false;                  // Status1 ЛОЖЬ (инверсия для Реле)
      digitalWrite(RELAY_1, Status1);   // Включаем реле №1
    }
  }

  lastbtnStat1 = btnPress1;     // Копируем значение из кнопки в lastbtnStat1
}
На всякий случай прикладываю код программы, для понимания в архиве...
 

Вложения

CodeNameHawk

Moderator
Команда форума
Вы точно знаете приоритеты в строке
Код:
if (btnPress1 == false && !button_long_state && ( ms - ms_button ) >= 2000 )
я бы записал так
Код:
if ( (btnPress1 == false) && (!button_long_state) && (( ms - ms_button ) >= 2000) )
 

Otto17

New member
Вы точно знаете приоритеты в строке
Код:
if (btnPress1 == false && !button_long_state && ( ms - ms_button ) >= 2000 )
я бы записал так
Код:
if ( (btnPress1 == false) && (!button_long_state) && (( ms - ms_button ) >= 2000) )
Попробовал, никак не повлияло на правильную корректность работы. И кстати, что это даёт ?
 

nikolz

Well-known member
1.это не код С, а код ардулино.
чтобы было более похоже на код C, вместо boolean запишите bool
------------------------------
2. можно немного упростить код для наглядности:
в условных выражениях:
1) вместо btnPress1 == false записать !btnPress1
2) вместо btnPress1 == true записать btnPress1
---------------------------------
3) вместо
if (btnPress1) { // Если кнопка нажата, то...
regim1++; // переключаем на слежующий режим
if (regim1 > 1) { // если действующий режим > второго, то...
regim1 = 0; // возвращаемся на нулевой режим
}
}
записать
if (btnPress1) {
regim1++; regim1&=1;
}
==============================
еще замечу следующее.
не правильно решена защита от дребезга.
От дребезга надо защищаться не задержкой, а повторным считыванием состояния кнопки до тех пор, пока состояние не станет стабильным.
---------------------------------------
кроме того, если это колбек и прерывания не запрещены, то задержка вообще не имеет смысл, так как дребезг будет вызывать многократные вызовы колбека.
---------------
 

sega6549

New member
1.это не код С, а код ардулино.
чтобы было более похоже на код C, вместо boolean запишите bool
------------------------------
2. можно немного упростить код для наглядности:
в условных выражениях:
1) вместо btnPress1 == false записать !btnPress1
2) вместо btnPress1 == true записать btnPress1
---------------------------------
3) вместо
if (btnPress1) { // Если кнопка нажата, то...
regim1++; // переключаем на слежующий режим
if (regim1 > 1) { // если действующий режим > второго, то...
regim1 = 0; // возвращаемся на нулевой режим
}
}
записать
if (btnPress1) {
regim1++; regim1&=1;
}
==============================
еще замечу следующее.
не правильно решена защита от дребезга.
От дребезга надо защищаться не задержкой, а повторным считыванием состояния кнопки до тех пор, пока состояние не станет стабильным.
---------------------------------------
кроме того, если это колбек и прерывания не запрещены, то задержка вообще не имеет смысл, так как дребезг будет вызывать многократные вызовы колбека.
---------------
а можете привести правильный вариант защиты от дребезга с повторным считыванием кнопки?
 

>hbq

New member
а можете привести правильный вариант защиты от дребезга с повторным считыванием кнопки?
Не знаю насколько правильно, но я делал так
Код:
int buttonPin = 4;
bool lastButton = LOW;
bool lastButton_auto = LOW;
uint32_t ms_button = 0;
uint32_t ms_up = 0;
unsigned long ms;

void setup()
{
  pinMode(buttonPin, INPUT);
  //все вводы и выводы (пины)
}

void loop()
{
  ms = millis();
  bool statePin = digitalRead(buttonPin);
  //Фиксируем нажатие кнопки
  if( statePin == HIGH && !lastButton && ( ms - ms_button) > 10 )
  {
    lastButton = HIGH;
    lastButton_auto = LOW;
    ms_button = ms;
    //функция по любому нажатию     
  }
 
  // продолжительное нажатие и удержание
  if( statePin == HIGH && (ms - ms_button ) > 300 && (ms - ms_up ) > 10 )
  {
   
    lastButton_auto = HIGH;
    ms_up = ms;
    //функция по удержанию
  }
 
  //Фиксируем отпускание кнопки
  if( statePin == LOW && lastButton && ( ms - ms_button) >50 )
  {
    lastButton = LOW;
    ms_button = ms;
    //функция по любому отпусканию
    if( lastButton_auto == HIGH)
    {
      //функция по отпусканию после удержания кнопки
    }
    if( !lastButton_auto)
    {
     //функция по отпусканию без удержания
    }
   
  }
}
 

nikolz

Well-known member
а можете привести правильный вариант защиты от дребезга с повторным считыванием кнопки?
Пример писать не буду, так как мне это не надо а его отладка требует времени.
Могу написать следующий алгоритм:
-----------------------
Обработку нажатия делаем в колбеке по фронту ( т е переход из 0 в 1 или из 1 в ноль) и колбеке аппаратного таймера
Нажатие - это 1->0, а отпускание это 1->0.
В колбеке GPIO соответственно условие на обработку этих ситуаций.
Когда приходит сигнал нажатия мы включаем таймер на величину интервала - длительное нажатие.
Если приходит сброс нажатия, то таймер сбрасываем.
Если дребезги закончились, то по завершению времени длительного нажатия произойдет колбек таймера .
В этом алгоритме нет никаких задержек и процессор не тормозится в ожидании завершения дребезгов либо опознания длительного нажатия.
-----------------------
Примерно так.
 
Сверху Снизу