前言
WS2812的驱动方式目前大致为gpio,spi,time+pwm
gpio会占用cpu,spi或spi+dma需要对spi频率进行配置,time+pwm+dma用起来相对复杂些。
本次用的是gpio通过 ` __NOP() ` 延时来模拟ws2812的时序。
为啥不用spi或pwm是因为spi无法配置为7MHZ或14MHZ stm32c031的时钟48mhz可以/2/4/8/16/32 这几种分频。实际是驱动不了,显示乱的。pwm的话本人实力有限,也不好用丢数据
一、CUBEMX配置
二、WS2812驱动时序
通过示波器将 __NOP();的用时记录然后逐次增加
一个nop大概占用30-40ns
0码为400+850ns
1码为850+400ns
1.WS2812.C
代码如下(示例):
- #include "ws2812.h"
- uint8_t ws_data[WS_ARRAY_SIZE]={0};
- void WS_0(void)
- {
- LL_GPIO_SetOutputPin(LED1_GPIO_Port, LED1_Pin);
- __NOP();__NOP();__NOP();__NOP();__NOP();
- __NOP();__NOP();__NOP();__NOP();__NOP();
- __NOP();__NOP();__NOP();
- LL_GPIO_ResetOutputPin(LED1_GPIO_Port, LED1_Pin);
- __NOP();__NOP();__NOP();__NOP();__NOP();
- __NOP();__NOP();__NOP();__NOP();__NOP();
- __NOP();__NOP();__NOP();__NOP();__NOP();
- __NOP();__NOP();__NOP();__NOP();__NOP();
- __NOP();
- }
- void WS_1(void)
- {
- LL_GPIO_SetOutputPin(LED1_GPIO_Port, LED1_Pin);
- __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();
- LL_GPIO_ResetOutputPin(LED1_GPIO_Port, LED1_Pin);
- __NOP();__NOP();__NOP();__NOP();__NOP();
- __NOP();__NOP();__NOP();__NOP();__NOP();
- __NOP();__NOP();__NOP();
- }
- void WS_RST(void)
- {
- uint16_t i=0;
- LL_GPIO_ResetOutputPin(LED1_GPIO_Port, LED1_Pin);
- for(i=0;i<860;i++)
- {
- __NOP();
- }
- }
- void ws2812_set_num(uint16_t num ,uint8_t r,uint8_t g,uint8_t b)
- {
- ws_data[(num-1)*3]=g;
- ws_data[(num-1)*3+1]=r;
- ws_data[(num-1)*3+2]=b;
- }
- void ws2812_rgb_all(u8 ws_count,u8 ws_r,u8 ws_g,u8 ws_b)
- {
- static uint8_t rgb_wsi;
- for(rgb_wsi=1;rgb_wsi<=ws_count;rgb_wsi++)
- {
- ws_data[(rgb_wsi-1)*3]=ws_g;
- ws_data[(rgb_wsi-1)*3+1]=ws_r;
- ws_data[(rgb_wsi-1)*3+2]=ws_b;
- }
- //ws2812_refresh(ws_count);
- }
- void ws2812_refresh(u8 ws_count)
- {
- uint8_t ws_ri=0;
- for(;ws_ri<ws_count*3;ws_ri++)
- {
- if((ws_data[ws_ri]&0x80)==0) WS_0(); else WS_1();
- if((ws_data[ws_ri]&0x40)==0) WS_0(); else WS_1();
- if((ws_data[ws_ri]&0x20)==0) WS_0(); else WS_1();
- if((ws_data[ws_ri]&0x10)==0) WS_0(); else WS_1();
- if((ws_data[ws_ri]&0x08)==0) WS_0(); else WS_1();
- if((ws_data[ws_ri]&0x04)==0) WS_0(); else WS_1();
- if((ws_data[ws_ri]&0x02)==0) WS_0(); else WS_1();
- if((ws_data[ws_ri]&0x01)==0) WS_0(); else WS_1();
- }
- //延时一段时间
- WS_RST();
- }
复制代码
2.WS2812.H
代码如下(示例):
- #ifndef _WS2812_H_
- #define _WS2812_H_
- #include "gpio.h"
- typedef unsigned char u8;
- #define WS_ARRAY_SIZE 64
- void ws2812_refresh(u8 ws_count);//显示
- void ws2812_rgb_all(u8 ws_count,u8 ws_r,u8 ws_g,u8 ws_b);//所有LED颜色配置
- void ws2812_set_num(uint16_t num ,uint8_t r,uint8_t g,uint8_t b);//配置单个显示
- #endif
复制代码
3.显示- while (1)
- {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- for(i = 1; i < 29; i++)//显示28个
- {
- ws2812_set_num(i, 1, 0, 0);//红色
- }
- ws2812_refresh(28);//显示全部数据
- ws2812_rgb_all(28, 0, 0, 0);//清除数据
- HAL_Delay(800);
- for(i = 1; i < 29; i++)//显示28个
- {
- ws2812_set_num(i, 0, 1, 0);//绿色
- }
- ws2812_refresh(28);
- ws2812_rgb_all(28, 0, 0, 0);
- HAL_Delay(800);
- for(i = 1; i < 29; i++)//显示28个
- {
- ws2812_set_num(i, 0, 0, 1);//蓝色
- }
- ws2812_refresh(28);
- ws2812_rgb_all(28, 0, 0, 0);
- HAL_Delay(800);
- }
复制代码
实验现象
|