STM32系列(HAL库)——F103C8T6驱动WS2812全彩RGB模块(PWM+DMA方式)

2023-11-17

1.软件准备

(1)编程平台:Keil5

(2)CubeMX

2.硬件准备

(1)某宝买的RGB模块(4个灯珠级联)

(2)F1的板子,本例使用经典F103C8T6

(3)ST-link 下载器

(4)杜邦线若干

3.模块资料

(1)模块简介:

没什么比手册讲得更加清楚了,模块中文数据手册:ws2812b中文资料_数据手册_参数

(2)驱动原理:

         以上这是数据手册中提到的,WS2812驱动用的是单线归零码的通讯方式。不同占空比的方波代表1码或者0码,这里不同的占空比就是  0码或1码高电平时间 / 方波周期时间 。对于本次例程,我们就是改变PWM的占空比实现0码或1码的传输。

(3)PWM+DMA原理:

        关于DMA的详细解析,我推荐这篇文章:DMA原理,步骤超细详解,一文看懂DMA

        PWM+DMA可以实现数量和占空比可控的脉冲,具体实现原理是在开启DMA的情况下,定时器在每次计数满后,会自动将DMA传输过来的数据作为新一轮的比较数值。如果DMA传输的数据每次不同,那么每次的方波占空比就不一样的。在本例程中,我们将数据存放在一个数组,通过DMA传输数组的内容,根据数组中数据的个数和每个数据的大小,就能实现数量和占空比可控的PWM。

4.CubeMX配置

(1)芯片选择

 (2)配置RCC、SYS、时钟树

配置RCC

配置SYS

配置时钟树

(3)配置定时器TIM1

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

(4)开启DMA

 (5)设置路径、生成代码工程 

5、Keil5代码

(1)创建RGB.c和RGB.h文件

(2)添加上述的RGB.c文件进工程

——————上述两步参考之前系列教学步骤,在此不再赘述(点击跳转)

(3)RGB.c和RGB.h代码

 RGB.h

#ifndef __RGB_H
#define __RGB_H
#include "main.h"
#define Hight_Data            ( 64  )                           //1 码相对计数值
#define Low_Data              ( 36  )                           //0 码相对计数值
#define Reste_Data            ( 80  )                           //80 复位电平相对计数值
#define Led_Num               (  4  )                           //WS2812灯个数
#define Led_Data_Len          ( 24  )                           //WS2812数据长度,单个需要24个字节
#define WS2812_Data_Len   (Led_Num * Led_Data_Len)              //ws2812级联后需要的数组长度

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


void WS2812_Display_1(uint32_t Color, uint16_t num);
void WS2812_Display_2( uint8_t red, uint8_t green, uint8_t blue,uint16_t num);

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


#endif


 RGB.c

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

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

void WS2812_Display_1(uint32_t Color, uint16_t num)
{
   
    //指针偏移:需要跳过复位信号的N个0
    uint16_t* p = (RGB_buffur + Reste_Data) + (num * Led_Data_Len);
    
    for (uint8_t i = 0; i < 8; ++i)         
	p[i+8]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);
    for (uint8_t i = 8; i < 16; ++i)
	p[i-8]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);
    for (uint8_t i = 16; i < 24; ++i)
	p[i]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);  
       
}


void WS2812_Display_2( uint8_t red, uint8_t green, uint8_t blue,uint16_t num)
{
            
            uint8_t i;
            uint32_t Color=(green << 16 | red << 8 | blue);//将2个8位数据合并转化为32位数据类型
    
            //指针偏移:需要跳过复位信号的N个0
            uint16_t* p = (RGB_buffur + Reste_Data) + (num * Led_Data_Len);
    
            for (i = 0; i < 24; ++i)    //对数组进行编辑
			p[i]= (((Color << i) & 0X800000) ? Hight_Data : Low_Data);	
                        
}


void WS2812_Number_4(uint32_t Color1,uint32_t Color2,uint32_t Color3,uint32_t Color4)
{
    
    uint16_t  RGB_Buff_4[Reste_Data + 4 * WS2812_Data_Len] = { 0 };
    uint16_t* p;
    uint32_t Color;
    
    for( uint8_t k=0;k<4;k++)
  {      
      switch (k)    //进行指针偏移
      {
        case 0: p= (RGB_Buff_4 + Reste_Data) + (0 * Led_Data_Len),Color=Color1;break;
        case 1: p= (RGB_Buff_4 + Reste_Data) + (1 * Led_Data_Len),Color=Color2;break;
        case 2: p= (RGB_Buff_4 + Reste_Data) + (2 * Led_Data_Len),Color=Color3;break;
        case 3: p= (RGB_Buff_4 + Reste_Data) + (3 * Led_Data_Len),Color=Color4;break;
        default : ;break;     
      }
      
     for (uint8_t i = 0; i < 8; ++i)   //对数组进行编辑
    {   
        for (uint8_t i = 0; i < 8; ++i)
        p[i+8]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);
        for (uint8_t i = 8; i < 16; ++i)
        p[i-8]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);
        for (uint8_t i = 16; i < 24; ++i)
        p[i]= (((Color << i) & 0X800000) ? Hight_Data :Low_Data);
    } 
   
 }   
  
    HAL_TIM_PWM_Start_DMA(&htim1,TIM_CHANNEL_1,(uint32_t *)RGB_Buff_4,(176));//启动DMA传输
    
}

 //  DMA 传输完成回调函数
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
    HAL_TIM_PWM_Stop_DMA(&htim1,TIM_CHANNEL_1);
}



