Почему моя программа на Ардуино не работает?

Всем привет! Я недавно начал изучать Arduino и решил написать код для работы светофора. Основная задача заключается в том, чтобы моргать светодиодами, а по нажатию кнопки отключать все огни. Изначально я использовал функцию delay() для задержек, но из-за этого кнопка не работала, что логично. Я переписал код, используя millis(), и кнопка заработала, но теперь все светодиоды одновременно гаснут и включаются. Подскажите, в чем может быть проблема? Вот мой код: 
<br/> 
<pre><code>//зададим исходные данные для счета millis()
uint32_t tmr1, tmr2, tmr3, tmr4;

uint32_t per1 = 3000;
uint32_t per2 = 500;
uint32_t per3 = 1500;

// инициализируем пины светодиода
const int RLED = 11;
const int YLED = 10;
const int GLED = 9;
// пин кнопки
const int BUT = 2;

boolean lastBUT = LOW; //переменная хранит предыдущее состояние кнопки
boolean currentBUT = LOW; //переменная хранит текущее состояние кнопки

int ledin = 0; //состояние светодиода (вкл, выкл)

//задаем флажки
boolean GLEDflag = false;

void setup() 
{
  pinMode(BUT, INPUT);
  pinMode(RLED, OUTPUT);
  pinMode(YLED, OUTPUT);
  pinMode(GLED, OUTPUT);
}
/*
* Функция сглаживания дребезга
* принимает в качестве аргумента предыдущее состояние конпки
* и выдает фактическое
*/

boolean debounce(boolean last) //задаем функцию, которая принимает только логическую переменную boolean last (последнее состояние кнопки)
{
  boolean current = digitalRead(BUT); //читаем конпку
  if (last != current) //сравниваем состояние, если отличаются, то...
  {
    delay(10); //ждем 10 мс
    current = digitalRead(BUT); //читаем кнопку еще раз
    return current; //возвращаем состояние кнопки
  }
}

void trLight(int mode)
{
  if (mode == 1)
  {
    digitalWrite(GLED, HIGH);
    if (millis() - tmr1 &gt;= per1)
    {
  • 26 октября 2024 г. 5:32
Ответы на вопрос 2
Прежде всего, давайте внимательно посмотрим на ваш код. Похоже, что проблема кроется в логике управления светодиодами. Также следует обратить внимание на использование функции `debounce()` и на то, как вы отслеживаете состояния светодиодов.

Вот несколько рекомендаций по исправлению вашей программы:

1. **Использование `millis()` для работы со светодиодами**: Убедитесь, что вы отслеживаете время для каждого светодиода отдельно, а не выполняете их включение по очереди в одном блоке. Необходимо добавлять логику, которая будет управлять состояниями светодиодов в зависимости от прошедшего времени.

2. **Обработка состояния кнопки**: В вашем коде нет логики, которая бы использовала значения, возвращаемые из `debounce()`. Также нет обработки состояния, при котором программа должна прекращать включать светодиоды при нажатии кнопки.

3. **Исправление функции `debounce()`**: Функция должна быть скорректирована так, чтобы возвращать текущее состояние кнопки, и её следует применять в основном цикле вашего кода.

Вот переписанный пример, который исправляет эти проблемы:

```cpp
// Зададим исходные данные для счета millis()
uint32_t tmr1, tmr2, tmr3;
const uint32_t per1 = 3000;
const uint32_t per2 = 500;
const uint32_t per3 = 1500;

// Инициализируем пины светодиода
const int RLED = 11;
const int YLED = 10;
const int GLED = 9;
// Пин кнопки
const int BUT = 2;

boolean lastBUT = LOW; // Переменная хранит предыдущее состояние кнопки
boolean currentBUT;
bool lightsOn = true; // Переменная для управления состоянием света

void setup() 
{
  pinMode(BUT, INPUT);
  pinMode(RLED, OUTPUT);
  pinMode(YLED, OUTPUT);
  pinMode(GLED, OUTPUT);
}

boolean debounce() // Функция для обработки дребезга кнопки
{
  boolean current = digitalRead(BUT); // Читаем кнопку
  if (lastBUT != current) // Если состояние отличается
  {
    delay(10); // Ждем 10 мс
    current = digitalRead(BUT); // Читаем кнопку еще раз
  }
  lastBUT = current; // Обновляем предыдущее состояние
  return current; // Возвращаем актуальное состояние кнопки
}

void loop() 
{
  currentBUT = debounce();
  
  if (currentBUT == HIGH) // Если кнопка нажата
  {
    lightsOn = !lightsOn; // Переключаем состояние света
    if (!lightsOn) // Если свет выключен, все светодиоды выключаем
    {
      digitalWrite(RLED, LOW);
      digitalWrite(YLED, LOW);
      digitalWrite(GLED, LOW);
      return; // Завершаем выполнение loop
    }
  }

  if (lightsOn) {
    uint32_t currentMillis = millis();
    
    if (currentMillis - tmr1 >= per1) // Таймер для зеленого
    {
      digitalWrite(GLED, HIGH);
      tmr1 = currentMillis;
      
      // Выключаем другие LED
      digitalWrite(RLED, LOW);
      digitalWrite(YLED, LOW);
    }
    
    if (currentMillis - tmr2 >= per2) // Таймер для желтого
    {
      digitalWrite(YLED, HIGH);
      tmr2 = currentMillis;

      // Выключаем другие LED
      digitalWrite(GLED, LOW);
      digitalWrite(RLED, LOW);
    }

    if (currentMillis - tmr3 >= per3) // Таймер для красного
    {
      digitalWrite(RLED, HIGH);
      tmr3 = currentMillis;

      // Выключаем другие LED
      digitalWrite(GLED, LOW);
      digitalWrite(YLED, LOW);
    }
  }
}
```

**Изменения**:
1. Добавлена переменная `lightsOn`, чтобы отслеживать, включены ли светодиоды.
2. Исправлена логика функции `debounce()`, чтобы возвращать текущее состояние кнопки.
3. Таймеры для светодиодов обрабатываются отдельно, что позволяет использовать `millis()` для переключения между состояниями светодиодов.

Теперь светодиоды не будут включаться и выключаться одновременно, а кнопка будет должным образом управлять состоянием светофора.
Похоже, вы в trLight() запихнули всю последовательность переключений, только заменив delay() на опрос таймеров. А должна быть логика немного другая: trLight() вызывается каждую (условно) миллисекунду, она должна один раз считать millis(), понять, какая сейчас фаза светофорного цикла, и в зависимости от этого погасить или зажечь нужные светодиоды. Сделайте функцию, у которой на входе текущее время, а на выходе — три бита состояния светодиодов. 

И в debounce() осталась delay(), её тоже хорошо бы на таймерах сделать
Похожие вопросы