Отслеживание нескольких действий

led

У меня есть несколько светодиодов, подключенных к Arduino, который получает JSON-словарь.

JSON-словарь определяет, какое действие должны выполнять светодиоды (затухание, импульс, включение или выключение), но у меня возникли проблемы с тем, как заставить один светодиод мигать, пока другой затухает и т. д.

Важные части кода выглядят так:

int led_choice;
int led_brightness;
String pattern_name;
int pattern_length;

// Настройка таймера
unsigned long led1_current_time;
unsigned long led2_current_time;
unsigned long previousFadeMillis[2];
unsigned long previousPulseMillis[2];
unsigned long current_time;

// настройка затухания
int fadeInterval = 50;
int fadeIncrement = 5;
int fadeDirection = 1;
int fadeValue = 0;
int maxPWM = 255;
int minPWM = 0;
int translated_pin;

// Настройка импульса
int pulse_state = 0;

void setup() {
  pinMode(BUILTIN_LED, OUTPUT);     // Инициализируем вывод BUILTIN_LED как выход
  Serial.begin(115200);
}

void loop() {

  current_time = millis();

  // КОД ЗДЕСЬ ДЛЯ ЧТЕНИЯ SERIAL/MQTT, РАСШИФРОВКИ JSON И ИЗВЛЕЧЕНИЯ ПЕРЕМЕННЫХ

  if ( pattern_name == "fade"){
    fade(current_time, pattern_length, led_brightness, led_choice);
  } else if ( pattern_name == "pulse"){
    pulse(current_time, pattern_length, led_brightness, led_choice); 
  }
  else if (pattern_name == "on" )
  {
    solid_running(led_choice, led_brightness);
  }
  else {
    switch_off(led_choice);
  }
}


/********** LED CONTROL FUNCTIONS *********/
void fade(unsigned long thisMillis, int fadeInterval, int maxPWM, int led_pin) {
  if (thisMillis - previousFadeMillis[led_pin] >= fadeInterval) {
    // да, пора!
    if (fadeDirection == 1) {
      fadeValue = fadeValue + fadeIncrement;
      if (fadeValue >= maxPWM) {
        // На максимуме, ограничение и изменение направления
        fadeValue = maxPWM;
        fadeDirection = 0;
      }
    } else {
      //если мы не идем вверх, мы идем вниз
      fadeValue = fadeValue - fadeIncrement;
      if (fadeValue <= minPWM) {
        // На минимуме, предел и изменение направления
        fadeValue = minPWM;
        fadeDirection = 1;
      }
    }
    // Нужно обновлять только при изменении
    analogWrite(led_pin, fadeValue);
    // сбросить миллис для следующей итерации (только таймер затухания)
    previousFadeMillis[led_pin] = thisMillis;
  }
}

void pulse(unsigned long thisMillis, int on_duration, int on_speed, int led_pin){
  if (thisMillis - previousPulseMillis[led_pin] >= on_duration) {
    // сохраните время последнего мигания светодиода
    previousPulseMillis[led_pin] = thisMillis;

    // если светодиод выключен, включите его и наоборот:
    if (pulse_state == 0) {
      pulse_state = 1;
      // устанавливаем светодиод с помощью ledState переменной:
      analogWrite(led_pin, 255);
    } else {
      analogWrite(led_pin, 0);
      }      
      pulse_state = 0;
    }
  }
}

void switch_off(int led_pin){
    analogWrite(led_pin, 0);
}

void solid_running(int led_pin, int led_brightness){
    analogWrite(led_pin, led_brightness);
}

Если я отправлю данные JSON, сообщающие светодиоду 1 о необходимости мигать, как только я отправлю вторую строку, сообщающую светодиоду 2 о необходимости затухания, светодиод 1 перестанет мигать.

Я уверен, что это очевидно, но это сводит меня с ума уже несколько дней!

РЕДАКТИРОВАНИЕ: Добавляю вторую попытку

// Объявляем количество светодиодов
const int led_count = 2;

