电子达人2011

WS2812灯珠的STM32驱动方式

0
阅读(8223)

一.了解对手

深入了解自己的对手,才能有把握打胜仗,先让我们看一下WS2812灯珠的相关资料吧。

WS2812灯珠的STM32驱动方式

以上照片来自某厂家官网的截图,可以看到同系列的LED型号还是不少的。尽管都是常见的5050封装,却由四脚与六脚之分,设计的时候一定要注意,
我们这次使用的是WS2812B。下面是有关这可灯珠的介绍。 

1.WS2812B灯珠介绍

1.1 WS2812B灯珠的主要特点

WS2812灯珠的STM32驱动方式

 

这张图是对这狂灯珠的一些基本介绍,例如电源可以串联共用,每个灯珠都自带信号整形电路,上电掉电复位电路,每颗灯珠都可以实现RGB256级控制,扫描频率400KHz,任意两点间通信距离不低于3米,至少可以级联1024颗,看起来这款灯珠就是专为LED灯带设计的。


1.2 WS2812B灯珠的电气特性

WS2812灯珠的STM32驱动方式

 

上面是关于这款灯带的一下电气参数,供电电压可以使最常用的5V电源,限号传输延迟很小,不过参数里有一点没提及,这款芯片内置了恒流驱动电路,
不但能保证灯珠颜色的良好一致,而且连限流电阻都可以省了。


1.3 W2812B单总线驱动

WS2812灯珠的STM32驱动方式

 
这是关于W2812B单总线驱动的内容,控制器可以连续发送24位GRB控制信号,第一个灯珠截取前24位后,会显示到自己的LED上,并会将其余的数据进行整形后发送给第二颗灯珠,第二颗灯珠会截取第二组24位数据进行显示,并继续转发剩下的,知道最后一组数据被显示为止。


WS2812灯珠的STM32驱动方式

 
这是对魅族24位GRB数据中信号0与信号1的介绍,可以看到信号的周期为1.25us,与前面的800kbps的通信频率正好对应。信号0与1通过不同的占空比拉进行区分。

然而此处也报漏了一个问题,我们都知道,常用的STM32F1系列单片机,内核速率只有72MHz,对于主打高性能的STMF4系列也不过200MHz左右,也就是说,STM32F1的一个指令周期需要大约14ns,而正常情况下用HAL库控制单片机I/O翻转,至少需要30个指令周期,将近500ns才能实现一次高低电平变化,这就不用说还要形成严格的驱动信号,来控制LED显示颜色了,

其实不光HAL库不行,用最新的LL库也一样,最大也不超过5MHz,即使是直接用寄存器驱动I/O,也不过只能达到12MHz的翻转速度,就是F4系列直接用寄存器驱动,虽然可以超频到240MHz,让I/O翻转速率达到80MHz,然而并没有什么卵用,先不说稳定性咋样,就但是30多块钱一片的F4就吃消不起。

所以这里希望的大家如果用到WS2812系列的LED灯珠的话,希望大家能记住这条结论,免得在原理问题上浪费时间,STM32以及所有比他性能还低的单片机,用I/O翻转的方式,是很难驱动WS2812系列灯珠的,除非你是土豪直接上400M的F7,或者你的片子啥事都不干就驱动一串LED。

那难道STM32就没法驱动WS2812这种灯珠了吗,答案当然是能了。具体怎么驱动看后续内容,这里就不啰嗦了。


1.4 WS2812串联驱动电路
下面是WS2812的串联驱动电路,到了WS2813系列,连那颗电容都可以省掉不焊,是不是很简单呢

WS2812灯珠的STM32驱动方式

 


 WS2812B规格书.pdf 
 WS2813_ABC规格书-201705_17101023100425.pdf 
 WS2813E规格书(修改)-201705_17101023122789.pdf 
 WS2813-Mini规格书-201705_17101023111383.pdf
 WS2815规格书201705_17101023135673.pdf 

附上WS2812,WS2813,WS2815系列灯珠的手册


二.WS2812B驱动方式:DMA+PWM

WS2812B这种内部集成驱动芯片的RGB灯珠,并通过对驱动信号通信速率的详细计算,重点说明了STM32等一众单片机通过I/O翻转方式,控制这种灯珠的困难之处,接下来我们介绍一下,如何用最常见的方式来实现STM32对WS2812的控制。

