Отслеживание нескольких действий
У меня есть несколько светодиодов, подключенных к 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 сегодня не очень-то помогает...
@ProfFalken, 👍1
Обсуждение2 ответа
Лучший ответ:
вам нужно вызывать функцию затухания/импульса каждый раз, пока не изменится состояние светодиода,
Начните с создания полного отдельного состояния для каждого светодиода,
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
Не заглядывая во весь код, лучший способ — использовать «режим» для каждого светодиода. Поэтому для каждого светодиода отслеживайте, как он должен себя вести (например, 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
- Питание светодиодной ленты - Сколько ампер?
- Несколько условий оператора if
- Светодиоды: разница между общим анодом и общим катодом
- Светодиод L продолжает гореть
- Улучшенное циклическое переключение цветов RGB.
- Плавное мигание светодиодов
- Остановить мигание светодиодов
- FastLED - Как управлять определенными светодиодами
ваш код не имеет ничего, что могло бы пульсировать или затухать, кроме `led_choice', @Juraj