STM32+PWM+DMA驱动WS2812 —— 2024年9月24日

news2024/11/17 21:32:53

一、项目简介

        采用STM32f103C8t6单片机,使用HAL库编写。项目中针对初学者驱动WS2812时会遇到的一些问题,给出了解决方案。

二、ws2812驱动原理

        WS2812采用单线归零码的通讯方式,即利用高低电平的持续时间来确定0和1。这种通信方式优点是只需要一根通信线,缺点是对通信的时序要求较高。

        以官方数据手册的时序图为例,通信速率为800kbit/s,也就是PWM波的速率为800Kbit/s,每个PWM的周期为1.25微妙。PWM的一个周期即为一个数据帧,每个数据帧由一段高电平和一段低电平组成。下图为官方规定的数据传输时间:

T0H0码,高电平时间0.22 us~0.35 us
T0L0码,低电平时间0.58 us~1.0 us
T1H1码,高电平时间0.58 us~1.0 us
T1L1码,低电平时间0.22 us~0.42 us
RES帧间隔,低电平时间50us以上

        也就是说:一个1码,由2/3左右的高电平 和 1/3左右的低电平组成。

                           一个0码,由1/3左右的高电平 和 2/3左右的低电平组成。

        若定时器的时钟频率为72MHz,那么预分频值设置为0,比较值设置为89,这样产生的PWM波的频率就为800KHz,周期为1.25us。要发送1码时,设置占空比为60。要发送0码时,设置占空比为29。

        每个WS2812需要用24bit的数据来控制,当n个ws2812进行级联的时候,第一个灯会将第一个24bit的数据拦截,将后面的数据进行转发。第二个灯又会拦截第二个24bit的数据,将后面的数据进行转发。后面的逻辑也是一样,数据每经过一个灯,数据的前24bit就会被拦截下来,作为这个灯的显示内容。数据传输方法如下图所示:

        代码编写逻辑:初始化的时候,需生成一个显存数组,由DMA将数组中的内容实时搬运到定时器的比较寄存器中,DMA要开启循环模式。之后我们只需要更新显存数组中的数据,WS2812的显示内容就会被实时更新。

三、Cube MX 生成底层代码

1、配置Debug的模式

2、配置外部晶振

3、配置时钟

4、配置定时器

5、配置定时器的DMA

6、生成代码

四、代码编写

1、下面ws2812.c的代码

#include "ws2812.h"

//显存数组,长度为 灯的数量*24+复位周期
uint16_t WS2812_RGB_Buff[LED_NUM*DATA_LEN+WS2812_RST_NUM] = {0}; 

/**
 * 函数:WS2812单灯设置函数
 * 参数:num:灯的位置,R、G、B分别为三个颜色通道的亮度,最大值为255
 * 作用:单独设置每一个WS2812的颜色
***/
void WS2812_Set(uint16_t num,uint8_t R,uint8_t G,uint8_t B)
{
  uint32_t indexx=(num*(3*8));
  for (uint8_t i = 0;i < 8;i++)
  {
	//填充数组
	WS2812_RGB_Buff[indexx+i]      = (G << i) & (0x80)?WS_H:WS_L;
	WS2812_RGB_Buff[indexx+i + 8]  = (R << i) & (0x80)?WS_H:WS_L;
	WS2812_RGB_Buff[indexx+i + 16] = (B << i) & (0x80)?WS_H:WS_L;
  }
}

//WS2812初始化函数
void WS2812_Init()
{
	//设置关闭所有灯
  for(int i=0;i<8;i++)
  {
	WS2812_Set(i,0,20,0);
  }
  //作用:调用DMA将显存中的内容实时搬运至定时器的比较寄存器
  HAL_TIM_PWM_Start_DMA(&htim2,TIM_CHANNEL_1,(uint32_t *)WS2812_RGB_Buff,sizeof(WS2812_RGB_Buff)/sizeof(uint16_t)); 
}

 2、下面为ws2812.h的代码

#include "main.h"
#include "tim.h"

#define WS_H           60   // 1 码相对计数值
#define WS_L           29   // 0 码相对计数值
#define WS_REST        40   // 复位信号脉冲数量
#define LED_NUM         8   // WS2812灯个数
#define DATA_LEN       24   // WS2812数据长度,单个需要24个字节
#define WS2812_RST_NUM 50   // 官方复位时间为50us(40个周期),保险起见使用50个周期

