Как именно работают велосипедные светодиоды? (Проект Arduino)

led

Оглавление:

  1. Чего я хочу достичь
  2. Проблема, с которой я столкнулся
  3. Что я пробовал
  4. Возможные гипотезы

Чего я хочу достичь

Привет, ребята, я работаю над проектом DIY LED Light для установки на мой велосипед, где я хочу воссоздать, как работают настоящие светодиодные велосипедные фонари:

[Этап 1] Нажмите кнопку один раз: светодиод загорается вечно, пока кнопка не будет нажата снова. [Этап 2] Нажмите кнопку дважды: светодиод мигает вечно, пока кнопка не будет нажата снова. [Этап 3] Нажмите кнопку трижды: светодиод выключается (возвращается в исходное состояние).

Проблема, с которой я столкнулся

После небольшого исследования я знаю, как разработать код для [Stage 1] (отслеживая текущее и предыдущее состояния кнопок). Но я не могу осуществить [Стадию 2].

Что я пробовал

Я пытался вместо отслеживания предыдущего и текущего состояний кнопок, почему бы не использовать счетчик, то есть:

Счетчик = 0 (начальный) При однократном нажатии кнопки счетчик = 1 (светодиод горит вечно, пока кнопка не будет нажата снова)

При повторном нажатии кнопки, Счетчик = 2 (светодиод мигает вечно, пока кнопка не будет нажата снова)

При повторном нажатии кнопки, Счетчик = 3 (светодиод выключается, возвращается в исходное НИЗКОЕ состояние) Счетчик снова сбрасывается на = 0

Вот мой код ниже:

const int ledPin = 8;
const int buttonPin = 7;

int buttonState;
int ledState;
int counter = 0;
int newcounter;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  digitalWrite(ledPin, HIGH);
}

void loop() {
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    newcounter = counter + 1;
    delay(500);
    if (newcounter != counter) {
      switch (newcounter) {
        case 1: 
            digitalWrite(ledPin, LOW);
            counter = newcounter;
            break;
        case 2: 
            digitalWrite(ledPin, HIGH);
            delay(500);
            digitalWrite(ledPin, LOW);
            delay(500);
            digitalWrite(ledPin, HIGH);
            delay(500);
            digitalWrite(ledPin, LOW);
            delay(500);
            digitalWrite(ledPin, HIGH);
            delay(500);
            digitalWrite(ledPin, LOW);
            delay(500);
            digitalWrite(ledPin, HIGH);
            delay(500);
            break;
        case 3: 
            digitalWrite(ledPin, HIGH);
            counter = 0;
            break;
        default: 
            digitalWrite(ledPin, HIGH);
            counter = 0;
            break;       
      }
    }
  }   
}

Возможные гипотезы (пожалуйста, критикуйте/поправьте меня, если я ошибаюсь)

А) Есть проблема с моим кодом (моя логика программирования и т. Д.)