(4)main函数

#include "RGB.h"



int main(void)
{
 
  extern uint16_t RGB_buffur[Reste_Data + WS2812_Data_Len];
 
  HAL_Init();
 
  SystemClock_Config();

  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */

//        //点亮4个灯
//        WS2812_Display_1(0x180000, 0);
//        WS2812_Display_1(0x001800, 1);
//        WS2812_Display_1(0x000018, 2);
//        WS2812_Display_1(0x181818, 3);
//        HAL_TIM_PWM_Start_DMA(&htim1,TIM_CHANNEL_1,(uint32_t *)RGB_buffur,(176));//启动DMA传输        


//        //以下代码和上述效果一致,只是颜色数据表示形式不一样
//        WS2812_Display_2( 22 , 0 , 0, 0);
//        WS2812_Display_2(  0 , 22, 0, 1);
//        WS2812_Display_2(  0 , 0, 22, 2);
//        WS2812_Display_2( 22, 22 , 22, 3);
//        HAL_TIM_PWM_Start_DMA(&htim1,TIM_CHANNEL_1,(uint32_t *)RGB_buffur,(176));//启动DMA传输 

 
 
  while (1)
  {
      
      //流水效果
    WS2812_Number_4(0x180000,0x001800,0x000018,0);
    HAL_Delay(500);
    WS2812_Number_4(0,0x180000,0x001800,0x000018);
    HAL_Delay(500);
    WS2812_Number_4(0x000018,0,0x180000,0x001800);
    HAL_Delay(500);
    WS2812_Number_4(0x001800,0x000018,0,0x180000);
    HAL_Delay(500);
     
    
  }
 
}

        因时间问题,代码没有做过多注释。后续再补上。

6.接线图及效果

        关于接线:定时器1的通道1为PA8,将PA8和模块IN引脚连接,并注意供电充足即可。

  本例程源码下载:点击跳转 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32系列(HAL库)——F103C8T6驱动WS2812全彩RGB模块(PWM+DMA方式) 的相关文章

  • 调用 McAfee 病毒扫描引擎

    我收到客户的请求 要求使用他们服务器上的 McAfee 病毒扫描将病毒扫描集成到应用程序中 我做了一些调查 发现 McScan32 dll 是主要的扫描引擎 它导出各种看起来有用的函数 我还发现提到了 McAfee Scan Engine
  • 根据属性的类型使用文本框或复选框

    如果我有这样的结构 public class Parent public string Name get set public List
  • 如何从 Visual Studio 将视图导航到其控制器?

    问题是解决方案资源管理器上有 29 个项目 而且项目同时具有 ASP NET MVC 和 ASP NET Web 表单结构 在MVC部分中 Controller文件夹中有大约100个子文件夹 每个文件夹至少有3 4个控制器 视图完全位于不同
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • 人脸 API DetectAsync 错误

    我想创建一个简单的程序来使用 Microsoft Azure Face API 和 Visual Studio 2015 检测人脸 遵循 https social technet microsoft com wiki contents ar
  • 两个类可以使用 C++ 互相查看吗?

    所以我有一个 A 类 我想在其中调用一些 B 类函数 所以我包括 b h 但是 在 B 类中 我想调用 A 类函数 如果我包含 a h 它最终会陷入无限循环 对吗 我能做什么呢 仅将成员函数声明放在头文件 h 中 并将成员函数定义放在实现文
  • 如何在当前 Visual Studio 主机内的 Visual Studio 扩展中调试使用 Roslyn 编译的代码?

    我有一个 Visual Studio 扩展 它使用 Roslyn 获取当前打开的解决方案中的项目 编译它并从中运行方法 程序员可以修改该项目 我已从当前 VisualStudioWorkspace 成功编译了 Visual Studio 扩
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • 对于某些 PDF 文件,LoadIFilter() 返回 -2147467259

    我正在尝试使用 Adob e IFilter 搜索 PDF 文件 我的代码是用 C 编写的 我使用 p invoke 来获取 IFilter 的实例 DllImport query dll SetLastError true CharSet
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置

