6552918 发表于 2022-1-23 17:04

【N32G435x】用PWM+DMA驱动WS281X RGB彩灯的产品级源码分享

本帖最后由 6552918 于 2022-3-4 22:43 编辑

#申请原创#

@21小跑堂

这次的N32优质帖征集活动不错,可以更好的体验国民技术的通用MCU的特点,能够让大家更深入的体验国民的通用MCU,也能让大家看到更多的干货,在此我来抛个砖!!!这次分享的是使用PWM+DMA驱动WS2812B(兼容WS2811)的方式和源码,源码内支持查询驱动方式和中断驱动方式,是一款可以产品级应用的方式,在此源码基础上可以根据自己的需求修改即可。下面我们先看看RGB彩灯WS2812B和WS2811的简单介绍WS2812B和WS2811在供电;驱动数量;24bit数据结构和0 1码高低电平定义上有差别,但大致是兼容的,在代码里我通过宏定义进行了兼容。接下来我介绍一下具体源码源码由5个文件组成delay.c               ->官方BSP内的延时函数支持微妙 毫秒延时delay.h            ->官方BSP内的延时函数头文件n32g43x_it.c          ->中断函数文件WS281X.c            ->WS2812B和WS2811的驱动文件WS281X.h             ->WS2812B和WS2811的驱动文件头文件
delay.c和delay.h是国民官方BSP内的延时函数文件,文件内实现的us和ms延时函数,可以方便的使用,在使用相关延时函数前需要调用void delay_init(void)对系统时钟进行初始化。我重点介绍一下n32g43x_it.c ;WS281X.c ;WS281X.h这3个文件
WS281X.h内定义了和灯珠驱动的相关宏定义//#define WS2811                      ->   芯片为WS2811开启此宏    两宏互斥#define WS2812B                     ->   芯片为WS2812B开启此宏两宏互斥#define PWM_DMA_IRQ            ->   使用PWM DMA中断开启此宏
#define   PIXEL_NUM14      //灯带1灯数(组数)#define   PIXEL_NUM23      //灯带2灯数(组数)#define   PIXEL_NUM32      //灯带3灯数(组数)#define   PIXEL_NUM41      //灯带4灯数(组数)#define   PIXEL_NUM51         //灯带5灯数(组数)#define   PIXEL_NUM    (PIXEL_NUM1+PIXEL_NUM2+PIXEL_NUM3+PIXEL_NUM4+PIXEL_NUM5)   定义了驱动的灯数(组数);
定义了WS2811和WS2812B的0 1码PWM占空比定义,这里WS_HIGH和WS_LOW的值会再后面初始化函数时介绍。
接下来我来介绍一下WS281X.c这个文件函数void WS281x_Init(void) 对PWM输出用到的GPIO进行了初始化;对PWM输出相关的定时器进行了初始化,对PWM输出相关的DMA进行了初始化; 对PWM输出相关的中断进行了初始化;在相关外设初始化前要打开相关外设的时钟。PWM输出使用GPIOA的6脚(TIM3的通道1),开启复用模式
这里DMA使用的是通道2,在开启DMA模式时通过宏定义PWM_DMA_IRQ开启了DMA的NVIC相关操作。这里重点介绍一下N32G435的DMA,尽管通道不多,但真的十分灵活,所有请求都可以映射到任意8个通道上,这让使用变得非常自由。DMA_RequestRemap(DMA_REMAP_TIM3_UP, DMA, DMA_CH2, ENABLE);这个函数实现了请求与通道的映射。
DMA_InitStructure.BufSize      = 0;    //传输次数-》为0不发送当DMA传输次数为0时,即使有相关请求也不会进行传输操作!!! 在这里使用更新事件触发DMA请求。在定时器相关初始化过程中,涉及到PWM的周期和占空比问题,在用户手册中相关描述如下:在函数中相关参数为TIM_TimeBaseInitStruct.Period= 68 - 1;/* 54M / 68 = 794.12K (小于800K) */(TIM3的时钟总线最大频率为54M,而WS2812B的数据发送速度最大为800K,所以将TIM3_AR寄存器值设定为68(794.12K约等于1.26us),以便将输出频率控制在最接近800K的速率以内。)TIM_OCInitStruct.Pulse= 0;(对应的寄存器为TIM3_CDDATx的值,此值由DMA进行传输赋值,以便控制占空比。)在开启DMA模式时通过宏定义PWM_DMA_IRQ开启了TIM3的NVIC相关操作。
外设初始化完成后,还要对灯珠进行初始化,就行将所要控制的灯珠,都设置为熄灭状态。void WS281x_CloseAll(void) 函数将显示buffer全部填充为“0”(0码对应的占空比数值),再通过WS281x_Show();控制PWM输出开始。
WS281x_Show()内,先检查DMA传输次数是否为0,不为0说明传输未完成,需要等待完成,再将TIM3_CDDATx的值清0,然后在关闭DMA通道情况下对传输次数赋值,然后开启通道,最后使能TIM3就开始PWM的输出了。在使用查询方式输出情况下,使用PWM_DMA_IRQ宏控制的部分是查询传输是否完成的相关操作。这部分涉及到2块内容,一块是DMA传输是否完成,领一部分是PWM输出是否完成,因为DMA传输完成是先于PWM输出完成的,为保证WS2812B的控制信号准确,要在PWM传输完成后马上关闭PWM输出才行。本文件的其他函数是和显示效果相关的,可以根据自己的需求选择,再此就不详细介绍了。
当使用PWM+DMA中断传输方式,就涉及到n32g43x_it.c文件的内容。由于开启PWM+DMA中断方式后,DMA传输完中断先产生,会先进void DMA_Channel2_IRQHandler(void)函数,在函数内确认是传输完中断后进入相关操作,先清除传输完成标志,关闭通道,然后再开启TIM的更新中断,在PWM完成最后一个周期的输出后进入TIM3的更新中断,再更新中断内要先清除TIM3_CDDAT1为0(以便保证输出为低电平,在下图中显示,如果TIM3_CDDAT1不为0,有可能会使输出为高电平,这样是不满足WS2812B的时序要求的),然后清除更新中断标志,关闭TIM3,禁用TIM3的更新中断。至此,在使用PWM+DMA驱动WS2812B(兼容WS2811)的整个过程就介绍完成,相关源码一并提供,希望对有需求的朋友有所帮助。源码在附件中,欢迎大家下载。https://www.bilibili.com/video/BV1x34y1q7tX/