Б) Может быть, это не проблема кода/программы? Это может быть связано с конструкцией электрической цепи (потому что я видел видео на YouTube, где светодиоды можно заставить мигать с помощью конденсаторов и транзисторов. Но как происходит последовательность от этапов 1 до 3 в велосипедном светодиодном фонаре? (https://www.youtube.com/watch?v=cXCExzIBNsA)

Я буду бесконечно благодарен, если кто-нибудь сможет помочь! Спасибо!!

, 👍1

Обсуждение

Прежде всего, вам нужно избавиться от всех этих вызовов delay () ' и реализовать его неблокирующим способом (посмотрите на BlinkWithoutDelay.ino`)., @Sim Son

Вы пропускаете строку counter = newcounter; в вашем "случае 2:", но реальная проблема (вероятно, поскольку вы на самом деле не описали, что означает " Но я не могу сделать [Этап 2]") почти наверняка заключается в том, что у вас есть только 3 мигания, а затем ваш код выходит из состояния и возвращается к началу цикла. Сим Сын уже дал вам один способ исправить это. Ваш код может работать немного больше, чем вы предполагаете, если вы переместите весь блок "switch" за пределы блока " if (buttonState == HIGH)". Как вы уже написали, дело со всеми миганиями выполняется только при нажатии кнопки., @brhans

Ваша проблема в том, что ваш код управления светодиодом полностью запутан с вашим нажатием кнопки и кодом счетчика. Разделите их на совершенно независимые блоки кода. Тот, который просто увеличивает счетчик с помощью кнопки, и тот, который отображает разные вещи в зависимости от текущего значения счетчика., @Majenko

@glen_geek, Это код Arduino. Библиотека Aduino эффективно вызывает while(true) loop(); https://www.arduino.cc/reference/en/language/structure/sketch/loop/, @Solomon Slow


2 ответа


1

вы не заявляете, какие результаты вы получаете.

Я вижу, что вы не предустановляете свои переменные состояния.
Это всегда хорошая практика, чтобы избежать случайных условий запуска.

у вас есть логика, которая будет работать только тогда, когда кнопка удерживается , ваш оператор if (newcounter != counter) и switch выполняются только при нажатии кнопки. переместите их за пределы проверки состояния кнопки и ищите изменения ТОЛЬКО в том случае, если кнопка изменилась.

попробуй это; он будет действовать только при изменении кнопки а не непрерывно поэтому изменения происходят только при каждом нажатии

я оставлю вас играть с условиями переключения

const int ledPin = 8;
const int buttonPin = 7;

int buttonState, chngButtonState = 0;
int ledState;
int counter = 0;
int newcounter;

void setup() {
  chngButtonState = buttonState; 
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  digitalWrite(ledPin, HIGH);
}

void loop() {
      buttonState = digitalRead(buttonPin);
      if (buttonState == HIGH && !buttonState == chngButtonState ) {     // read once only if changed button state changed not on every loop
        newcounter = counter + 1;
        delay(500);
        chngButtonState = buttonState;      // mae them equal again
        }                // NOTE I moved 1 of the } from the bottom
        
        if (newcounter != counter) {
          switch (newcounter) {
            case 1: 
                digitalWrite(ledPin, LOW);
                counter = newcounter;
                break;
            case 2: 
                digitalWrite(ledPin, HIGH);
                delay(500);
                digitalWrite(ledPin, LOW);
                delay(500);
                digitalWrite(ledPin, HIGH);
                delay(500);
                digitalWrite(ledPin, LOW);
                delay(500);
                digitalWrite(ledPin, HIGH);
                delay(500);
                digitalWrite(ledPin, LOW);
                delay(500);
                digitalWrite(ledPin, HIGH);
                delay(500);
                break;
            case 3: 
                digitalWrite(ledPin, HIGH);
                counter = 0;
                break;
            default: 
                digitalWrite(ledPin, HIGH);
                counter = 0;
                break;       
          }
        }
    }

теперь просто поиграйте с операторами Switch, чтобы получить свои результаты.

pinMode(buttonPin, ВХОД);

ваша проводка кнопок не ясна.

Скорее всего, у вас есть кнопка, подключенная к VCC и контакту 7. У вас все еще должен быть выдвижной резистор от arduino pin7 до GND, чтобы получить надежные состояния.

Однако, если кнопка находится от pin7 до GND и не подтягивается, состояние также не изменится.

Если это так; измените pinMode(buttonPin, INPUT) на pinMode(buttonPin, INPUT_PULLUP), и внешний подтягивающий резистор не понадобится.

,

0

Подумайте о "стадиях", которые вы определили как состояния или режимы работы, и нажатия кнопок циклически переходят от одной стадии к другой.

Затем для "этапа 2" вы переписываете его как функцию, которая в основном не блокируется и не простаивает в течение 3,5 секунд, но которая немедленно возвращает управление обратно в цикл (), чтобы вы могли быстро проверить наличие дополнительных нажатий кнопок:

// эта функция построена по образцу примера в
// https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay
void stage2(void){
  const unsigned long interval = 500;
  static unsigned long last = 0;
  if(millis() - last >= interval){
    last += interval;
    digitalWrite(ledPin, !digitalRead(ledPin));
  }
}

а затем вы включаете сцену в цикле событий:

      switch (stage) {
        case 0: // idle
            break;
        case 1: // on
            digitalWrite(ledPin, LOW);
            counter = newcounter;
            break;
        case 2: // blinking
            stage2();
            break;
        case 3: // turn off
            digitalWrite(ledPin, HIGH);
            stage = 0;
            break;
        default: 
            digitalWrite(ledPin, HIGH);
            counter = 0;
            break;       
      }
      ...

Этот переключатель почти не занимает времени и возвращает управление циклу событий, поэтому пользовательский интерфейс может быстро реагировать на другие нажатия кнопок или проверять наличие других задач.

Я не переписывал остальную часть вашего кода, но вот ключевые различия между вашим кодом и тем, что работает в велосипедном свете:

  1. Используйте переменные состояния и конечные автоматы для изменения режима работы.

  2. Избегайте захвата процессора в "блокирующий" код, который использует delays (), for(;;), while (); и т. Д... Вместо этого полагайтесь на цикл событий (loop() в Arduino), чтобы вернуть управление вашим функциям.

Существует имитация велосипедного фонаря с использованием этих шаблонов кодирования на Wokwi по адресу https://wokwi.com/arduino/projects/325075981102482003

,