通宵敲代码 发表于 2018-5-6 22:48

WS2812灯珠的STM32驱动方式(二)——DMA+PWM

<div class='showpostmsg'> 本帖最后由 通宵敲代码 于 2018-5-6 23:34 编辑

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

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

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


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




</div><script>                                var loginstr = '<div class="locked">查看精华帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                               
                                if(parseInt(discuz_uid)==0){
                                                                                        (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                }
</script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

通宵敲代码 发表于 2018-5-6 22:49

本帖最后由 通宵敲代码 于 2018-5-6 23:28 编辑


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

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

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

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

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

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


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


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

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

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

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

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

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


通宵敲代码 发表于 2018-5-6 22:49

本帖最后由 通宵敲代码 于 2018-5-6 23:34 编辑


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




http://v.youku.com/v_show/id_XMzU4ODE1NTYxNg==.html?spm=a2h3j.8428770.3416059.1

附上相关程序
这个是用TIM2_CH1实现三色呼吸灯的。

这个是用TIM2_CH123实现三路LED控制的。

这个是用TIM2345_CH1实现四路LED控制的。


















naga568 发表于 2018-5-7 07:51

通宵敲代码 发表于 2018-5-6 22:49
上面介绍完原理,下面就是如何实现功能了,
我们直接来看程序,声明一下我们是用原子的例程移植的。
这 ...

{:1_103:}謝謝分享。

bioger 发表于 2018-5-7 08:31

通宵敲代码 发表于 2018-5-6 22:49
定义了三个数组,主函数里写个三色循环呼吸灯看看效果。






附上相关程序
这个是用TIM2_CH1实 ...

谢谢分享

通宵敲代码 发表于 2018-5-7 11:28



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

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








eleven@ 发表于 2018-5-19 21:33

楼主,为什么我的PA0没有输出呢?用万用表也测不出来,我按照你的代码,原封不动,可就是没有输出,还请大佬指导一波

eleven@ 发表于 2018-5-19 21:37

还有,LED_Init();这个来初始化LED貌似没什么用吧,程序里好像没用上吧,输出是PA0吧?:titter:

eleven@ 发表于 2018-5-20 12:33

我仿真出来PA0一直是低电平

通宵敲代码 发表于 2018-5-25 17:12

eleven@ 发表于 2018-5-19 21:37
还有,LED_Init();这个来初始化LED貌似没什么用吧,程序里好像没用上吧,输出是PA0吧?

嗯,这个确实没用,以前的函数留下的。
输出引脚确实是PA0,程序都是验证过的,你好好检查一下硬件。

DSCX05 发表于 2018-7-20 10:01

楼主你的硬件不是级联?程序上看起来是每一个都用一个DMA的通道?

mochou678 发表于 2018-7-29 16:08

优酷视频打不开啊,能直接发个图片我看下或者其他视频,看下显示效果,不知道我这边显示的效果对不对。

通宵敲代码 发表于 2018-7-30 08:58

DSCX05 发表于 2018-7-20 10:01
楼主你的硬件不是级联?程序上看起来是每一个都用一个DMA的通道?

做的四路独立控制,
需要级联你直接延长灯带就行了,
我试过288颗灯级联的,毫无压力,
官方给的数据可以级联1000颗灯

通宵敲代码 发表于 2018-7-30 09:01

mochou678 发表于 2018-7-29 16:08
优酷视频打不开啊,能直接发个图片我看下或者其他视频,看下显示效果,不知道我这边显示的效果对不对。

百度一搜很多这个灯珠的视频,
我这边公司的网络也上不了优酷,
我记不清这个是呼吸灯还是流水灯了,
你看一下,只要颜色渐变流畅就没问题。

mk0007 发表于 2018-7-30 09:09

{:1_103:}{:1_103:}{:1_103:}{:1_103:}{:1_103:}{:1_103:}

soqy 发表于 2018-8-24 16:10

怎么输出来的脉冲没有24个?

lvfangfang000 发表于 2018-10-30 15:57

为什么使用TIM1_CH1定时器就不行呢,灯可以点亮,颜色不受控

F思念 发表于 2018-11-1 09:43

lvfangfang000 发表于 2018-10-30 15:57
为什么使用TIM1_CH1定时器就不行呢,灯可以点亮,颜色不受控

你解决问题了吗?我也像你一样,现在不知道怎么搞

vickyinhere 发表于 2018-12-25 17:25

有一点我不明白的是,为什么提到用hal库,但是大体上看起来还是标准库的代码风格?新手,求指教:time:

vickyinhere 发表于 2018-12-25 18:08

soqy 发表于 2018-8-24 16:10
怎么输出来的脉冲没有24个?

我也是这样,只有8个,请问你解决了吗,还是说要使用三路LED的代码
页: [1] 2 3 4
查看完整版本: WS2812灯珠的STM32驱动方式(二)——DMA+PWM