STM32使用PWM驱动WS2812_RGB灯珠

news2025/1/2 0:19:47

项目场景:


使用STM32标准库产生PWM实现RGB灯珠控制。
芯片型号:stm32f405rgt6
设计优点:不需要使用定时器中断资源,可以使得STM32在驱动RGB灯珠的同时能够执行其他任务。


RGB灯珠简介


项目所使用的RGB灯珠如下所示,封装为5050。
在这里插入图片描述
串联结构如下所示:
在这里插入图片描述
每个灯珠采用24bit数据结构进行显示驱动,其数据结构如下所示:
在这里插入图片描述
发送顺序为高位在前,按照GRB格式进行发送
由于RGB灯珠采用单线归零码方进行数据传输,所以具有严格的时许要求,通过单个周期内高低电平持续的时间来判断bit位为0、1或reset。三种数据类型的高低电平时间如下:
在这里插入图片描述


目前已有的实现方式:


参考:https://blog.csdn.net/qq_40102829/article/details/106030934

第一种是使用延时函数在特定延时时间内对输出管脚进行翻转操作,这种方式非常占用单片机资源,而且实现1.25us延时的准确度不高。

第二种是使用定时器进行PWM输出,输出频率设置为800kHz即可实现1.25us周期循环,通过改变周期内占空比来实现0码和1码输出,但是用到了定时器中断,1.25us的中断非常快,会导致STM32几乎不能处理其他事务。

第三种是使用SPI,这种方式比较巧妙,使用SPI的clk线和mosi线,通过8分频可以设置clk时钟线的输出频率,然后采用16byte数据模拟0码和1码,这样输出频率为562.5kHz,理论上也是可以驱动的,该up主的文章【SPI驱动ws2812】有介绍这种方式,感兴趣的可以尝试下。


本文设计方式:


  1. 计算定时器ARR值:本项目使用的芯片型号是STM32F405RGT6,使用了TM3来进行PWM生成。TIM3挂载在APB1总线上,主频为84M。由于RGB灯一个码元周期为1.25us,故计算的ARR=105,PSC=0。
  2. 确定0码和1码的占空比:
 T0H_Pulse = (T0H/1.25us) * arr = 0.32/1.25 * arr = 27
 T1H_Pulse = (T1H/1.25us) * arr = 0.64/1.25 * arr = 54
  1. reset码设置:RGB灯珠需要保持至少80us以上的低电平才能复位,为了实现reset功能,本文的设计方式是通过将pwm占空比设置为0,让其保持多个周期来实现80us以上的低电平达到复位效果。具体实现代码如下:
void ledReset()
{
	u8 i;
	//设置保持周期数,达到复位效果
	for(i=0;i<120;i++) //150us/1.25us = 120
	{
		TIM_SetCompare4(TIM3, 0); //让占空比为0
		while(TIM3->CNT < TIM3_ARR);
	}

}
  1. 将RGB颜色格式转换为GRB格式:由于颜色生成网站上的颜色格式都是RGB格式,直接复制过来没法直接使用,需要去手动交换颜色顺序,本文设计了颜色格式转换函数,可以自动将RGB格式转换为GRB格式,具体实现如下:
//将RGB格式转换为GRB格式
u32 dataPrecess(u32 RGBData)
{
	u32  GRBData;
	u8 R, G, B;
	B = RGBData & (u8)0xff;
	G = (RGBData >> 8) & (u8)0xff;
	R = (RGBData >> 16) & (u8)0xff;
	
	GRBData = 0;//先置零,保证数据干净
	GRBData |= G;
	GRBData <<= 8;
	GRBData |= R;
	GRBData <<= 8;
	GRBData |= B;
	return GRBData;
}

完整代码:


led.c

#include "led.h" 
#include "delay.h"
#include "usart.h"

const u8 N = 12;
u32 colors[N] = {
					0x84fab0, 0x8fd3f4,
					0xfccb90, 0xd57eeb,
					0xfa709a, 0xfee140,
					0x5ee7df, 0xb490ca,
					0xcfd9df, 0xe2ebf0,
					0xff0000, 0x00ff00
                };


//PC9->TIM3_CH4
void TIM3_PWM_Init(u16 arr,u16 psc)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
	
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;       
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;      
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;     
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;       
	GPIO_Init(GPIOC,&GPIO_InitStructure); 

	GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_TIM3);    
	
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;  //分频因子
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = arr;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = psc;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	TIM_OCStructInit(&TIM_OCInitStructure);
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//TIM_OCMode_PWM1
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//TIM_OCPolarity_High
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	
	TIM_OC4Init(TIM3, &TIM_OCInitStructure);
	TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable);
	
	TIM_CtrlPWMOutputs(TIM3, ENABLE);
	TIM_ARRPreloadConfig(TIM3,ENABLE); //使能TIM3在ARR上的预装载寄存器
	TIM_Cmd(TIM3, ENABLE);
}

