Последующий вопрос о кнопке и переключателе

ПОСТАНОВКА ПРОБЛЕМЫ:

  1. Контур измеряет различные параметры (температуру, влажность, д.) через постоянно подключенные к нему датчики.
  2. Когда кнопка нажимается и удерживается в течение 2 секунд между ними, Arduino должна войти в режим настройки. (Я использовал петлю IF и для этого используется функция millis() )
  3. В режиме настройки есть 6 экранов, которые появляются один за другим.
  4. После того, как Arduino войдет в режим настройки, должен появиться случай переключения 0 (экран 1) (для этого я использовал последовательный монитор).
  5. Теперь, если я нажму ту же кнопку и отпущу через мгновение, должен появиться следующий вариант Switch 1 (экран 2).
  6. Шаг 5 будет повторяться до случая переключения 5 (экран 6).
  7. После варианта Switch 5 цикл переходит к варианту Switch 0 (SCREEN1), затем к варианту Switch 1, варианту Switch 2 и т. д.
  8. Если в промежутке между вышеуказанным циклом Switch Case нажать кнопку и удерживать ее в течение 2 секунд, цикл Switch case должен завершиться, и Arduino должен вернуться к MAIN LOOP(), где он измеряет параметр датчика.
  9. Опять же, если кнопка нажата и удерживается в течение 2 секунд между процессом измерения, Arduino должен войти в режим настройки.

Соображения:

  1. Кнопка подключена к контакту 2 Arduino (АКТИВНЫЙ НИЗКИЙ)
  2. Вход на выводе 2 рассматривается как прерывание, поэтому Arduino предоставляет услуги в любой момент времени.
  3. Последовательный монитор Arduino используется для демонстрации выходных данных Screen1-Screen6.
  4. Конденсатор 0,1 мкФ используется на кнопке для устранения дребезга . И резистор 10K, 0,25 Вт подключен от VCC к Pin №2
  5. Код для определения параметров (температуры, влажности и т. д.) еще предстоит написать.

ДОСТИЖЕНИЕ: До пункта № 7 ПОСТАНОВЛЕНИЯ ПРОБЛЕМЫ код работает нормально.

ОШИБКА: Если я нажимаю кнопку в течение 2 секунд в цикле SWITCH CASE, Arduino выходит из SWITCH CASE и переходит в MAIN LOOP(), но снова возвращается в цикл SWITCH CASE(). Он должен снова попросить нажать кнопку в течение 2 секунд, чтобы войти в режим настройки.

const int btn = 2;     
const int ledPin =  13;     
int selector = 0;
boolean  volatile wait = false; 
const unsigned long event=2000;
unsigned long previous1=0;
unsigned long current1=0;
unsigned long sum1=0;
unsigned long previous2=0;
unsigned long current2=0;
unsigned long sum2=0;
bool buttonPress = false;
void setup() 
{
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
pinMode(btn, INPUT);
attachInterrupt(digitalPinToInterrupt(btn),decoder,CHANGE);
}

void loop() 
{
  if (digitalRead(btn) ==LOW && !buttonPress) 
  {
    previous1 = millis();
    buttonPress = true;
  }
  else if (digitalRead(btn) == HIGH && buttonPress) 
  {
    current1 = millis();
    sum1=current1-previous1;
    Serial.println(sum1);
    Serial.println("SUM1");  
    if (sum1>=event)

       {  BREAK1:
          doSwitchCase();
          selector++;
          goto BREAK1; 
          if (selector >6) 
              {
                  selector = 0;
                  delay(500);
              }
        }
        buttonPress = false;
  }
  wait = true;
  interrupts();

}

void decoder() 
{
 noInterrupts();
 wait = false;
}


