Глюки в WS2812B

forfrends
Offline
Зарегистрирован: 24.02.2015

Всем привет! Создаю один проект. В качестве индикации буду использовать адресные светодиоды WS2812B, 16 штук, которые создают визуальную шкалу. Код:

#include <Adafruit_NeoPixel.h>
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

char auth[] = "1f65de93e395467c9a2bab7f12886742";
char ssid[] = "DIR-615";
char pass[] = "forfrends";

#define LedPIN    13    // Pin D7
                        // On Trinket or Gemma, suggest changing this to 1
#define NUMPIXELS 16    // Popular NeoPixel ring size

#define FanPin 13       // D7
int FanSpeed = 500;
bool Ionithation = false;
#define IonPin 2       // D8
#define Button 0        // D3
#define pin_A 14        // D5
#define pin_B 12        // D6
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;
unsigned char encoder_B_prev=0;
String input_string = "";
int Pow = 7;

//Adafruit_NeoPixel pixels(NUMPIXELS, LedPIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, LedPIN, NEO_GRB + NEO_KHZ800);

void setup()
{
    Serial.begin(9600);
    
    Blynk.begin(auth, ssid, pass);
    // You can also specify server:
    //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80);
    //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080);
    pinMode(pin_A, INPUT);
    pinMode(pin_B, INPUT);
    pinMode(Button, INPUT);
    digitalWrite(Button, HIGH);
    pinMode(IonPin, OUTPUT);
    digitalWrite(IonPin, LOW);
    pinMode(FanPin, OUTPUT);
    analogWrite(FanPin, FanSpeed);
    pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
    pixels.show();  
    StripUpdate();
}

BLYNK_READ(V0)
{
    Blynk.virtualWrite(V0, Pow);
}

BLYNK_WRITE(V1)
{
    Pow = param.asInt();
    if (Pow > NUMPIXELS) Pow = NUMPIXELS;
    else if (Pow < 1) Pow = 1;
    StripUpdate();
}

BLYNK_WRITE(V2)
{
    Ionithation = param.asInt();
    digitalWrite(IonPin, Ionithation);
    StripUpdate();
}

void loop()
{
    Blynk.run();
    // You can inject your own code or combine it with other sketches.
    // Check other examples on how to communicate with Blynk. Remember
    // to avoid delay() function!
    
    encoder();
    button();
}

void button(){
    if (!digitalRead(Button)){
        Ionithation = !Ionithation;
        StripUpdate();
        Blynk.virtualWrite(V2, Ionithation);
        delay(300);
    }
}

void encoder(){
    encoder_A = digitalRead(pin_A);     // считываем состояние выхода А энкодера 
    encoder_B = digitalRead(pin_B);     // считываем состояние выхода B энкодера    
    if((!encoder_A) && (encoder_A_prev)){    // если состояние изменилось с положительного к нулю
        if(encoder_B) {
            if (Pow<NUMPIXELS){
                Pow++;
            }else{
                Pow = NUMPIXELS;
            }
            StripUpdate();
        }   
        else {
            if (Pow > 1){
                Pow--;
            }else{
                Pow=1;
            }
            StripUpdate();
        }  
    } 
    else if((!encoder_B) && (encoder_B_prev)){    // если состояние изменилось с положительного к нулю
        if(!encoder_A) {
            if (Pow<NUMPIXELS){
                Pow++;
            }else{
                Pow = NUMPIXELS;
            }
            StripUpdate();
        }   
        else {
            if (Pow > 1){
                Pow--;
            }else{
                Pow=1;
            }
            StripUpdate();
        }  
    }
    encoder_A_prev = encoder_A;     // сохраняем значение А для следующего цикла 
    encoder_B_prev = encoder_B;
}

void StripUpdate()
{
    FanSpeed = map(Pow, 1, NUMPIXELS, 50, 1023);
    analogWrite(FanPin, FanSpeed);
    if (Ionithation) {
        digitalWrite(IonPin, HIGH);
        for(int i=0; i<Pow; i++) {
            pixels.setPixelColor(i, pixels.Color(40, 20, 0));
            pixels.show();
        }
    }else{
        digitalWrite(IonPin, LOW);
        for(int i=0; i<Pow; i++) { // For each pixel...
            pixels.setPixelColor(i, pixels.Color(0, 0, 80));
            pixels.show();
        }
    }
    if (Pow < NUMPIXELS){
        for(int i=Pow; i<NUMPIXELS; i++) { // For each pixel...
            pixels.setPixelColor(i, pixels.Color(0, 80, 0));
            pixels.show();
        }
    }
    
    delay(30);
}

Последняя функция StripUpdate() отвечает за формирование цвета на ленте. Переменная Pow содержит текущий уровень шкалы по количеству светодиодов (1-16). NUMPIXELS - максимальный уровень (количество светодиодов, в данном случае - 16).
Суть функции закрашивать Pow количество светодиодов синим (или желтым), а дальше до конца зеленым цветами. Выглядеть это должно быть так: Допустим Pow = 6, значит первые 6 светодиодов светят синим, а остальные (7-16) зеленым....
Но наблюдаются глюки. То цвет не тот, то вместо 16 светит 18 (и более) светодиодов, то вся лента нормально светит, правильно, а один светодиод горит не тем цветом, голубым, или розовам, или вообще красным, в общем совсе не того цвета.
При этом обычные примеры из NeoPixel работают без проблем и без глюков.
Что можете посоветовать? Что я сделал не так, где ошибся?