//将RGB格式转换为GRB格式
u32 dataPrecess(u32 RGBData)
{
	u32  GRBData;
	u8 R, G, B;
	B = RGBData & (u8)0xff;
	G = (RGBData >> 8) & (u8)0xff;
	R = (RGBData >> 16) & (u8)0xff;
	
	GRBData = 0;//先置零,保证数据干净
	GRBData |= G;
	GRBData <<= 8;
	GRBData |= R;
	GRBData <<= 8;
	GRBData |= B;
	return GRBData;
}

void ledReset()
{
	u8 i;
	//设置保持周期数,达到复位效果
	for(i=0;i<120;i++) //150us/1.25us = 120
	{
		TIM_SetCompare4(TIM3, 0); //让占空比为0
		while(TIM3->CNT < TIM3_ARR);
	}

}

void singleLedShow(u32 GRBData)
{
	u8 i;
	u32 pulse;
	for(i=0;i<24;i++)
	{
		pulse = (GRBData & 0x00800000) ? T1H_Pulse : T0H_Pulse;
		TIM_SetCompare4(TIM3, pulse); 
		while(TIM3->CNT < TIM3_ARR);
		GRBData = GRBData<<1;
	}
}

void ledControl()
{
	u8 i;
	ledReset();
	for(i=0;i<N;i++)
	{
		singleLedShow(dataPrecess(colors[i]));
		delay_ms(300);
		ledReset();
	}
}








led.h

#ifndef __led_h
#define __led_h

#include "sys.h"

#define T0H_Pulse 27
#define T0L_Pulse 78

#define T1H_Pulse 54
#define T1L_Pulse 51

#define TIM3_ARR 105

void TIM3_PWM_Init(u16 arr,u16 psc);
void ledControl();	
u32 dataPrecess(u32 oData);

#endif


效果展示:

stm32驱动RGB

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

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

相关文章

76. UE5 RPG 实现场景阻挡剔除功能

在俯视角游戏中&#xff0c;我们总会碰到一个问题就是&#xff0c;建筑会遮挡住角色的问题。遇到这种问题有多种解决方案&#xff0c;厂商经常使用的一种方案是&#xff0c;如果角色被遮挡&#xff0c;则使用一种纯色或者增加一些菲涅尔的效果来实现 这种效果我之前在unity内实…

免费使用文心一言会员教程

领取&安装链接&#xff1a;Baidu Comate 领取季卡 有图有真相 原理&#xff1a;百度comate使用文心一言最新的4.0模型。百度comate目前免费使用&#xff0c;可以借助comate达到免费使用4.0模型目的。 如何获得 点击「Baidu Comate 领取季卡 -> 领取权益」&#xff0…

Cesium Model 中的剪裁平面 (ClippingPlane)

Cesium Model 中的剪裁平面 (ClippingPlane) 参考: https://www.cnblogs.com/webgl-angela/p/9197672.html Cesium Model 中的剪裁平面 (ClippingPlane) // 相关类: class ClippingPlaneCollection {} class ClippingPlane {}// 剪裁的整体流程: Model.prototype.update () …

Mathematica训练课(45)-- 一些常用的函数Abs[],Max[]等函数用法

①绝对值函数&#xff1a;Abs[]函数 ②最大值和最小值函数 ③反函数

SAP ATP可用性检查简介

Availability Check,就是可用性检查,指的是要检查一下此物料是否能满足我的需求。 接到一张销售订单(SALES ORDER),客户要求数量为100PC,并且客户要求的出货日期是2024-07-01,此时我们的销售人员肯定会想到底能否出货给客人呢?系统中建立此单时,SAP就会做一个所谓的检…

实验八 T_SQL编程

题目 以电子商务系统数据库ecommerce为例 1、在ecommerce数据库&#xff0c;针对会员表member首先创建一个“呼和浩特地区”会员的视图view_hohhot&#xff0c;然后通过该视图查询来自“呼和浩特”地区的会员信息&#xff0c;用批处理命令语句将问题进行分割&#xff0c;并分…

17859划分准则小结

17859《划分准则》 发布时间&#xff1a;1999.9.13 实施时间&#xff1a;2001.1.1 计算机信息系统安全保护能力的五个等级&#xff1a; 第一级&#xff1a;用户自主保护级 第二级…

Java知识点整理 15 — MyBatis框架

一. 什么是 MyBatis MyBatis 是一款优秀的持久层框架&#xff0c;支持自定义 SQL、存储过程以及高级映射。它免除了几乎所有 JDBC代码以及手动设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff08;普通老式 Jav…

