现在带IC的彩灯虽然有 SK6812 、WS2812 等不同信号,但是其控制逻辑基本是完全兼容的,本文所描述相关控制参数来源于 SK6812 ,原于带 IC 芯片的 RGB 可以通过串联来实现数据的传输,使得其在PCB布线时变得更为简单。



在此不难看出 RGB 灯的时序并不复杂,在此主要有以下几种驱动方式可供参考。
在 LLQ-82 这一款机械键盘中有80颗 RGB 灯,在此将灯分为了三组以节省总的刷新时间
在考虑余量的情况下进行配置



// 关闭DMA半传输中断
__HAL_DMA_DISABLE_IT(&hdma_spi1_tx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_tim4_ch1, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_tim4_ch2, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_tim4_ch3, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart1_tx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart3_tx, DMA_IT_HT);
#define BSP_WS2812_TERO 27
#define BSP_WS2812_ONE_ 68
#define BSP_WS2812_MAX_NUM 28 //每组定时器通道下的RGB灯数量
#define BSP_WS2812_R_OFFSET 1 //红色偏移量
#define BSP_WS2812_G_OFFSET 2 //绿色偏移量
#define BSP_WS2812_B_OFFSET 0 //蓝色偏移量
// TIM 中设置传输 bit 数据耗时 1.25us
#define BSP_WS2812_RGB_BITS_NUM 3*8
// 附加4个灯的时长,所有BIT设置为0码,进行复位逻辑 4*1.25*24 = 120us
#define BSP_WS2812_RGB_DATA_LEN (BSP_WS2812_MAX_NUM+4)
#define BSP_WS2812_RGB_DMA_NUM (BSP_WS2812_RGB_BITS_NUM*BSP_WS2812_RGB_DATA_LEN)
#define BSP_WS2812_KEYBOARD_NUM 80
typedef union
{
uint32_t color_u32;
uint8_t color_u8[4];
} bsp_color_struct;
// 颜色设置
bsp_color_struct keyboard_color[3][BSP_WS2812_MAX_NUM];
// pwm 占空比数值为uint16_t 类型,DMA传输时只能以半字输出,pixelBuffer应为uint16_t 类型
static uint16_t timCh1DmaBuffer[BSP_WS2812_RGB_DATA_LEN][3*8];
static uint16_t timCh2DmaBuffer[BSP_WS2812_RGB_DATA_LEN][3*8];
static uint16_t timCh3DmaBuffer[BSP_WS2812_RGB_DATA_LEN][3*8];
board_rgb[k].color.color_u8[BSP_WS2812_R_OFFSET] = (uint8_t)r;
board_rgb[k].color.color_u8[BSP_WS2812_G_OFFSET] = (uint8_t)g;
board_rgb[k].color.color_u8[BSP_WS2812_B_OFFSET] = (uint8_t)b;
// 更新DMA缓冲区数据内容
for(n=0; n< BSP_WS2812_MAX_NUM; n++)
{
for(i = 0; i < 3*8; ++i)
{
timCh1DmaBuffer[n][i] = ((keyboard_color[0][i].color_u32<< i) & 0x800000) ? BSP_WS2812_ONE_ : BSP_WS2812_TERO;
timCh2DmaBuffer[n][i] = ((keyboard_color[1][i].color_u32<< i) & 0x800000) ? BSP_WS2812_ONE_ : BSP_WS2812_TERO;
timCh3DmaBuffer[n][i] = ((keyboard_color[2][i].color_u32<< i) & 0x800000) ? BSP_WS2812_ONE_ : BSP_WS2812_TERO;
}
}
// 启动DMA传输
HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_1, (uint32_t *)timCh1DmaBuffer, BSP_WS2812_RGB_DMA_NUM);
HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_2, (uint32_t *)timCh2DmaBuffer, BSP_WS2812_RGB_DMA_NUM);
HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_3, (uint32_t *)timCh3DmaBuffer, BSP_WS2812_RGB_DMA_NUM);