Анимация светодиодной ленты с ESP32 не работает при использовании WiFi

c++ esp32 interrupt led-strip

Я использую ESP32 для простого проекта. Я знаю, как анимировать светодиодную ленту, используя atmega328p с Arduino, но когда я анимирую ее на ESP32, это не работает так хорошо. Было бы неплохо, если бы я мог использовать один и тот же ESP32 для запуска всего моего проекта без необходимости включать еще один MCU. Удалось ли кому-нибудь анимировать светодиодную ленту, используя Wi-Fi на ESP32?

Это код, который я использую для анимации светодиодной ленты при использовании Wi-Fi. Я сам написал этот код, поэтому, возможно, я делаю что-то не так. Он работает лучше, чем любая из библиотек, которые я нашел в Интернете. Лучше всего работает библиотека esp32WS2811-master. Но все равно в моем случае этот код работает лучше, чем эта библиотека.

#include <Arduino.h>
#include "WiFi.h"
#include <Adafruit_NeoPixel.h>

// запускаем задачу, которая анимирует светодиодную ленту на отдельном ядре ардуино
TaskHandle_t Task1;

// куда подключен светодиод и количество светодиодов для анимации
#define PIN 32
#define NUM_LEDS 80

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

// мьютекс, который помогает войти в критические секции, пока мы анимируем светодиодную ленту
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;


// он будет работать на ядре 0 esp32. Отвечает за анимацию светодиодной ленты.
void loop2(void *parameter)
{
   uint32_t _color = strip.Color(0, 0, 0);

   for (;;) // бесконечный цикл
   {
      _color = strip.Color(0, 0, 255);

      // анимация 1
      for (uint16_t i = 0; i < strip.numPixels(); i++)
      {                                  
         strip.setPixelColor(i, _color); 

         //портОТКЛЮЧИТЬ_ПРЕРЫВАНИЕ(); // альтернатива портуENTER_CRITICAL
         portENTER_CRITICAL(&mux);        /* start critical section */

         strip.show();

         //portENABLE_INTERRUPTS(); // альтернатива портуEXIT_CRITICAL
         portEXIT_CRITICAL(&mux);         /* end critical section */

         vTaskDelay(15);                  // задержка в один тик (15 мс) между чтениями для стабильности
      }

     
      // анимация 2
      _color = strip.Color(0, 255, 0);
      for (uint16_t i = 0; i < strip.numPixels(); i++)
      {                                   
         strip.setPixelColor(i, _color);  

         //портОТКЛЮЧИТЬ_ПРЕРЫВАНИЕ(); // альтернатива портуENTER_CRITICAL
         portENTER_CRITICAL(&mux);        /* start critical section */

         strip.show();

         //portENABLE_INTERRUPTS(); // альтернатива портуEXIT_CRITICAL
         portEXIT_CRITICAL(&mux);         /* end critical section */

         vTaskDelay(15);                  // задержка в один тик (15 мс) между чтениями для стабильности
      }
   }
}

void setup()
{    
   Serial.begin(115200);

   // отключение Wi-Fi помогает, но нам это нужно
   // WiFi.режим(WIFI_OFF);

   // инициализируем светодиодную ленту
   strip.begin();
   strip.setBrightness(4);
   strip.show(); // Инициализируем все пиксели выключенными

   // создаем задачу, которая работает на ядре 0 esp32
   xTaskCreatePinnedToCore(
       loop2,
       "Task_1",
       1000,
       NULL,
       2, // приоритет 0 — самый низкий.
       &Task1,
       0 // использовать ядро 0. Ядро 1 является ядром по умолчанию
   );

   // продолжить выполнение кода на ядре 1 по умолчанию esp32

   // Установить WiFi в режим станции и отключиться от точки доступа, если она ранее была подключена
   WiFi.mode(WIFI_STA);
   WiFi.disconnect();
   
   Serial.println("Setup done");
}

// в сети сканирования основного цикла просто для того, чтобы показать, как светодиодная лента не работает, когда используется Wi-Fi
// Этот код я скопировал и вставил из примеров WiFi esp32
void loop()
{
   Serial.println("scan start");

   // WiFi.scanNetworks вернет количество найденных сетей
   int n = WiFi.scanNetworks();
   Serial.println("scan done");
   if (n == 0)
   {
      Serial.println("no networks found");
   }
   else
   {
      Serial.print(n);
      Serial.println(" networks found");
      for (int i = 0; i < n; ++i)
      {
         // Печатаем SSID и RSSI для каждой найденной сети
         Serial.print(i + 1);
         Serial.print(": ");
         Serial.print(WiFi.SSID(i));
         Serial.print(" (");
         Serial.print(WiFi.RSSI(i));
         Serial.print(")");
         Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
         delay(10);
      }
   }
   Serial.println("");           

   // ждем 5 секунд до следующего сканирования сети
   auto end = millis() + (unsigned long)5000;
   while(millis() < end)  {
      vTaskDelay(1);
   }

}

