STM32F 驱动WS2812B (3) SPI+DMA


一、基本思路

原理说明在《STM32F 驱动WS2812B (1) IO口》已经说明

STEP1:

实现逻辑1跟逻辑0的脉冲

STEP2:

将数据通过DMA发送到SPI外设,发送前面80us的低电平RESET信号以及每个灯珠的24个逻辑0或者1的脉冲。

二、实现

1.配置CUBEMX

芯片使用STM32F107VC
理清思路,上一期通过TIM方式驱动灯组的时候说过,对于灯带的逻辑1就是一个高电平800ns低电平450ns的脉冲,逻辑0就是一个高电平400ns低电平850ns的脉冲。脉冲周期为1250ns。所以理论上通过SPI的方式可以产生这两种脉冲就可以实现控制灯带。
一般来说SPI一次发送8位的数据,如果将8位中前6位置1后2位置0。即1111’1100b,这样的画发送一个脉冲就是发送0xFC这样一个8位数据。按照之前所说周期为1250ns的脉冲,8位SPI数据产生一个脉冲的话,每个bit的时间就是1250ns/8=156.25ns,所以时钟频率因该是1/156.25ns=6.4Mbit/s,所以通过调整时钟分频最终把时钟调整成6.4Mbit/s可以满足要求。所以如果这时候通过SPI发送0XFC,那么实际上将产生一个(6/8)*1250=937ns的高电平跟(2/8)*1250=312ns的低电平的脉冲。反之如果通过SPI发送0xC0,那么实际将产生一个312ns的高电平跟一个937ns的低电平的脉冲。这个数值跟之前提到的标准的数值有一点差异但是都是在范围之内的。所以对应逻辑1应该是通过SPI发送0xFC,逻辑0应该是通过SPI发送0xC0。

在这里插入图片描述
通过调整时钟将HCLK调整成52M,SPI处调整成4分频,可以看到spi的时钟位6.5M接近我们需要的6.4M.
在这里插入图片描述
DMA的选项中如下设置:
在这里插入图片描述

2.修改工程

点击生成代码,生成MDK的代码。每个灯珠需要24个脉冲对应RGB的24位,根据RGB的bit来产生代表逻辑0或者逻辑1的脉冲。在发送RGB数据之前需要一个reset信号,是大于50us的低电平。我们使用80us的低电平,之前通过cubemx配置SPI输出一个8位数据的时间是(1/6.5M)*8 =1.23us,所以这个80us的低电平需要使用65个0x00数据形成,所以先定义一个数组用来存放灯的数据,这边以1个灯为例:

	uint32_t spi_data[RESET_WORD+24*LED_NUM]={0};

这里的RESET_WORD定义成65,LED_NUM定义成1,即1个灯需要65+24个SPI数据。初始化为0,这样我们修改65个数据之后的数据不会影响前面的reset的数据。
假设需要亮蓝色,蓝色的RGB为0x0000FF,WS2812B的传输顺序是GRB,并且是先传输高bit,所以要先把G的颜色值放入数组,需要一个for循环,循环7次从高到低将bit对应的数据填入数组,如果这个bit是0对应的应该是0xc0,1对应的是0xfc:

#define CODE_0 0xC0
#define CODE_1 0xFC
uint32_t RGB_COLOR=0x0000ff;
for(j=15;j>=8;j--)//G	
	(((color>>j)&0x01)==1)?(spi_data[RESET_WORD+(i*24+(15-j))]= CODE_1):( spi_data [RESET_WORD+(i*24+(15-j))]= CODE_0);

因为第一个传输的是G数据,所以从RBG_COLOR的第15位bit15开始判断是否为1如果是1就用0xFC表示,一直判断到bit8。这里从RGB_COLOR的bit15到bit8应该存放到spi_data的对应灯的bit0-bit7。
之后是R传输,同理:

for(j=23;j>=16;j--)//R
	(((color>>j)&0x01)==1)?( spi_data[RESET_WORD+(i*24+(31-j))]= CODE_1):( spi_data[RESET_WORD+(i*24+(31-j))]= CODE_0);

最后是B传输,同理:

for(j=7;j>=0;j--)//B			
	(((color>>j)&0x01)==1)?(spi_data[RESET_WORD+(i*24+(23-j))]= CODE_1):(spi_data[RESET_WORD+(i*24+(23-j))]= CODE_0);

把这个数组填好之后就可以开启DMA传输了:

HAL_SPI_Transmit_DMA(&hspi3,spi_data,RESET_WORD+24*LED_NUM);

这里的传输数据的个数就是整个数组的个数。

二、验证

1.抓取0 code波形

将LED_NUM设置成1,调用点灯函数

ws2812b_show_dot(00x000000);

第一个参数是需要显示哪个点,由于是从0开始的,后面一个参数是颜色的RGB,都是0,所以应该发送24个逻辑0的脉冲,通过逻辑分析仪抓到如下:
在这里插入图片描述

2.抓取1 code波形

将LED_NUM设置成1,并且将全部的占空比的参数设置成80 也就是1 code的脉冲
在这里插入图片描述

灯带实验

一些想法

1:使用SPI生成脉冲并不是特别的好,其一因为占空比不能精准控制,其二时钟不好控制,不如PWM的方法方便,这里写这个方法只是抛砖引玉,希望能获得更多的思路。
2:在设置DMA传输的时候一定需要注意传输的方向是Memory To Peripheral

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

网布

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值