El led WS2812B de NeoPixel no brilla cuando se le dan niveles de RGB iguales

0

Estaba intentando iluminar WS2812B y funciona bien cuando se le da un código RGB similar a este (255, 145, 67). Pero cuando envío un código como (255, 67, 67) a este diodo, no se enciende. Del mismo modo, si deseo obtener un color blanco puro, no puedo enviar el código (255,255,255), sino que debo enviar (255,254,253) para que todos sean diferentes.

Esto no parece ser un problema de software para mí, pero aquí está el código del programa. Estoy usando ATmega328p mcu de Atmel a 8 MHz y el código se compila con el compilador avr-gcc. Agradecería cualquier sugerencia de cómo solucionar este problema!

#include <avr/io.h>
#include <util/delay.h>

#define DATA_PORT PORTD
#define DATA_PIN PD0
#define DATA_DDR DDRD


void fill_array(int* arr, int color)
{
    for(int i = 0; i < 8; ++i)
    arr[i] = color & (1 << (7 - i));
}

void set_color(int* arr, int red, int green, int blue)
{
    fill_array(arr, green);
    fill_array(&arr[8], red);
    fill_array(&arr[16], blue);
}

int main(void)
{

    int rgb_array[24];
    set_color(rgb_array, 0,255,0);

    DATA_DDR = (1 << DATA_PIN);
    DATA_PORT &= ~(1 << DATA_PIN);
    _delay_us(100);

    for(int i = 0; i < 24; ++i)
        if(rgb_array[i]){    //send one
                           //1 clock cycle is 0.125us           
            DATA_PORT = 1; __builtin_avr_delay_cycles(6); DATA_PORT = 0;
        }
        else{  //send zero
            DATA_PORT = 1; __builtin_avr_delay_cycles(3); DATA_PORT = 0;
        }

    DATA_PORT &= ~(1 << DATA_PIN); //reset signal
}
    
pregunta etrusks

2 respuestas

1

Sospecho que el problema es eléctrico: el WS2812B se atenúa mediante el uso de PWM, es decir, enciende y apaga los LED. La conmutación hace que el consumo de corriente varíe y provoca ruido en la línea eléctrica. Ahora, si dos de ellos tienen la misma configuración y cambian al mismo tiempo, el ruido se acumula y causa un error en el controlador de los diodos. Intente agregar un capacitor de 100 nF (o similar) cerca del LED entre VCC y GND.

En cuanto al tiempo, los WS2812B son mucho más fáciles de controlar que lo que sugiere el diagrama de tiempo. Mi experiencia es, siempre y cuando se asegure de que el período alto esté entre 0.25 y 0.5 µs para un '0' y más de 0.7 µs para un '1'; y el período bajo es más corto que el tiempo de reinicio, todo funciona bien.

No se ha comprobado lo siguiente, pero creo firmemente que la lógica dentro del controlador para recibir datos es simplemente "espere a que la entrada sea alta. espere 0.6 µs. compruebe si la entrada sigue siendo alta ('1') o baja nuevamente ( '0'). Repite. "

    
respondido por el asdfex
0

Figura1.El WS2812B diagrama de tiempo.

Mirando tu código, parece que tu código permite que los pulsos sean múltiplos de 0.125 µs. Esto le dará posibilidades de tiempo de 0.125, 0.250, 0.275, 0.500, 0.625, 0.750, 0.875, 1.000 y 1.125 µs. Puede ver que, mientras que la tolerancia de 150 ns se adapta a esto, ninguno de los tiempos es ideal.

_delay_us(100);

for(int i = 0; i < 24; ++i)
    if(rgb_array[i]){    //send one
                       //1 clock cycle is 0.125us           
        DATA_PORT = 1; __builtin_avr_delay_cycles(6); DATA_PORT = 0;
    }
    else{  //send zero
        DATA_PORT = 1; __builtin_avr_delay_cycles(3); DATA_PORT = 0;
    }
}

Mi otra sospecha es que tiene retrasos para las señales '1' pero no tiene retraso para la señal '0'. Esperaba:

    if(rgb_array[i]){    //send one
        DATA_PORT = 1; 
        __builtin_avr_delay_cycles(6);     //T1H
        DATA_PORT = 0;
        __builtin_avr_delay_cycles(3);     //T1L
    }
    else{  //send zero
        DATA_PORT = 1; 
        __builtin_avr_delay_cycles(3);     //T0H
        DATA_PORT = 0;
        __builtin_avr_delay_cycles(6);     //T0L
    }

¿He detectado el error?

    
respondido por el Transistor

Lea otras preguntas en las etiquetas