STM32F103使用TIM+DMA驱动WS2812灯带

STM32F103使用TIM+DMA驱动WS2812灯带
2025年11月02日 21:52 电子产品世界

ws2812做为RGB灯,在很多场合都是非常有用的,我准备使用STM32H755的M4内核驱动时,遇到了一些问题,因此先用STM32F103来验证一下,找到库存的STM32103的开发板,来实现驱动,特记录如下:

1.使用STM32CubeMX 新建基于STM32F103C8Tx的工程:

2.打开外部时钟,因为内部时钟最高只能跑到64MHz。

3.在时钟配置界面,配置72MHz的总线时钟。

从上面我们得到Timer的时钟总线为72MHz。

4.打开TIM1的配置界面配置如下:

这里我们需要将GPIO的输出速度选择为高速模式。

5.配置pwm

在定时器配置中,我们根据WS2812 的最大传输速率800kbps,设置定时器不分频和计数周期为89+1,这样下来波形的频率为72 M /(89+1) = 800 K,并且一个波形的周期为1 / 800 = 1.25 us

6.配置DMA

我们打开DMA的界面,添加一个DMA,选择方向为从内存到外设,内存为递增,数据宽度为半字节,即16 bit。

到此界面配置结束,生成工程后,使用mdk 打开工程。

【代码添加】

1.新建RGB.c 添加代码如下:

view plaincopy to clipboardprint?

1.#include “RGB.h”

2.#include “main.h”

3.#include “tim.h”

4.

5.uint16_t RGB_buffur[Reste_Data + WS2812_Data_Len] = { 0 }; //数据缓存数组

6.

7.void WS2812_Display_1(uint32_t Color, uint16_t num)

8.{

9.

10.//指针偏移:需要跳过复位信号的N 个0

11.uint16_t* p = (RGB_buffur + Reste_Data) +(num * Led_Data_Len);

12.

13.for (uint8_t i = 0; i < 8; ++i)

14.p[i+8]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);

15.for (uint8_t i = 8; i < 16; ++i)

16.p[i-8]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);

17.for (uint8_t i = 16; i < 24; ++i)

18.p[i]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);

19.

20.}

21.

22.

23.void WS2812_Display_2( uint8_t red, uint8_t green, uint8_t blue,uint16_t num)

24.{

25.

26.uint8_t i;

27.uint32_t Color=(green << 16 | red << 8 | blue);// 将2 个8 位数据合并转化为32 位数据类型

28.

29.//指针偏移:需要跳过复位信号的N 个0

30.uint16_t* p = (RGB_buffur + Reste_Data) + (num * Led_Data_Len);

31.

32.for (i = 0; i < 24; ++i) // 对数组进行编辑

33.p[i]= (((Color << i) & 0X800000) ? Hight_Data : Low_Data);

34.

35.}

36.

37.

38.void WS2812_Number_4(uint32_t Color1,uint32_t Color2,uint32_t Color3,uint32_t Color4)

39.{

40.

41.uint16_t RGB_Buff_4[Reste_Data + 4 *WS2812_Data_Len] = { 0 };

42.uint16_t* p;

43.uint32_t Color;

44.

45.for( uint8_t k=0;k<4;k++)

46.{

47.switch (k) // 进行指针偏移

48.{

49.case 0: p= (RGB_Buff_4 + Reste_Data) +(0 * Led_Data_Len),Color=Color1;break;

50.case 1: p= (RGB_Buff_4 + Reste_Data) +(1 * Led_Data_Len),Color=Color2;break;

51.case 2: p= (RGB_Buff_4 + Reste_Data) +(2 * Led_Data_Len),Color=Color3;break;

52.case 3: p= (RGB_Buff_4 + Reste_Data) +(3 * Led_Data_Len),Color=Color4;break;

53.default : ;break;

54.}

55.

56.for (uint8_t i = 0; i < 8; ++i) // 对数组进行编辑

57.{

58. for (uint8_t i = 0; i < 8; ++i)

59.p[i+8]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);

60.for (uint8_t i = 8; i < 16; ++i)

61.p[i-8]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);

62.for (uint8_t i = 16; i < 24; ++i)

63.p[i]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);

64.}

65.

66.}

67.

68.HAL_TIM_PWM_Start_DMA(&htim1,TIM_CHANNEL_1,(uint32_t *)RGB_Buff_4,(176));//启动DMA传输

69.

70.}

71.

72.//DMA传输完成回调函数

73.void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)

74.{

75.HAL_TIM_PWM_Stop_DMA(&htim1,TIM_CHANNEL_1);

76.}

2.添加RGB.h 代码如下:

view plaincopy to clipboardprint?

1.#ifndef __RGB_H

2.#define __RGB_H

3.#include “main.h”

4.#define Hight_Data ( 64 ) //1码相对计数值

5. #define Low_Data ( 36 ) //0码相对计数值

6. #define Reste_Data ( 80 ) //80复位电平相对计数值

7.#define Led_Num ( 4 ) //WS2812灯个数

8.#define Led_Data_Len ( 24 )//WS2812数据长度,单个需要24个字节

9.#define WS2812_Data_Len (Led_Num * Led_Data_Len) //ws2812级联后需要的数组长度

10.

11.//uint16_t RGB_buffur[Reste_Data + WS2812_Data_Len] = { 0 }; //数据缓存数组

12.

13.

14.void WS2812_Display_1(uint32_t Color,uint16_t num);

15.void WS2812_Display_2( uint8_t red, uint8_t green, uint8_t blue,uint16_t num);

16.

17.void WS2812_Number_4(uint32_t Color1,uint32_t Color2,uint32_t Color3,uint32_t Color4);//封装好的四个灯函数,只需要分别输入四个灯的颜色即可

18.

19.

20.#endif

3.Main

首先引RGB.h头文件

再使用extern一下数组

view plaincopy to clipboardprint?

1.extern uint16_t RGB_buffur[Reste_Data +WS2812_Data_Len];

在while中添加周期的亮灯:

view plaincopy to clipboardprint?

1.WS2812_Number_4(0x180000,0x001800,0x000018,0);

2.HAL_Delay(500);

3.WS2812_Number_4(0,0x180000,0x001800,0x000018);

4.HAL_Delay(500);

5.WS2812_Number_4(0x000018,0,0x180000,0x001800);

6.HAL_Delay(500);

7.WS2812_Number_4(0x001800,0x000018,0,0x180000);

8.HAL_Delay(500);

【验证】

将ws2812 的DI 引脚接到PA8,VCC 与GND 接到开发板的电源上,将程序下载到开发板后,可以看到如期点亮了WB2812。

DMARGB
新浪科技公众号
新浪科技公众号

“掌”握科技鲜闻 (微信搜索techsina或扫描左侧二维码关注)

创事记

科学探索

科学大家

苹果汇

众测

专题

官方微博

新浪科技 新浪数码 新浪手机 科学探索 苹果汇 新浪众测

公众号

新浪科技

新浪科技为你带来最新鲜的科技资讯

苹果汇

苹果汇为你带来最新鲜的苹果产品新闻

新浪众测

新酷产品第一时间免费试玩

新浪探索

提供最新的科学家新闻,精彩的震撼图片