Когда я запускаю этот код, первый светодиод мигает. Другие светодиоды отлично анимируют 99,99% времени. Когда я отключаю WiFi, этот код отлично работает. Мне по-прежнему нужен portENTER_CRITICAL(&mux); или portDISABLE_INTERRUPTS();, чтобы он работал, даже если я отключу WiFi. Кому-нибудь удалось успешно анимировать светодиодную ленту с помощью ESP-32, используя Wi-Fi?

Если мне нужно использовать отдельный микроконтроллер, какой из них вы порекомендуете? ATtiny85?

, 👍0

Обсуждение

это не Wi-Fi, это ваши звонки с задержкой и заявления во время, которые останавливают шоу., @dandavis

Задержка является частью анимации. Если я отключу Wi-Fi, анимация будет отлично работать @dandavis. Мне нужно анимировать один светодиод каждые 15 миллисекунд., @Tono Nam

ну, я знаю, что могу передавать значения RGB через Wi-Fi на esp32 со скоростью 30 кадров в секунду на полосе 64 пикселя. Если бы Wi-Fi заблокировался, это выглядело бы очень рывками, но это не так, за исключением случайных сбоев, которые устраняются сами собой. Я даже не возился с прерываниями или явным управлением потоком. Сделайте свою анимацию асинхронной (например, мигание без задержки), чтобы одновременно происходило более одного действия. Для меня это потребовало перезаписи библиотеки adafruit, чтобы переместить циклы в автономные вызываемые функции, которые выполняли работу за одну итерацию в нужное время, как это определено логикой loop() и millis()., @dandavis

Разве все программное обеспечение для управления WiFi не работает на ядре 0? Если вы работаете на ядре 1, это улучшается?, @Majenko

@danvis, вы используете адресную светодиодную ленту? Вы анимируете свой светодиод, меняя цвет одного светодиода за раз? Если я использую не адресную светодиодную ленту, она работает., @Tono Nam

@Majenko, если я использую ядро 1, оно работает лучше. У меня просто мигает раз в 5 секунд. Но светодиоды отлично анимируются, это просто мерцание, которое я должен как-то решить, как решить., @Tono Nam


1 ответ


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

0

Я использовал библиотеку FastLed, и теперь она работает. По какой-то причине библиотека adafruit работает только тогда, когда я не использую WiFi. Этот код работает:

#include "Arduino.h"
#include <FastLED.h>
#include "WiFi.h"

// запускаем задачу, которая анимирует светодиодную ленту на отдельном ядре ардуино
TaskHandle_t Task1;

#define LED_PIN 32
#define NUM_LEDS 108
#define BRIGHTNESS 10
#define LED_TYPE WS2811
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];

#define UPDATES_PER_SECOND 100



// сканируем сеть каждые 5 секунд
void loop2(void *parameter)
{
    for (;;)
    {
        Serial.println("scan start");

        // WiFi.scanNetworks вернет количество найденных сетей
        int n = WiFi.scanNetworks();
        Serial.println("scan done");
        if (n == 0)
        {
            Serial.println("no networks found");
        }
        else
        {
            Serial.print(n);
            Serial.println(" networks found");
            for (int i = 0; i < n; ++i)
            {
                // Печатаем SSID и RSSI для каждой найденной сети
                Serial.print(i + 1);
                Serial.print(": ");
                Serial.print(WiFi.SSID(i));
                Serial.print(" (");
                Serial.print(WiFi.RSSI(i));
                Serial.print(")");
                Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
                delay(10);
            }
        }
        Serial.println("");

        vTaskDelay(5000);
    }
}



void setup()
{

    Serial.begin(115200);

    delay(1000); // задержка безопасности при включении питания
    FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
    FastLED.setBrightness(BRIGHTNESS);


    // Установить WiFi в режим станции и отключиться от точки доступа, если она ранее была подключена
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();

    // создаем задачу, которая работает на ядре 0 esp32
    xTaskCreatePinnedToCore(
        loop2,
        "Task_1",
        1000,
        NULL,
        2, // приоритет 0 — самый низкий.
        &Task1,
        1 // использовать ядро 0. Ядро 1 — ядро по умолчанию
    );

    Serial.println("Setup done");
}


void loop()
{

    // красный
    for (int i = 0; i < NUM_LEDS; i++)
    {
        leds[i] = 0xFF0000;
        FastLED.show();
        FastLED.delay(25);
    }

    // зеленый
    for (int i = 0; i < NUM_LEDS; i++)
    {
        leds[i] = 0x00FF00;
        FastLED.show();
        FastLED.delay(25);
    }

    // синий
    for (int i = 0; i < NUM_LEDS; i++)
    {
        leds[i] = 0x0000FF;
        FastLED.show();
        FastLED.delay(25);
    }

    // rgb красный зеленый синий

    //Периодически менять палитру();
    //FillLEDsFromPaletteColors(startIndex);
}
,

Пожалуйста, примите свой собственный ответ, чтобы он не появлялся снова и снова., @Sim Son