常用STM32的都知道,STM32有8个定时器,其中TIM1跟TIM8是高级定时器,TIM2345是通用定时器,TIM67是基本定时器,当然还有个滴答定时器,
其中TIM123458都可以独立控制输出PWM波形,TIM1跟TIM8还可以输出两组互补PWM波形,这个功能在电机驱动中十分常用。

WS2812灯珠的STM32驱动方式

 
STM32定时器的PWM输出功能,是通过CNT与CCR寄存器的数值比,直接控制对应引脚输出高低电平的,也就是说只要我们愿意,可以用定时器直接输出36MHz的方波,当然波形可能就不那么好看了,不过用来驱动我们800kbps的WS2812,可以说是绰绰有余了,

WS2812灯珠的STM32驱动方式 

但是还有一个问题,通常情况下,我们的WS2812不会仅仅是一个或者几个LED串联,如果串联的LED较多的话,又会面临驱动信号的稳定性问题,毕竟我们要不断地改变定时器CCR的数值,来控制对应的I/O发送信号0还是信号1,而项目中我们的单片机又不可能只是用来控制LED,这时候我们的DMA功能就派上用场了。这也就是我们接下来要介绍的最容易想到的一种方法DMA+PWM。


2.1 DMA+PWM驱动方式介绍和实现方法

WS2812灯珠的STM32驱动方式

 

下面就是如何实现功能了,我们直接来看程序,声明一下我们是用原子的例程移植的。这里我们依然使用是STM32的HAL库,没办法,用熟了,顺手,而且各种以前的资源不能浪费了不是。

首先是时钟配置,这个没什么好说的,能跑多快就多快吧。就跟没人会希望自己媳妇丑一样。

WS2812灯珠的STM32驱动方式

 
(哦,不好意思这段是之前用寄存器写的,拿过来用了,见谅)

下面是今天的主角,DMA+PWM的配置方式。

WS2812灯珠的STM32驱动方式

 
先配置下GPIO吧,我们使用的是TIM2的CH1通道,对用的PWM输出引脚是PA0,注意要用复用输出功能哦。

下面是TIM2+CH1通道的配置,注意要配置成800KHz的频率,内核时钟72M / 90 = 800KHz,应该不难理解吧。然后是CH1输出通道的,配置成PWM1输出模式即可,注意电平的极性,不放心的可以用示波器抓抓波形。

WS2812灯珠的STM32驱动方式

 

然后就是我们的DMA的配置了,要设置好数组地址跟寄存器地址,然后就是DMA传输的字节长度,传输模式等等了

WS2812灯珠的STM32驱动方式

 

有关寄存器地址大家应该会找吧,不会的看下边,先从Datasheet找到我们的存储器映像图表,找到TIM寄存器租的起始地址。

WS2812灯珠的STM32驱动方式

 
可以看到TIM2寄存器组的起始地址是0x40000000,然后找到Reference Manual里,我们需要使用的TIM2_CCR1寄存器。

WS2812灯珠的STM32驱动方式

 
可以看到CCR1的偏移地址是0x34,所以我们需要的寄存器地址就是,0x40000000 + 0x34 = 0x40000034,不懂得童鞋回去好好啃啃计算机原理吧,

需要的外设资源配置好了,接下来就是万事俱备只欠东风了,下面就是我们有关LLED控制信号的处理函数了,look,不多解释。

WS2812灯珠的STM32驱动方式

 
上图最后面那个bug,是之前原子的程序就带着的,家里没有示波器目前没做验证,有空会控死抓抓波形看看。程序能用,也就没深究下去。

注意一下,到这可没玩呢,说好了要用DMA方式传输数据的,下面才是数据传输的主要内容呢。


WS2812灯珠的STM32驱动方式

定义了三个数组,主函数里写个三色循环呼吸灯看看效果。

WS2812灯珠的STM32驱动方式

 


WS2812灯珠的STM32驱动方式

 



附上相关程序
这个是用TIM2_CH1实现三色呼吸灯的。
 STM32F1_DMA_PWM_WS2813E_2018_05_06-Bingo.zip 
这个是用TIM2_CH123实现三路LED控制的。
 STM32F1_DMA_PWM_WS2813E_2018_05_06-TIM2_CH123.zip 