// Настройка ENUM для различных режимов
enum EMode { Off, On, Pulse, Fade };
// Создаем структуру и инициализируем ее
struct MMode {
  EMode pin_mode;
  int action_pin;
  int action_delay;
  int action_max;
  int action_min;
  int fade_direction;
  int fade_value;
  int fade_increment;
  unsigned long m_current_time;
  unsigned long previous_millis;
} leds[led_count] {
  {Fade, D4, 20, 255, 0, 1, 0, 1, 0, 0},
  {Fade, BUILTIN_LED, 20, 255, 0, 1, 0, 1, 0, 0}
};


void setup() {
  Serial.begin(9600);
  // Настройка встроенного светодиода
  pinMode(BUILTIN_LED, OUTPUT);
  // Настройка красного светодиода
  pinMode(D4, OUTPUT);
}

void loop() {
    for (int n = 0; n < led_count; n++) {
      leds[n].m_current_time = millis();
      switch(leds[n].pin_mode){
        case Fade:
          fade(leds[n]);
          break;
      }
    }
}

/********** LED CONTROL FUNCTIONS *********/
void fade(struct MMode led) {
  if (led.m_current_time - led.previous_millis >= led.action_delay) {
    // да, пора!
    if (led.fade_direction == 1) {
      led.fade_value = led.fade_value + led.fade_increment;
      Serial.print("Fade Up Value: ");
      Serial.print(led.fade_value);
      Serial.println("    ");
      if (led.fade_value >= led.action_max) {
        // На максимуме, ограничение и изменение направления
        led.fade_value = led.action_max;
        led.fade_direction = 0;
      }
    } else {
      //если мы не идем вверх, мы идем вниз
      led.fade_value = led.fade_value - led.fade_increment;
    // Serial.print("Значение уменьшения");
    // Serial.print(led.fade_value);
    // Serial.print(" ");
      if (led.fade_value <= led.action_min) {
        // На минимуме, предел и изменение направления
        led.fade_value = led.action_min;
        led.fade_direction = 1;
      }
    }
    //Serial.print(led.fade_value);
    //Серийный.печать(" ");
    // Нужно обновлять только при изменении
    analogWrite(led.action_pin, led.fade_value);
    // сбросить миллис для следующей итерации (только таймер затухания)
    led.previous_millis = led.m_current_time;
    //Serial.print(led.previous_millis);
    //Серийный.печать(" ");
  }
}

Эта вторая итерация кода, по-видимому, правильно определяет светодиоды с использованием структуры, однако, когда я загружаю его в Arduino, motor.fade_value устанавливается равным 1 и никогда не увеличивается выше этого значения.

У меня такое чувство, что я что-то упускаю из ответов, которые мне уже давали, но я не уверен, что именно, а Google сегодня не очень-то помогает...

, 👍1

Обсуждение