随机推荐

  • 会议OA项目----我的审批

    前言 上一篇博客我将我的会议的送审和会议排座这两个功能完成 送审之后就到了审批阶段 那么这次做的就是 我的审批 一 实现思路 根据产品原型图 见产品原型图 我的审批界面与我的会议界面大同小异 那么我们可以调用之前的写好的SQL语句 只不过将
  • 文件上传/下载接口(超简单的教程来了)

    前言 文件上传 下载接口与普通接口类似 但是有细微的区别 如果需要发送文件到服务器 例如 上传文档 图片 视频等 就需要发送二进制数据 上传文件一般使用的都是 Content Type multipart form data 数据类型 可以
  • java懒加载注解_一分钟学习Spring注解之懒加载@Lazy

    先声明 本篇文章非常简单属于一分钟学会使用系列 不深入讲解原理 如果要学习源码 可以看小编Spring源码解析系列 什么是懒加载 懒加载就是不使用不加载 使用的时候才去加载 Spring默认不是懒加载 而是启动加载 就在Spring上下文启
  • rac集群节点级联重启故障分析

    author skate time 2012 07 16 无意中发现以前处理故障写的一篇文章 记录下来以备查找 rac集群节点级联重启故障分析 环境 os linux db rac10g ocfs2 rac数据库环境实际包含两个集群 一个是
  • linux socket非阻塞之connect 函数

    1 connect原型 include
  • 联想E480安装MacOS苹果系统记录

    联想E480安装MacOS记录 联想E480安装黑苹果 自己有用IPad和Iphone 但Mac OS却没怎接触过 于是萌生了转用Mac OS的想法 用自用的联想E480装个黑果 为了方便软件上的互补 双系统优先 网上搜搜转转没发现有E48
  • 代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、206.反转链表

    目录 知识点 链表 结点定义 单链表的初始化 判断一个链表是否为空 单链表的销毁 清空单链表 求链表表长 取单链表中第i个元素 按值查找 插入第i个结点 删除第i个结点 移除列表元素 没有采用虚拟头结点的方法 采用虚拟头结点的方法 设计链表
  • PHPExcel导出各种方法总结

    PHPExcel导出 方法一 https blog csdn net u014236259 article details 60601767 public function ExportExcelOrder data name vendor
  • ARM+Linux中断系统详细分析

    ULK第四章里明确讲到 Linux实现了一种没有优先级的中断模型 并且 Linux中断和异常都支持嵌套 这个我不太理解了 这两种说法都与我以前的理解刚好相反 核对了原书 翻译没有错 Linux中断系统到底是否支持优先级 可否嵌套 中断号又是
  • c# json解析(反序列化)、json规范化

    使用 NETFramework3 5 4 0中提供的System Web Script Serialization命名空间下的JavaScriptSerializer类进行对象的序列化与反序列化 很直接 要求当前的工程的TargetFram
  • Two Divisors【GCD数论】

    You are given nn integers a1 a2 ana1 a2 an For each aiai find its two divisors d1 gt 1d1 gt 1 and d2 gt 1d2 gt 1 such th
  • vue实现预览PDF、Excel、Docx、Txt、PPT文件的功能

    目录 一 实现步骤 二 实现效果 代码真实可用 一 实现步骤 1 使用的是vue和elementUI 假设有这些变量 attachment是附件的意思 data return previewDialog false attachmentSr
  • 交换机与路由器技术:静态NAT、动态NAT、PAT和端口镜像

    网络地址转换NAT 1 静态转换 2 动态转换 3 端口多路复用PAT 4 端口映射 服务器映射 目录 一 NAT基本概念 1 目的 2 出现背景 3 转换方式 二 静态NAT 三 动态NAT 三 PAT 总结 五 端口镜像 1 基本概念
  • 【unity】Shader.SetGlobalFloat/Vector/Texture 不生效

    Shader SetGlobalFloat Shader SetGlobalVector Shader SetGlobalTexture等等函数不生效是为什么 答 shader的properties要去掉对应的变量 也就是说shader获取
  • echarts的基本使用

    一 基本使用 1 导入echarts js 下载并导入 地址 https echarts apache org zh download html 使用 CDN 方法 https cdn staticfile org echarts 4 3
  • C++ private,public,protected的访问范围解析

    第一 private public protected的访问范围 private 只能由该类中的函数 其友元函数访问 不能被任何其他访问 该类的对象也不能访问 protected 可以被该类中的函数 子类的函数 以及其友元函数访问 但不能被
  • BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.NullPointerException

    集成mybatis plus sqlSessionFactory改为MybatisSqlSessionFactoryBean后 项目无法启动
  • 团队新人多,稳定性经验不足,研发质量怎么保障?|TakinTalks论道

    一分钟精华速览 在研发和稳定性保障过程中 人与设备 程序 组织的交互是一个复杂的过程 虽然人们极少会恶意犯错 但由于受特定情景下的实际条件影响 人为失误也时有发生 那么 如何尽可能减少这些失误的发生 如何保障研发质量和系统稳定 TakinT
  • 读《大数据时代》有感

    大数据时代 读后感 大数据时代 这本书主要描述的是大数据时代到临人们生活 工作与思维各方面所遇到的重大变革 文中清晰的阐述了大数据的基本概念和特点 并列出明确的观点 不管对于产业实践者 还是对于政府和公众机构 都非常具有价值 作者将本书分为
  • STM32系列(HAL库)——F103C8T6驱动WS2812全彩RGB模块(PWM+DMA方式)

    1 软件准备 1 编程平台 Keil5 2 CubeMX 2 硬件准备 1 某宝买的RGB模块 4个灯珠级联 2 F1的板子 本例使用经典F103C8T6 3 ST link 下载器 4 杜邦线若干 3 模块资料 1 模块简介 没什么比手册