NUCLEO-F042K6驱动的彩色灯环(WS2812)
NUCLEO-F042K6是STMicroelectronics出品的Nucleo系列开发板之一,MCU为Cortex-M0核心的STM32F042K6。WS2812是常用的集成驱动电路的16M色LED。这里介绍使用STM32F042K6的SPI+DMA驱动WS2812的方法以及源代码分享。
效果图
接线图
- NUCLEO-F042K6的+5V <-> WS2812的VCC
- NUCLEO-F042K6的GND <-> WS2812的GND
- NUCLEO-F042K6的A6(STM32F042K6的PA7) <-> WS2812的IN
总共就3根线,是不是超级简单呢。
材料清单
- NUCLEO-F042K6一块
- WS2812灯环一个(24盏灯)
- 面包板一个
驱动原理
WS2812的时序非常特殊,见下图,没有办法使用标准的外设来驱动,得使用模拟实现。我采用的方案是SPI+DMA,用一个字节的SPI数据来表示WS2812的一位数据,SPI时钟频率调整到6.4M(800K * 8,WS2812的速率要求为800K,SPI每8个位长表示1位WS2812数据),SPI数据0x70(3个1,5个0,符合WS2812低电平的时序要求)表示WS2812的0,SPI数据0x7C(5个1,3个0,符合WS2812高电平的时序要求)表示WS2812的1。一个WS2812需要24位数据,首先将这24位RGB数据转换成24字节的SPI数据,然后使用DMA将24字节SPI数据发出去,这样就可以驱动WS2812了。我这个灯环有24盏LED,那么需要24*24=576字节的SPI缓存,用DMA可以一次性操作。这种方法比较耗内存,但是实现起来比较简单,输出时序一致性非常高。
核心代码
#define RS_PIXEL_MAX 24 // 这个灯环有24盏灯
static uint8_t ringBufferSPI[3 * 8 * RS_PIXEL_MAX]; // SPI缓存,每个灯24位,转换成SPI后每个灯需要24字节
void ringScriptPortOutput(const uint32_t pixels[])
{
uint32_t i, j, k;
uint32_t r, g, b;
uint32_t grb[3];
for(i = 0; i < RS_PIXEL_MAX; i++)
{
r = (pixels[i] >> 8) & 0xff;
g = (pixels[i] >> 16) & 0xff;
b = (pixels[i] >> 24) & 0xff;
// WS2812要求的排序是GRB
grb[0] = g;
grb[1] = r;
grb[2] = b;
for(j = 0; j < 3; j++)
{
for(k = 0; k < 8; k++)
{
if(grb[j] & (1 << (7 - k)))
{
ringBufferSPI[i * 3 * 8 + j * 8 + k] = 0x7C; // 1
}
else
{
ringBufferSPI[i * 3 * 8 + j * 8 + k] = 0x70; // 0
}
}
}
}
HAL_SPI_Transmit_DMA(&hspi1, &ringBufferSPI[0], sizeof(ringBufferSPI));
}
关于NUCLEO-F042K6
STMicroelectronics推出的Nucleo-32系列开发板,更多内容请访问:http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32f0-series/stm32f0x2/stm32f042k6.html
关于STM32F042K6
STMicroelectronics推出的STM32F0系列微控制器,更多内容请访问:http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32f0-series/stm32f0x2/stm32f042k6.html
关于Cortex-M0
ARM公司推出的32位微控制器核心,更多内容请访问:https://developer.arm.com/products/processors/cortex-m/cortex-m0
关于WS2812
Worldsem公司推出的集成驱动电路的16M色LED,数据手册及其它更多内容请访问:http://www.world-semi.com/details-108-4.html