通常驱动W2812的方法是参照它的时序要求,以GPIO口来模拟它的时序进行驱动,
但对于主频较低的MCU来说则较难达到它的时序要求。
对于AT32F425来说,还可以利用它的SPI和DMA来驱动WS2812灯带,并按时序的要求将主频设为80MHz。
在该驱动方式下,其显示效果如图1和图2所示。
在实现WS2812的驱动过程中,要涉及一个变换处理函数,它需要将8位的二进制色彩值转换为一个4字节的32位二进制数,其中某位为“1”时,就转换为0xe(高电平占优);为“0”,则转换为0x8(低电平占优)。
尽管是使用SPI来驱动WS2812,但WS2812只有一个数据引脚,故其该引脚的配置函数为:
static void gpio_config(void)
{
gpio_init_type gpio_initstructure;
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE15, GPIO_MUX_0);
gpio_default_para_init(&gpio_initstructure);
gpio_initstructure.gpio_pull = GPIO_PULL_DOWN;
gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
gpio_initstructure.gpio_pins = GPIO_PINS_15;
gpio_init(GPIOB, &gpio_initstructure);
}
也就是说将WS2812与PB15相连接就可以了,实现演示效果的主程序为:
int main(void)
{
int8_t mod;
system_clock_config();
at32_board_init();
delay_us(100);
gpio_config();
spi_config();
int8_t dir[WS2812_NUM][3] = {0};
for(uint32_t i = 0; i < sizeof(WS2812_rgb_buf); i++)
{
for(uint32_t j = 0; j < 3; j++)
{
WS2812_rgb_buf[j] = i * (j + 2);
dir[j] = j + 2;
}
}
while(1)
{
dma_channel_enable(DMA1_CHANNEL5, TRUE);
while(!dma_flag_get(DMA1_FDT5_FLAG));
dma_flag_clear(DMA1_FDT5_FLAG);
dma_channel_enable(DMA1_CHANNEL5, FALSE);
DMA1_CHANNEL5->dtcnt = sizeof(WS2812_bit_buf);
DMA1_CHANNEL5->maddr = (uint32_t)WS2812_bit_buf;
delay_ms(10);
uint8_t *buf = (uint8_t *)WS2812_rgb_buf;
for(uint32_t i = 0; i < sizeof(WS2812_rgb_buf); i++)
{
for(uint32_t j = 0; j < 3; j++)
{
*buf += dir[j];
if((*buf >= 255)||(*buf == 0))
{
dir[j] = -dir[j];
}
buf++;
}
}
rgb_to_buf(&WS2812_rgb_buf[0][0],&WS2812_bit_buf[0][0]);
}
}
本帖最后由 jinglixixi 于 2022-4-17 21:42 编辑
WS2812的驱动LED灯,很经典呀,好似这个可以做动态显示图像的,是这个吗?
引用: lugl4313820 发表于 2022-4-17 11:52 WS2812的驱动LED灯,很经典呀,好似这个可以做动态显示图像的,是这个吗?
没错,点位数多的效果比较好,否则显示的内容受限。