人脑网络的多层建模与分析

摘要 了解人类大脑的结构及其与功能的关系&#xff0c;对于各种应用至关重要&#xff0c;包括但不限于预防、处理和治疗脑部疾病(如阿尔茨海默病或帕金森病)&#xff0c;以及精神疾病(如精神分裂症)的新方法。结构和功能神经影像学方面的最新进展&#xff0c;以及计算机科学等…

决定佛蒙特州版图的关键历史事件:

​决定佛蒙特州版图的关键历史事件: 1. 早期探险与命名&#xff1a; - 1609年&#xff0c;法国探险家萨缪尔德尚普兰&#xff08;Samuel de Champlain&#xff09;到达了现在的佛蒙特州区域&#xff0c;并探索了尚普兰湖&#xff08;Lake Champlain&#xff09;。他将周围的山…

mwwz库添加对多模板匹配的支持:find_shape_models

多模板匹配的实现只需要对单模板匹配做一些扩展&#xff0c;传入的模板由不同的id表示&#xff0c;在金字塔顶层完成模板的分类&#xff0c;在剩下的金字塔完成对每一类模板的匹配&#xff0c;匹配结果由id标识。测试程序已集成该方法&#xff0c;清除模板后所创建的模板被看作…

Python基于决策树分类模型、支持向量机分类模型、随机森林分类模型和XGBoost分类模型实现月亮数据标签预测项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 在探索机器学习算法的性能与适用性时&#xff0c;我们往往需要依赖于精心设计的人工数据集来测试和验证…

全面对标GPT-4 Turbo,讯飞星火V4.0凭什么?

大数据产业创新服务媒体 ——聚焦数据 改变商业 自从ChatGPT爆火出圈之后&#xff0c;大模型就走上了发展的快车道。 一方面&#xff0c;大模型技术快速演进&#xff0c;Sora为我们打开了视频生成的想象空间&#xff0c;各大厂商争相打破大模型的“模态墙”&#xff0c;长文本…

pytest中的极其重要固件(request)的理解

pytest 是一个非常流行的Python测试框架&#xff0c;它为开发人员提供了丰寴的测试工具和功能。 在pytest中&#xff0c;固件&#xff08;fixture&#xff09;是一种非常核心的概念&#xff0c;用于设置测试前的预条件&#xff0c;清理测试后的环境&#xff0c;或者提供测试过…

什么是DEQ?

DEQ (Delivered Ex Quay, Duty Paid) 是指目的港码头交货 (……指定目的港)。 这种术语规定卖方在指定目的港码头将货物交给买方处置&#xff0c;并且不办理进口清关手续。 DEQ适用范围 DEQ术语仅适用于海运、内河运输或多式联运&#xff0c;并且在目的港码头卸货时使用。如…

RAG 基本流程及处理技巧 with LangChain

LLM 主要存在两个问题&#xff1a;幻想和缺乏领域知识。领域知识缺乏的原因是因为训练 LLM 本身的知识更新慢&#xff0c;对特定领域的知识也没有太细致的输入。 RAG 主要是解决 LLM 缺乏领域知识的问题。底层的逻辑是&#xff1a;把 LLM 作为逻辑推理引擎&#xff0c;而不是信…

【计算机网络仿真】b站湖科大教书匠思科Packet Tracer——实验10 IPv4地址 — 构造超网(无分类编址)

一、实验目的 1.加深对构造超网的理解&#xff1b; 二、实验要求 1.使用Cisco Packet Tracer仿真平台&#xff1b; 2.观看B站湖科大教书匠仿真实验视频&#xff0c;完成对应实验。 三、实验内容 1.构建网络拓扑&#xff1b; 2.根据各网络所指定的地址块完成以下工作&#…

Python 面试【中级】

欢迎莅临我的博客 &#x1f49d;&#x1f49d;&#x1f49d;&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

Linux----> tail、cat、more、head、less的用法详解

1.tail命令&#xff1a;用于查看文件的最后几行内容。 基本用法&#xff1a;tail [选项] [文件] 常用选项&#xff1a; -n <行数>&#xff1a;显示最后的 <行数> 行。-f&#xff1a;实时显示文件新增内容&#xff0c;通常用于查看日志文件。 示例&#xff1a;…

程序中的Reduce(CPU和GPU)

前提 最近在看Reduce&#xff08;归约&#xff09;的相关知识和代码&#xff0c;做个总结。这里默认大家已经明白了Reduce的基础概念。 Reduce 根据参考链接一&#xff0c;Recude常见的划分方法有两种&#xff1a; 相邻配对&#xff1a;元素和它们相邻的元素配对 交错配对…