• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

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

武飞扬头像
嵌入式创客工坊
帮助1

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

  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
  21.  
     
  22.  
     
学新通

 RGB.c

  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.  
    }
  77.  
     
  78.  
     
  79.  
     
学新通

(4)main函数

  1.  
    #include "RGB.h"
  2.  
     
  3.  
     
  4.  
     
  5.  
    int main(void)
  6.  
    {
  7.  
     
  8.  
    extern uint16_t RGB_buffur[Reste_Data WS2812_Data_Len];
  9.  
     
  10.  
    HAL_Init();
  11.  
     
  12.  
    SystemClock_Config();
  13.  
     
  14.  
    MX_GPIO_Init();
  15.  
    MX_DMA_Init();
  16.  
    MX_TIM1_Init();
  17.  
    /* USER CODE BEGIN 2 */
  18.  
     
  19.  
    // //点亮4个灯
  20.  
    // WS2812_Display_1(0x180000, 0);
  21.  
    // WS2812_Display_1(0x001800, 1);
  22.  
    // WS2812_Display_1(0x000018, 2);
  23.  
    // WS2812_Display_1(0x181818, 3);
  24.  
    // HAL_TIM_PWM_Start_DMA(&htim1,TIM_CHANNEL_1,(uint32_t *)RGB_buffur,(176));//启动DMA传输
  25.  
     
  26.  
     
  27.  
    // //以下代码和上述效果一致,只是颜色数据表示形式不一样
  28.  
    // WS2812_Display_2( 22 , 0 , 0, 0);
  29.  
    // WS2812_Display_2( 0 , 22, 0, 1);
  30.  
    // WS2812_Display_2( 0 , 0, 22, 2);
  31.  
    // WS2812_Display_2( 22, 22 , 22, 3);
  32.  
    // HAL_TIM_PWM_Start_DMA(&htim1,TIM_CHANNEL_1,(uint32_t *)RGB_buffur,(176));//启动DMA传输
  33.  
     
  34.  
     
  35.  
     
  36.  
    while (1)
  37.  
    {
  38.  
     
  39.  
    //流水效果
  40.  
    WS2812_Number_4(0x180000,0x001800,0x000018,0);
  41.  
    HAL_Delay(500);
  42.  
    WS2812_Number_4(0,0x180000,0x001800,0x000018);
  43.  
    HAL_Delay(500);
  44.  
    WS2812_Number_4(0x000018,0,0x180000,0x001800);
  45.  
    HAL_Delay(500);
  46.  
    WS2812_Number_4(0x001800,0x000018,0,0x180000);
  47.  
    HAL_Delay(500);
  48.  
     
  49.  
     
  50.  
    }
  51.  
     
  52.  
    }
学新通

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

6.接线图及效果

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

学新通

学新通

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

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhghehjk
系列文章
更多 icon
同类精品
更多 icon
继续加载