NeoPixel led WS2812B brilla el color correcto solo cada 2ª vez

0

Estoy tratando de crear un proyecto en el que pueda iluminar WS2812B del color que quiera y se entregue un código de color RGB específico a través de UART. Por eso, cuando recibo el código, estoy intentando enviar datos a WS2812B pero parece que funciona solo cada 2 veces cuando realmente no debería y no funciona en absoluto cuando debería .

Estoy usando Atmega328P-PU de Atmel y su velocidad de CPU está configurada en 8MHz. Este código realmente funcionó bien cuando lo escribí primero, pero tuve que cambiar algunas cosas en la sección de UART, así que tuve que compilarlo y vaciarlo nuevamente, pero esta vez se hizo desde Linux usando las herramientas de línea de comandos de avrdude en lugar de Windows 7 (que estaba en mi amigos de la PC y se eliminó).

Este es el diagrama de temporización de datos para WS2812B

Todo en el código funciona bien, excepto para enviar '1' y '0' a LED y sucede en la función set_leds_color . Lo extraño es que si dejo los valores de __builtin_avr_delay_cycles(); como estaban antes de que se actualice el código de UART (y como se muestra en el código), siempre establece el color del LED en blanco como que siempre enviaría '1' al led (255,255,255 ). Incluso si configuro el retraso para '0' en __builtin_avr_delay_cycles (1) nada cambia, cualquier color se muestra en blanco. Ahora, la parte interesante es que si elimino esta demora para '0', el código se convertirá en lo siguiente

//send 0
else{              
   DATA_PORT = high_data;
    DATA_PORT = low_data;
}

cuando configuro el mismo color varias veces seguidas: el LED en realidad configura mi color deseado una vez, pero la segunda vez se vuelve blanco nuevamente. Esto continúa no tengo idea cual es el problema. Probé que __builtin_avr_delay_cycles() funciona como se esperaba y mi frecuencia de CPU es de 8Mhz. También envié rgb_array[] valores de mcu a mi PC, pensé que UART y también están bien. ¿Alguien puede darme algunas sugerencias de lo que podría estar mal? Gracias.

Aquí está mi código final

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

#define DATA_PORT PORTD
#define DATA_PIN PD2
#define DATA_DDR DDRD

/*
UART stuff
*/

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

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

void set_leds_color(unsigned int red, unsigned int green, unsigned int blue)
{
    //prepare 24 color bits to send to LED
    unsigned int rgb_array[24];
    set_color(rgb_array, red, green, blue);

    int high_data = DATA_PORT | (1 << DATA_PIN);
    int low_data = DATA_PORT & (~(1 << DATA_PIN));

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

int main(void)
{
    DATA_DDR = (1 << DATA_PIN);
    DATA_PORT &= ~(1 << DATA_PIN);

    initialize_UART();

    while(1)
    {
        int color_code[3];
        if(receive_color_from_uart(color_code))
        {
            set_leds_color(color_code[0], color_code[1], color_code[2]);
        }
    }

} 
    
pregunta etrusks

1 respuesta

0

Así que lo más extraño solucionó el problema. Creé 2 funciones más

void send_one_bit(int high, int low){
    DATA_PORT = high;
    __builtin_avr_delay_cycles(5);
    DATA_PORT = low;
    __builtin_avr_delay_cycles(1);
}

void send_zero_bit(int high, int low){
    DATA_PORT = high;
    __builtin_avr_delay_cycles(2);
    DATA_PORT = low;
    __builtin_avr_delay_cycles(1);
}

y los usé para enviar cero o un byte

for(int i = 0; i < 24; ++i){
    //send 1
    if(rgb_array[i]){   
        send_one_bit(high_data, low_data);
    }
    //send 0
    else{              
        send_zero_bit(high_data, low_data);
    }
}

Si saco el código de estas funciones y lo coloco directamente dentro de la declaración if/else en forma de línea, siempre aparece el color blanco. Sería feliz si alguien pudiera explicar esta cosa rara.

    
respondido por el etrusks

Lea otras preguntas en las etiquetas