void WS2812_Init(void);
void WS2812_Set(uint16_t num,uint8_t R,uint8_t G,uint8_t B);

3.下面为main.c中调用的代码,效果为流水灯
 

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
  WS2812_Init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	//效果一,流水灯
	for(int i=0;i<8;i++)
	{
		HAL_Delay(100);
		WS2812_Set(i,2*(i+1),4*(i+1),10*(i+1));
	}
	HAL_Delay(300);
	for(int i=0;i<8;i++)
	{
		WS2812_Set(i,0,0,0);
	}
	HAL_Delay(100);

	//效果二,跑马灯
//	for(int i=0;i<8;i++)
//	{
//		HAL_Delay(100);
//		WS2812_Set(i,0,20,0);
//		if(i==0) WS2812_Set(7,0,0,0);
//		else     WS2812_Set(i-1,0,0,0);	
//	}
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

五、烧录效果

六、注意事项

1、DMA的搬运方向为 内存(Memory) 到 外设(Peripheral)

2、DMA的模式为循环模式

3、DMA设置内存地址自增

七、其他问题请留言

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2176663.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【赵渝强老师】Job控制器多工作队列的并行方式

Kubernetes Job是一次性任务的控制器。它控制Pod中的容器执行完成任务后不会再重启&#xff0c;并将容器的状态设置为“Completed”。如果Pod中的容器出现了异常终止的情况&#xff0c;Job控制器会根据设置的重启策略进行Pod的重启。如果因为Node节点的故障导致Pod无法正常运行…

[leetcode] 70. 爬楼梯

文章目录 题目描述解题方法动态规划java代码复杂度分析 题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1…

鸿蒙HarmonyOS NEXT 电商APP开发,打造你的专属购物商城

2024年年初&#xff0c;鸿蒙HarmonyOS Next星河版强势发布&#xff0c;随着鸿蒙系统的普及和应用场景的拓展&#xff0c;市场需求将持续增加。鸿蒙系统已经应用于华为的智能手机、平板电脑、智能家居等多个领域&#xff0c;并有望在未来拓展到智能汽车、物联网等更多领域。这为…

一起发现CMake太美-03-CMake是什么CMake的安装

本系列课程的主要内容包括&#xff1a; 点击本课程的 链接 可以进入视频课程的学习。 下面介绍本系列课程的第三课的主要内容&#xff0c;本节课介绍了CMake在Ubuntu环境、docker环境、CentOS环境上的安装过程进行了详细介绍。以便大家能够学会如何在linux环境中快速搭建CMak…

SpringMVC源码-SpringMVC源码请求执行流程及重点方法doDispatch讲解

一、开始请求 在浏览器访问http://localhost:8080/spring_mymvc/userlist这个接口&#xff0c;是个get请求。 FrameworkServlet类的service方法会被请求到: 调用路径如下&#xff1a; service:945, FrameworkServlet (org.springframework.web.servlet) service:764, HttpSer…

数据结构(7.3_5)——红黑树的插入和删除

红黑树的插入 注意&#xff1a;插入时候重点考察“不红红”特性&#xff08;红黑树的性质&#xff09; 染色&#xff1a;哪几个结点有变动就红的变黑&#xff0c;黑的变红 RR、LL、LR、RL从爷结点开始算起 非根结点的插入只需要判断是否违背的“不红红”特性 练习&#xff1…

通过人工智能AI大模型定制的完美旅游行程

人工智能在购票与乘车体验优化方面发挥着重要作用&#xff0c;通过智能技术的应用&#xff0c;不仅提升了购票效率&#xff0c;还改善了乘车体验。以下是人工智能赋能购票与乘车体验优化的具体表现&#xff1a; 一、购票体验优化 智能推荐系统&#xff1a; 购票平台如12306利…

USB3.0线束质量的影响

一. 前言 近一年频繁与USB3.0打交道&#xff0c;深受USB3.0线束之苦&#xff0c;在USB3.0相机和USB3.0 U盘上栽了很多跟头&#xff0c;问题反反复复。前期通过比对&#xff0c;发现USB3.0线束的特征阻抗特性对传输速度影响很大。市场上普通的USB3.0线束无法满足要求&#xff0…

免费送源码:Javaspringboot++MySQL springboot 社区互助服务管理系统小程序 计算机毕业设计原创定制

摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受居民的喜爱&#xff0c;社区互助服务管理系统小程序被居民普遍使用&#xff0c;为…

FastAPI 第七课 -- Pydantic 模型

