• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе 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 соответственно условие на обработку этих ситуаций.
Когда приходит сигнал нажатия мы включаем таймер на величину интервала - длительное нажатие.
Если приходит сброс нажатия, то таймер сбрасываем.
Если дребезги закончились, то по завершению времени длительного нажатия произойдет колбек таймера .
В этом алгоритме нет никаких задержек и процессор не тормозится в ожидании завершения дребезгов либо опознания длительного нажатия.
-----------------------
Примерно так.
 
Сверху Снизу