b707
Offline
Зарегистрирован: 26.05.2017

команда pixels.show(); высвечивает на ленте готовую картинку. Ее надо подавть после того, как вы вывели цвет на все диоды. А вы ее в цикле после каждого диода лепите.

Или после каждого pixels.show(); надо ставить задержку, такую чтобы вся пиксели успели пересчитаться и в и вывестись на ленту

sadman41
Offline
Зарегистрирован: 19.10.2016

b707 пишет:

Или после каждого pixels.show(); надо ставить задержку, такую чтобы вся пиксели успели пересчитаться и в и вывестись на ленту

После show() задержка требуется только для того, чтобы зритель смог насладиться композицией текущего фрейма ;)

А так - диагноз верный, поддерживаю.

forfrends
Offline
Зарегистрирован: 24.02.2015

Вставка пауз делает переключение ленты плавным, с последовательным обновлением светодиодов. Мне такие спец эферты не нужны. Кстати, так в примерах сделано.
Пробовал убирать pixels.show();, и ставить его только в самом конце - это ни на что не влияет.

sadman41
Offline
Зарегистрирован: 19.10.2016

В конце - где?

forfrends
Offline
Зарегистрирован: 24.02.2015

Так:

void StripUpdate()
{
    FanSpeed = map(Pow, 1, NUMPIXELS, 50, 1023);
    analogWrite(FanPin, FanSpeed);
    if (Ionithation) {
        digitalWrite(IonPin, HIGH);
        for(int i=0; i<Pow; i++) {
            pixels.setPixelColor(i, pixels.Color(40, 20, 0));
            //pixels.show();
        }
    }else{
        digitalWrite(IonPin, LOW);
        for(int i=0; i<Pow; i++) { // For each pixel...
            pixels.setPixelColor(i, pixels.Color(0, 0, 80));
            //pixels.show();
        }
    }
    if (Pow < NUMPIXELS){
        for(int i=Pow; i<NUMPIXELS; i++) { // For each pixel...
            pixels.setPixelColor(i, pixels.Color(0, 80, 0));
            //pixels.show();
        }
    }
    pixels.show();
    delay(30);
}

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Должно работать. Переменный резистор возьмите, замапьте его analogRead() в 1...NUMPIXELS и проверьте на StripUpdate(). 

forfrends
Offline
Зарегистрирован: 24.02.2015

Попробовал тестовый скетч:
 

#include <Adafruit_NeoPixel.h>

#define LedPIN    13    // Pin D7
                        // On Trinket or Gemma, suggest changing this to 1
#define NUMPIXELS 16    // Popular NeoPixel ring size

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, LedPIN, NEO_GRB + NEO_KHZ800);
int Pow = 0;
bool Ionithation = false;
void setup() {
    pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
    pixels.show();  
    StripUpdate();

}

void loop() {
    for (Pow = 1; Pow<17; Pow ++)
    {
        StripUpdate();
        delay(400);
    }
    Ionithation = !Ionithation;
}

void StripUpdate()
{
    if (Ionithation) {
        for(int i=0; i<Pow; i++) {
            pixels.setPixelColor(i, pixels.Color(40, 20, 0));
            //pixels.show();
        }
    }else{
        for(int i=0; i<Pow; i++) { // For each pixel...
            pixels.setPixelColor(i, pixels.Color(0, 0, 80));
            //pixels.show();
        }
    }
    if (Pow < 16){
        for(int i=Pow; i<16; i++) { // For each pixel...
            pixels.setPixelColor(i, pixels.Color(0, 80, 0));
            //pixels.show();
        }
    }
    pixels.show();
    delay(30);
}

И... все работает! Значит проблема не в том как написана функция StripUpdate(). Что-то другое нарушает работу NeoPixel. Есть идеи?

sadman41
Offline
Зарегистрирован: 19.10.2016

Особо идей нет. Но я бы для начала из первого скетча вынес весь Blynk...

А вообще, Ваша функция сворачивается в такое:

const uint32_t colorIonithation   = 0xAABB00; 
const uint32_t colorNoIonithation = 0x000099; 
const uint32_t colorBackground    = 0x009900; 

...

void StripUpdate()
{
     ...
     digitalWrite(IonPin, Ionithation);
     for (uint8_t i = 0; i < 16; i++) {
         pixels.setPixelColor(i, (i < Pow) ? (Ionithation ? colorIonithation : colorNoIonithation) : colorBackground);
     }
    pixels.show();
    delay(30);
}

 

forfrends
Offline
Зарегистрирован: 24.02.2015
Все оказалось гораздо проще... все дело в невнимательности. В коде я назначил выходы на ленту и ШИМа на один и тот же пин:
...
#define LedPIN 13 // Pin D7
// On Trinket or Gemma, suggest changing this to 1
#define NUMPIXELS 16 // Popular NeoPixel ring size
#define FanPin 13 // D7
...
Переназначил выводы и глюк пропал.
forfrends
Offline
Зарегистрирован: 24.02.2015

sadman41, спасибо за пример! 

Можете его объяснить? Я не силен в программировании, такая структура для меня неизвестна. Что означает символ "?", какая его функция?

Где об этом можно почитать?

sadman41
Offline
Зарегистрирован: 19.10.2016

forfrends пишет:

Что означает символ "?", какая его функция?

https://prog-cpp.ru/c-if/ -> Тернарные операции

forfrends
Offline
Зарегистрирован: 24.02.2015

Спасибо!