目录 一. 前言 二. 定义 Pydantic 模型 三. 使用 Pydantic 模型 3.1. 请求体验证 3.2. 查询参数验证 四. 自动文档生成 五. 数据转换和序列化 一. 前言 Pydantic 是一个用于数据验证和序列化的 Python 模型库。 它在 FastAPI 中广泛使用&#xff0c;用于定义请求体、响…

鸢尾花书实践和知识记录[编程1-10可视化]

一个人可以被摧毁&#xff0c;但不能被打败。 A man can be destroyed but not defeated 原作者的github 主要内容Matplotlib,Plotly如何绘制线图 文章目录 思维导图解剖图代码:图像的要素和标注 使用Matplotlib绘制线图代码2:绘制正弦和余弦的图像图像存储格式的说明 代码3子…

Linux 默认内核版本更改

随笔记录 目录 1. 背景介绍 2. 解决方法 2.1 查看所有可用版本 2.2 安装指定版本内核 2.3 检查当前内核列表 2.4 检查当前默认内核 2.5 设置新的默认内核 2.6 确认内核是否成功加载 2.7 重启 2.8 删除其他版本内核 1. 背景介绍 linux 一般安装多个内核版本&…

97、配置 VXLAN 不同子网互访 (分布式网关)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、基础配置SW1SW2IGP IS-IS 二、VXLAN1.引入库 总结 前言 一、基础配置 SW1 vlan 10 vlan 20interface GigabitEthernet0/0/1port link-type accessport de…

[Python学习日记-33] Python 中的嵌套函数、匿名函数和高阶函数

[Python学习日记-33] Python 中的嵌套函数、匿名函数和高阶函数 简介 嵌套函数 匿名函数 高阶函数 简介 在 Python 当中函数除了能减少重复代码、扩展性强和易维护外&#xff0c;其实还有挺多不通的玩法的&#xff0c;例如嵌套函数、匿名函数、高阶函数等&#xff0c;它们是…

酒店智能开关的组成与功能

酒店智能开关作为智能家居系统的重要组成部分&#xff0c;其应用日益广泛。本文将深入探讨酒店智能开关的组成部分及其功能特点。 酒店智能开关的组成 酒店智能开关的构成相对复杂&#xff0c;但主要可以归纳为以下几个核心部分&#xff1a; 开关主体&#xff1a;开关主体是智能…

带链的队列,入队,退队,检测带链队列的状态

代码&#xff1a; #include<iostream> using namespace std; template<class T> struct node {T d;node *next;}; template<class T> class linked_Queue {private:node<T> *front;node<T> *rear;public:linked_Queue();void prt_linked_Queue(…

联想电脑怎么开启vt_联想电脑开启vt虚拟化教程(附intel和amd主板开启方法)

最近使用联想电脑的小伙伴们问我&#xff0c;联想电脑怎么开启vt虚拟。大多数可以在Bios中开启vt虚拟化技术&#xff0c;当CPU支持VT-x虚拟化技术&#xff0c;有些电脑会自动开启VT-x虚拟化技术功能。而大部分的电脑则需要在Bios Setup界面中&#xff0c;手动进行设置&#xff…

掌握DFIR报表: 法医专家指南

介绍 在数字安全领域&#xff0c;DFIR&#xff08;数字取证和事件响应&#xff09;是一门重要的学科&#xff0c;体现了调查网络事件和破坏行为所必不可少的方法和实践。作为DFIR的核心&#xff0c;对DFIR报告的重视怎么强调都不为过。这些报告不仅仅是文件&#xff1b;它们是…

每天3分钟,彻底弄懂神经网络的优化器(三)Momentum

前面从最初的SGD开始&#xff0c;介绍SGD的算法细节&#xff0c;以及其在深度神经网络中的劣势&#xff0c;本文引入Momentum算法&#xff0c;解决SGD的一些问题。 1. Momentum算法的提出 动量&#xff08;Momentum&#xff09;方法最初由B.T.Polyak在1964年提出。这一方法被…

IAR全面支持国科环宇AS32X系列RISC-V车规MCU

IAR嵌入式开发解决方案将全面支持国科环宇AS32X系列ASIL-B MCU&#xff0c;共同推动汽车高品质应用的安全开发 中国上海&#xff0c;2024年9月29日 – 全球领先的嵌入式系统开发软件解决方案供应商IAR与北京国科环宇科技股份有限公司&#xff08;以下简称“国科环宇”&#xf…