一、前言
目的:对于使用STM32驱动WS2812-RGB灯,已经有很多大佬进行了分享,同时写得很好!但是对于GD32的调试WS2812确实偏少,刚好最近的项目有用到,顺便记录一下踩过的坑。开源不易,谢谢大家!
感谢:特别感谢三位大佬的的博文贡献;
1.GD32F470通过DMA输出PWM_gd32 pwm dma-CSDN博客
2.基于GD32的定时器不完全详解--定时、级联_gd32 定时器-CSDN博客
3.WS2812B彩灯 STM32HAL库开发:PWM+DMA(stm32f103c8t6)_ws2812编程实例-CSDN博客
硬件:GD32E230F6V6(72M主频)、WS2812B(RGB灯)
引脚:PA6-----复用功能_定时器2通道0
踩坑记录附到文章最后
二、WS2812B点亮原理
在DI脚通过MCU的引脚产生特定的脉冲,形成各种各样的炫彩灯光。
根据描述得知一次数据的传输的时间大概为1.25us,转换过来即800K HZ的频率,同时通过0码和1码的高电平的持续时间不同,那么我们就可以采用PWM产生对应的占空比来表示0码、1码。
通过级联的电路连接,我们就可以实现用1个MCU引脚来控制多个RGB灯。注意:每个RGB灯每次只会接收24bit的数据,接收到后就会锁存,下一个RGB灯则接收到的是第二组的24bit数据,同时接收的数据是以G、R、B的顺序。
三、话不多说,上代码
头文件:ws2812.h
#ifndef _WS2812_H_
#define _WS2812_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "gd32e230.h"
#include "systick.h"
#define WS2812_PIN_PORT GPIOA
#define WS2812_PIN_NUM GPIO_PIN_6
/*建立一个定义单个LED三原色值大小的结构体*/
typedef struct
{
uint8_t R;
uint8_t G;
uint8_t B;
}RGB_Color_TypeDef;
typedef enum{
RED_COLOR = 0,
GREEN_COLOR,
BLUE_COLOR,
SKY_COLOR,
MAGENTA_COLOR,
YELLOW_COLOR,
OEANGE_COLOR,
BLACK_COLOR,
WHITE_COLOR
}rgb_color;
void ws2812_init(void);//初始化
void ws2812_display_color(uint16_t color);//显示颜色
void ws2812_display_blink_light(uint16_t blink_num, uint16_t color,uint32_t time_out);//闪烁灯模式设置
void ws2812_display_breathe_light(uint16_t color,uint32_t time_out);//呼吸灯模式设置
#ifdef __cplusplus
}
#endif
#endif
C文件:ws2812.c
这里没有采用dma中断的形式,轮询就已够用;
通过控制PWM占空比发送0码和1码,额定周期为1.25us,则频率为800Khz
0码PWM占空比:(0码高电平时间)/(周期)---> 0.4 / 1.25 = 0.32
用占空比乘以定时器重装值加一就是0码的CCR值(代表PWM高电平计数个数)--->0.32 * (89+1) = 28.8(取28,实测不可以高于28,但23到28都可以)
1码PWM占空比:同理计算:(1码高电平时间)/ (周期)---> 0.8 / 1.25 = 0.64(占空比)*(重置值+1)= CCR --