yljon 发表于 2022-1-24 10:36

不错啊

两只袜子 发表于 2022-1-24 11:29

有源码的东西真的是好东西

kyzhd 发表于 2022-1-26 09:09

楼主的灯条好好看哟,学习了,感谢楼主。

duo点 发表于 2022-2-13 10:35

感谢楼主分享

chenjun89 发表于 2022-2-14 18:35

不错,感谢分享。

alvpeg 发表于 2022-3-3 22:09

WS281X 使用定时器可以吗

i1mcu 发表于 2022-3-3 22:26

N32G435 用的pwm可行?

6552918 发表于 2022-3-3 22:35

alvpeg 发表于 2022-3-3 22:09
WS281X 使用定时器可以吗

定时器不就是用PWM吗?

6552918 发表于 2022-3-3 22:35

i1mcu 发表于 2022-3-3 22:26
N32G435 用的pwm可行?

必须可以,我就是用435调试的

nomomy 发表于 2022-3-3 22:42

如何用dma修改pwm呢

vivilyly 发表于 2022-3-3 23:04

以前用过延时操作。

earlmax 发表于 2022-3-3 23:31

最多支持多少个WS281X RGB彩灯

robincotton 发表于 2022-3-4 20:00

不是可以spi+dma吗

单片小菜 发表于 2022-3-7 10:37

感谢楼主的分享,不错的一个案例哦。

七毛钱 发表于 2022-3-11 10:05

这个值得学习的案例

起点116 发表于 2022-3-11 22:09

感谢分享

primojones 发表于 2022-3-16 20:47

最大支持多少的控制

htmlme 发表于 2022-3-16 21:15

WS281X RGB彩灯效果怎么样

showgu 发表于 2022-3-16 21:40

我倾向于用SPI 引脚方式。
页: [1] 2 3 4
查看完整版本: 【N32G435x】用PWM+DMA驱动WS281X RGB彩灯的产品级源码分享