Skip to content

幻彩LED WS2812B

WS2812B 有三个状态,0码和1码 则是在通讯的时候表示0,或者1的状态。
当需要复位LED 灯的时候,则需要使用reset码将LED灯 控制为熄灭的状态。

alt text

下面表示了三个码的时间,这个在GPIO模拟的时候,需要特别注意,GPIO翻转的速度。可以通过逻辑分析仪来读取实际GPIO的控制信号翻转速度。 alt text

下图是单个24bit的数据顺序, alt text

主机会不断的刷新数据,然后逐个传递下去 alt text

1. 硬件连接

这边硬件上使用了PA13 这个PIN来控制灯的信号。 因为WS2812B,这个芯片是串行的总线,所以只需一个GPIO,就可以控制所有连接的LED灯。

alt text

2. CubeMX生成代码

可以看到,配置了3个部分

  1. 外部时钟
  2. SWD 接口
  3. GPIO 配置成输出模式

注意:下图是配置的PB7,板子上需要配置成PC13 alt text

系统时钟72M,需要和图片保持一致 alt text

点击 GENERATE CODE 生成代码

3. 编写代码

3.1 WS2812B 控制相关的代码

下面就是控制WS2812B的代码,其中 “__NOP();” 数量是根据芯片的频率,以及LED的时序要求来调整的。如果跟换芯片,需要自己调整数量。

WS2812B控制代码
c

#define GPIO_WS2812B  GPIOC
#define GPIO_PIN_WS2812B  GPIO_PIN_13
//存储一个转化后的RGB2进制数  共24bits
struct My_24bits                    //结构体
{
    unsigned char G_VAL;                 //绿色  0-255
    unsigned char R_VAL;                  //红色 0-255
    unsigned char B_VAL;                  //蓝色0-255
};
 
struct My_24bits RGB;


/*写入数据时序*/
void Send_A_bit(unsigned char VAL)
{
    if (VAL!=1)
    {
			GPIO_WS2812B->BSRR = GPIO_PIN_WS2812B;
            __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
            GPIO_WS2812B->BSRR = (uint32_t)GPIO_PIN_WS2812B << 16u;
        
            __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
			__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
    }
    else
    {
			GPIO_WS2812B->BSRR = GPIO_PIN_WS2812B;
			__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
			__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
			__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
			__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
			GPIO_WS2812B->BSRR = (uint32_t)GPIO_PIN_WS2812B << 16u;
        
			__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
			__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
			__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
    }
}

void Reset_LED()
{
    HAL_GPIO_WritePin(GPIO_WS2812B,GPIO_PIN_WS2812B, GPIO_PIN_SET);	
    HAL_GPIO_WritePin(GPIO_WS2812B,GPIO_PIN_WS2812B, GPIO_PIN_RESET);
    HAL_Delay(1);

}



/*发送24位字符(包含RGB信息各8位)*/
void Send_24bits(struct My_24bits RGB_VAL)
{
    unsigned char i;
    for(i=0; i<8; i++)
    {
        Send_A_bit(RGB_VAL.G_VAL>>(7-i)&0x01);//注意是从高位先发
    }
    for(i=8; i<16; i++)
    {
        Send_A_bit(RGB_VAL.R_VAL>>(15-i)&0x01);
    }
    for(i=16; i<24; i++)
    {
        Send_A_bit(RGB_VAL.B_VAL>>(23-i)&0x01);
    }

}

一个“Send_24bits”,就是点亮一个LED灯,如果需要点亮多个,则发送多次就可以了。

C
  while (1)
  {
        RGB.G_VAL = 0; RGB.R_VAL = 0;RGB.B_VAL = 255;
        Reset_LED();
        Send_24bits(RGB);
        Send_24bits(RGB);
        Send_24bits(RGB);
        Send_24bits(RGB);
        Send_24bits(RGB);
        Send_24bits(RGB);
        Send_24bits(RGB);
        Send_24bits(RGB);
  }

循环改变LED灯的颜色

C

RGB.G_VAL = 0; RGB.R_VAL = 0;RGB.B_VAL = 0;
int i = 0;
char flag = 0;

while()
{
    i++;
    if(flag == 0)
    {
        RGB.B_VAL = 255 -i;
        RGB.R_VAL = i;
        if(i == 255)
        {
            i =0;
            flag = 1;
        }
    }else if(flag ==1)
    {
        RGB.R_VAL = 255 -i;
        RGB.G_VAL = i;
        if(i == 255)
        {
            i =0;
            flag = 2;
        }
    }else if(flag ==2)
    {
        RGB.G_VAL = 255 -i;
        RGB.B_VAL = i;
        if(i == 255)
        {
            i =0;
            flag = 0;
        }
    }
    HAL_Delay(1);
}

4. 后记

  1. 可以在代码中循环调整灯的颜色,从而实现颜色变化,---------待完善
  2. 单个GPIO可以实现多灯的控制,如果没有刷新速度的要求,则可以做低刷新速度的屏幕