这个是用TIM2345_CH1实现四路LED控制的。
 STM32F1_DMA_PWM_WS2813E_2018_05_06-TIM2345.zip 


开启DMA数据传输,定时器开启之前,增加一条计数寄存器清空指令,防止寄存器非零造成第一次脉冲信号不准确。

同时在DMA数据传输完成后,应先关闭DMA通道,再关闭定时器,防止DMA传输完成,但PWM最后一次信号未发送完影响最后一个灯的显示。

WS2812灯珠的STM32驱动方式

 


WS2812灯珠的STM32驱动方式


三.WS2812B驱动方式:DMA+SPI

接上节我们介绍了一种STM32控制WS2812最常用,也是最用一想到的方法,就是用PWM来模式控制信号,并通过DMA传输数组数据,来保证信号传输的连续性。接下来来介绍一个不常用的方法——用SPI单总线控制

估计好多不熟悉STM32的小伙伴都没通过这种通信方式吧,其实我也不熟,只是知道这种模式从未用过,今天也算学习了。下面是STM32F1的Reference Manual里给的一段介绍,了解一下。


3.1 DMA+SPI驱动方法的原理

WS2812灯珠的STM32驱动方式

 

其实说白了,SPI不是有一个MOSI引脚吗,我们就是用MO功能,通过发送一个字节或半字的数据,来模拟我们的LED控制信号0或1,看下图。

WS2812灯珠的STM32驱动方式

 

是不是有恍然大悟的感觉,本来就很简单嘛。可仔细看来这是不是有点得不偿失啊,用16位数据去模拟1位数据,是不是感觉太浪费资源了!!!
还在我们的SPI通信速率足够高,完全可以应付的来。


3.2 DMA+SPI驱动方式的程序代码
时钟就不用说了,还是能跑多快就跑多块咯,重点来看看我们SPI的单总线模式是如何配置的,当然第一个要配置的自然是我们的信号输出引脚,
SIM32F1系列SPI1的MOSI引脚是PA7。

WS2812灯珠的STM32驱动方式

 

注意要配置成复用输出模式,最大驱动频率50MHz,接下来就是我们的主角SPI1的配置了。

WS2812灯珠的STM32驱动方式

 

前两句就可以看到,我们将SPI配置成了主模式下的单线发送模式,采用了16微数据帧格式,时钟引脚悬空未用,片选引脚未用。然后就是我们的DMA数据传输的配置,通过我们的Reference Manual可以查到SPI的TX使用的DMA1_CH3通道。

WS2812灯珠的STM32驱动方式

 

接下来就是我们有关LED通信数据的处理了,这才是最有意思的部分。首先是RGB数据的分解,在C语言里并没有定义24位主句格式,只有32位可用,所以我们将RGB数组定义32位格式,如下是我定义的一个数组。

WS2812灯珠的STM32驱动方式

 

然后我们要将每个数组元素中的RGB三色分解出来,函数如下注意一下数据的先后顺序,我们定义的是RGB,而发送需要的是GRB。

WS2812灯珠的STM32驱动方式

 

然后我们要将分解出来的RGB信号的每一位进行解析,转化成我们即将使用SPI发送出去的16位帧信号,注意,此处帧的格式是根据LED所需的信号0和1定义好的。

WS2812灯珠的STM32驱动方式

 

然后我们要将转化出来的16位帧数据一次存放打我们给SPI准备的数组中,也就是我们通过DMA功能给SPI的TX引脚传送数据的数组,注意对应哦。

WS2812灯珠的STM32驱动方式

 
看看是不是跟DMA初始化的时候配置的一样呢。

WS2812灯珠的STM32驱动方式

 

接下来就是如何把已经转化好的16位帧数据发送出去了。具体函数如下,记得要使用DMA功能传送数据哦。

WS2812灯珠的STM32驱动方式

我们在主函数中,通过数据发送函数,将RGB信号传送到LED,同时,我们简单通过一个循环移位函数,实现了LED的三色流水灯。

WS2812灯珠的STM32驱动方式 

WS2812灯珠的STM32驱动方式

 


附上程序
 STM32F1_DMA_SPI_16B_WS2813E_2018_05_06-Bingo.zip 

了解更多