void doSwitchCase() 
{
  switch(selector) 
  {
  case 0:
    Serial.println("SCREEN1");
    while (digitalRead(btn)!=LOW) ;
    previous2 =millis();
    while (digitalRead(btn)!=HIGH) ;
    current2=millis();
    sum2=current2-previous2;
        if(sum2>=event)
        {
         Serial.println(sum2);
         loop();
        }
    break;

  case 1:
    Serial.println("SCREEN2");
    while (digitalRead(btn)!=LOW) ;
    previous2 =millis();
    while (digitalRead(btn)!=HIGH) ;
    current2=millis();
    sum2=current2-previous2;
        if(sum2>=event)
        {
         Serial.println(sum2);
         loop();
        }
    break;

  case 2:
   Serial.println("SCREEN3");
    while (digitalRead(btn)!=LOW) ;
    previous2 =millis();
    while (digitalRead(btn)!=HIGH) ;
    current2=millis();
    sum2=current2-previous2;
        if(sum2>=event)
        {
         Serial.println(sum2);
         loop();
        }
   break;

  case 3:
   Serial.println("SCREEN4");
    while (digitalRead(btn)!=LOW) ;
    previous2 =millis();
    while (digitalRead(btn)!=HIGH) ;
    current2=millis();
    sum2=current2-previous2;
        if(sum2>=event)
        {
         Serial.println(sum2);
         loop();
        }
   break;

  case 4:
   Serial.println("SCREEN5");
    while (digitalRead(btn)!=LOW) ;
    previous2 =millis();
    while (digitalRead(btn)!=HIGH) ;
    current2=millis();
    sum2=current2-previous2;
        if(sum2>=event)
        {
         Serial.println(sum2);
         loop();
        }   
   break;

  case 5:
  Serial.println("SCREEN6");
    while (digitalRead(btn)!=LOW) ;
    previous2 =millis();
    while (digitalRead(btn)!=HIGH) ;
    current2=millis();
    sum2=current2-previous2;
        if(sum2>=event)
        {
         Serial.println(sum2);
         loop();
        }
  break;  
  }
}

, 👍0


1 ответ


1

Одно примечание перед тем, как НИКОГДА не использовать goto в C++, это плохой стиль и делает в объектно-ориентированном языке на 99,9% бессмысленным. Чтобы войти в регистр переключателя после двухсекундного нажатия, вам нужно всего лишь ввести одно утверждение в соответствии с исходным предложением. Я не читал ваш код, так как он становится нечитаемым, чем больше функций вы хотите добавить. Подумайте о его рефакторинге, иначе вам не повезет с помощью (поскольку никто не мучает себя каотичным чужим кодом:

const int btn = 2;
const int ledPin =  13;
int selector = 0;
const unsigned long buttonPressLong = 2000;  // 2 секунды
const unsigned long buttonPressShort = 250;  // 0,25 секунды выполнимо
const unsigned long buttonPressDebounce = 50;  // устранение дребезга при слишком коротком нажатии. Спасибо, Эдгар Боне.
unsigned long buttonPressStart = 0;

bool buttonPress = false;
bool inMenu = false;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(btn, INPUT);
  }

void loop() {
  if (digitalRead(btn) == LOW && !buttonPress ) {
    buttonPressStart = millis();
    buttonPress = true;
  }
  // Подпрограмма запускается только в том случае, если имело место предыдущее нажатие, в противном случае она игнорируется
  else if (digitalRead(btn) == HIGH && buttonPress) {
    if (millis() - buttonPressStart > buttonPressLong && millis() - buttonPressStart > buttonPressDebounce && inMenu) {
      Serial.print("Long press: ");
      Serial.println(millis() - buttonPressStart);
      buttonPress = false;
      inMenu = false;
    }
    if (millis() - buttonPressStart < buttonPressLong && millis() - buttonPressStart > buttonPressDebounce && !inMenu) {    // ЭТО ИЗМЕНЕНИЕ
      Serial.print("First long press ");    // ВОТ ИЗМЕНЕНИЕ
      inMenu = true;
    }
    if (millis() - buttonPressStart < buttonPressShort && millis() - buttonPressStart > buttonPressDebounce && inMenu) {
      Serial.print("Short press: ");
      Serial.println(millis() - buttonPressStart);
      doSwitchStatement();
      selector++;
      if (selector > 6) {
        selector = 0;
        delay(500);
      }
      buttonPress = false;
    }
  }
  // Здесь вы можете делать другие вещи, так как это не блокирует
}
doSwitchStatement(){...}// Остается таким же, как у вас

Я только что изменил 1 оператор (и 1 отладочное сообщение), чтобы получить то, что вы хотите увидеть // ВОТ ИЗМЕНЕНИЕ

,