资讯详情

SPI+DMA驱动和控制WS2812彩色RGB灯

SPI DMA驱动和控制WS2812彩色RGB灯

SPI DMA驱动WS2812

官方灯条是比赛的能量机制SK6812灯珠,每米144个灯珠,但真的很贵(

最后还是选了WS2811灯珠。

恶心的是,WS在2811逻辑0和1表达方式中,网上很多图片都是错误的,必须以数据手册为准… 如果逻辑0和逻辑1的发送顺序错误,则整个灯条的颜色混乱,甚至根本不亮

ws28121

先放一段QA吧

Q1: 这种信号线输出控制的逻辑电平一般需要5V以上,需要3.3V升5V吗

A1: STM虽然32只能输出3.3V,但是控WS2811是可以的。.3V升到5V,三极管或是MOS管道信号上升时间相对较长,无法跟上控制信号的变化,导致信号几乎无法输出

Q2: 直接用IO口翻可以控制吗?

A2: 不太好。用封装库函数翻转。IO执行速度难以满足数百ns到1us虽然寄存器可以直接操作,但即使对示波器进行一点测试NOP空指令的数量只是时间序列相似。随着灯条长度的延长和信号发送时间的推移,总会出现逻辑0和1的误解

Q3: FreeRTOS 是否会影响控制时序?

A3: 任务优先级稍高,使用SPI DMA不会影响

Q4: 一条总线能控制多少灯?

A4: 测试一条SPI DMA控制1920个灯珠仍然可以正常控制,更多的灯珠没有设备也没有测量。只要顺序是正确的,理论上就可以控制无限的

控制方式

单总线,通过总线上高低电平时间长短的不同来区分0和1。

WS2811工作频率8000KHz,如果将SPI频率设置为6.4MHz,正好是灯条IC芯片的8倍,所以每个字节(8位)对应一个逻辑位,即11110000代表逻辑1,11000000代表逻辑0

但也有150个协议ns的兼容性。比如SPI设置为5.25MBits/s(Mbps)(84MHz时钟线16分频据线8Bits),一Bit发送时间为1/5.25=190ns一个字节约1.52us。所以可以通过SPI的MOSI输出信号线发送一个字节Byte(8Bits)的数据模拟 WS2812的一个位。所以发送一个uint8字节0xF8(1111000)x190=950ns在580ns-1us范围之间代表逻辑1;0x80(1万)高电平时间为190ns接近220ns-380ns范围,代表逻辑0

CubeMX 配置

  • 开启 SPI因为只用了MOSI输出信号线,所以模式选择Transmit Only Master 只发送主模式 就可以。

    • Data Size 设置为 8 Bits。原因是上述控制方法

    • CPHA 设置为 2 Edge。跳变沿为1时,MOSI空闲电平为高电平。当跳变沿设置为2时,上次发送的最终电平将继续,因为发送数据的末尾是低电平,因此 WS2812 不会误判

    • CPOL 设置为 High。总线空闲时SCK时钟状态为高电平

  • 开启 DMA。Mode设置为Normal,由程序触发DMA发送即可。

程序

#define LED_NUM 64 // LED灯珠个数  // 模拟bit码: 0x80为逻辑0, 0xF8为逻辑1 const uint8_t code[]={ 
        0x80,0xF8};  typedef struct { 
           uint8_t R;   uint8_t G;   uint8_t B; }RGBColor_TypeDef; //颜色结构体  // 常见的颜色定义 const RGBColor_TypeDef RED = { 
        255, 0, 0}; const RGBColor_TypeDef BLUE = { 
        0, 0, 255};  // 灯颜色缓存 RGBColor_TypeDef RGB_Data[LED_NUM] = { 
        0};  /** * @brief 设置灯带颜色发送缓存 * @param[in] ID 颜色 */
void Set_LEDColor(uint16_t LedId, RGBColor_TypeDef Color)
{ 
        
    RGB_Data[LedId].G = Color.G;
    RGB_Data[LedId].R = Color.R;
    RGB_Data[LedId].B = Color.B;
}

/** * @brief SPI发送控制ws2812 * @param[in] 待发送缓存 */
static void SPI_Send_WS2812(uint8_t *SPI_RGB_BUFFER)
{ 
        
    // 判断上次DMA有没有传输完成
    while(HAL_DMA_GetState(&hdma_spi1_tx) != HAL_DMA_STATE_READY);
    // 发送一个24bit的RGB数据
    HAL_SPI_Transmit_DMA(&hspi1, SPI_RGB_BUFFER, 24);
}

/** * @brief 控制WS2812 * @param[in] 待发送缓存 */
void RGB_Reflash(void)
{ 
        
	static uint8_t RGB_BUFFER[24]={ 
        0};
	uint8_t dat_b,dat_r,dat_g;
	// 将数组颜色转化为24个要发送的字节数据
    for (uint16_t i = 0; i < LED_NUM; i++) { 
        
        dat_g = RGB_DAT[i].G;
        dat_r = RGB_DAT[i].R;
        dat_b = RGB_DAT[i].B;
        for (uint16_t j = 0; j < 8; j++) { 
        
            RGB_BUFFER[7-j] =code[dat_g & 0x01];
            RGB_BUFFER[15-j]=code[dat_r & 0x01];
            RGB_BUFFER[23-j]=code[dat_b & 0x01];
            dat_g >>=1;
            dat_r >>=1;
            dat_b >>=1;
        }
        SPI_Send_WS2812(RGB_BUFFER);
	}
}

标签: 三极管j112g三极管2sk2654三极管j3v

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台