ваш код не имеет ничего, что могло бы пульсировать или затухать, кроме `led_choice', @Juraj


2 ответа


Лучший ответ:

1

вам нужно вызывать функцию затухания/импульса каждый раз, пока не изменится состояние светодиода,

Начните с создания полного отдельного состояния для каждого светодиода,

struct LED_state{
    STATE state;

    unsigned long led1_current_time;
    unsigned long previousMillis;
    int pin;
    int fadeValue;
    int fadeDirection;
    int pulse_state = 0;
}

LED_state led[2];

STATE — это перечисление для каждой анимации, которую вы делаете. Измените функции так, чтобы они принимали указатель на это состояние. Инициализируйте их в init().

Затем создайте функцию обновления, которая выглядит так:

void updateLED(LED_state* state){
    switch(state->state){
    case FADE:  fade(state);break;
    case PULSE: pulse(state);break;
    case ON:    solid_running(state);break;
    case OFF:   switch_off(state);break;
    }
}

Каждый раз в цикле вы вызываете эту функцию обновления для каждого состояния светодиода.

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

  if ( pattern_name == "fade"){
    led[chosen_led]->state = FADE;
  } else if ( pattern_name == "pulse"){
    led[chosen_led]->state = PULSE;
  } else if (pattern_name == "on" ){
    led[chosen_led]->state = ON;
  } else {
    led[chosen_led]->state = OFF;
  }
,

Так это тот же подход, что и у @michel-keijzers (мне кажется, так оно и есть!), или он отличается? Если он отличается, не могли бы вы объяснить, что/почему, чтобы я мог принять обоснованное решение? Спасибо :), @ProfFalken

это почти то же самое, за исключением того, что я добавил больше состояний в структуру per led, @ratchet freak


2

Не заглядывая во весь код, лучший способ — использовать «режим» для каждого светодиода. Поэтому для каждого светодиода отслеживайте, как он должен себя вести (например, Off, On, Blink, FadeOff, FadeOn и т. д.) и некоторые параметры (например, скорость затухания). Для этого можно использовать структуру, например

enum EMode { Off, On, Pulse, FadeOff, FadeOn };
struct LedMode
{
   EMode mode;
   int fadeSpeed; // Используется только когда mode = fade off/on
};

LedMode ledModes[8]; // Например, для 8 светодиодов

Когда вы получите команду JSon, измените структуру ledMode для этого светодиода соответствующим образом.

Затем в основном цикле используйте что-то вроде:

loop()
{
    for (int n = 0; n < 8; n++) // Для каждого светодиода
    {
       switch (ledModes[n].mode)
       {
       case Off: 
         TurnOff(ledModes[n]);
         break;

       case On:
          TurnOn(ledModes[n]);
          break;

       case Pulse:
          Pulse(ledModes[n]);
          break;

       case FadeOn:
          FadeOn(ledModes[n]);
          break;

       ...
    }
}

Чтобы избежать постоянного перехода к каждому случаю, добавьте в структуру флаг «Dirty», который устанавливается в значение true с помощью JSON и устанавливается в значение false после выполнения изменения (например, вам нужно включить или выключить светодиод только один раз, а не в каждом цикле). Для FadeOn/Off, пока он не достигнет 255 или 0. Вы также можете использовать PreviousMode и проверить, был ли изменен режим с последнего раза.

А для Pulse/FadeOn/Off вам нужно добавить в структуру последнее установленное значение, чтобы иметь возможность увеличивать/уменьшать его, и время его последнего изменения.

Кстати, вы также можете передать n и получить LedModes[n] напрямую, поскольку он является глобальным.

,

То есть это переместит весь код, управляющий светодиодами, *из* выделенных функций и непосредственно в основной цикл как часть оператора switch?, @ProfFalken

Нет, это была просто «структура».... ПОЖАЛУЙСТА, сохраните отдельные функции, вы можете передать структуру для этого светодиода в функцию (ledModes[n], где n — светодиод, который в данный момент обрабатывается в цикле). Используйте отдельную функцию для каждого режима, это очень хорошая практика программирования., @Michel Keijzers

Это меня и смутило, ведь сохранение их имеет большой смысл. Я привык писать код на Python, но у меня возникли трудности с переводом кода на C! Спасибо., @ProfFalken

Вы делаете хорошую работу, это упростит задачу, если вы используете структуру с параметрами, так что каждый светодиод будет иметь свой собственный набор данных, а затем в функциях режима (выкл., вкл., импульс и т. д.) вы сможете изменять интенсивность светодиода в зависимости от параметров, независимо от других светодиодов., @Michel Keijzers

К сожалению, я могу принять только один ответ, и именно часть о ссылках и настройке переменных в ответе @rachettFreak наконец заставила это работать для меня. Спасибо за всю помощь, это действительно ценно, и если бы я мог, я бы тоже выбрал ваш ответ!, @ProfFalken

Его способ на самом деле лучше, но я хотел, чтобы мое решение было простым для понимания. Хорошо, что вы понимаете его и можете его использовать. Использование структур или лучше: классов для хранения информации и функциональности вместе всегда является хорошей идеей, или, лучше сказать: использование структур/классов для разделения различной информации/функциональности лучше., @Michel Keijzers