谁不想拥有炫酷的小彩灯呢?WS2812B可以给你机会......

博主使用STM32驱动WS2812B主要参考了这位佬的文章,因为需求问题,采用了Cortex-M0的stm32f030f4p6(16k的flash,4k的sram)来驱动,原文中写的是stm32f103c8t6,个人认为其实区别并不是很大,需要修改部分参数即可移植(cv战士申请出战)。

上图是我的一圈灯,一共8个,第一个LED的数据输入端接的是定时器1的通道2,想看底层原理可以去看佬的文章,本文只介绍如何移植。

CUBEMX配置

首先选择外部石英晶振,我用的是外部12M晶振,然后配置时钟树:

然后打开串行调试:

找到使用的定时器(输出PWM的),并打开定时器时钟,选定输出PWM的通道以及模式:

重点来了:

佬的文章中说的0码PWM占空比(CCR值)算到约为28,1码PWM占空比(CCR值)算到约为58;但人家用的是f1啊,72M时钟频率的,咱的是f0,自然低人一等,只有48M时钟频率。所以在满足灯带频率固定为800KHz的前提下,略微修改即可,设置参数如下:

下面来简单说一下如何修改

因为PWM频率F需要为800KHz,而时钟频率固定为48MHz,根据Fpwm=Fclk / (arr+1)(psc+1),我取psc为0,取arr=59,恰好可以得到 800KHz的频率,所以arr取值为59。因此,计算出PWM0码的CCR值为:0.32 × (59+1)=19.2 ≈ 19;PWM1码的CCR值为:0.32 × (59+1)=38.4 ≈ 38;

接下来配置DMA:

再由于我后面切换显示需要用到定时器中断,所以用了一个定时器3的1ms中断:

 配置好生成路径后直接生成代码即可

代码部分:

主函数头文件加个#include "ws2812b.h"即可

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_TIM1_Init();MX_TIM3_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */led_loop();  //循环显示}/* USER CODE END 3 */
}

ws2812b.h文件如下:

#ifndef __WS2812B_H__
#define __WS2812B_H__#include "main.h"/*这里是上文计算所得CCR的宏定义*/
#define CODE_1       (38)       //1码定时器计数次数
#define CODE_0       (19)       //0码定时器计数次数/*建立一个定义单个LED三原色值大小的结构体*/
typedef struct
{uint8_t R;uint8_t G;uint8_t B;
}RGB_Color_TypeDef;#define Pixel_NUM 8  //LED数量宏定义,这里我使用一个LED,(单词pixel为像素的意思)void RGB_SetColor(uint8_t LedId,RGB_Color_TypeDef Color);//给一个LED装载24个颜色数据码(0码和1码)
void Reset_Load(void); //该函数用于将数组最后24个数据变为0,代表RESET_code
void RGB_SendArray(void);          //发送最终数组
void RGB_RED(uint16_t Pixel_Len);  //显示红灯
void RGB_GREEN(uint16_t Pixel_Len);//显示绿灯
void RGB_BLUE(uint16_t Pixel_Len); //显示蓝灯
void RGB_WHITE(uint16_t Pixel_Len);//显示白灯void led_loop(void);#endif

ws2812b.c文件如下:

#include "ws2812b.h"
#include "tim.h"/*Some Static Colors------------------------------*/
const RGB_Color_TypeDef RED      = {255,0,0};   //显示红色RGB数据
const RGB_Color_TypeDef ORANGE   = {127,106,0};
const RGB_Color_TypeDef YELLOW   = {127,216,0};
const RGB_Color_TypeDef GREEN    = {0,255,0};
const RGB_Color_TypeDef CYAN     = {0,255,255};
const RGB_Color_TypeDef BLUE     = {0,0,255};
const RGB_Color_TypeDef PURPLE   = {238,130,238};
const RGB_Color_TypeDef BLACK    = {0,0,0};
const RGB_Color_TypeDef WHITE    = {255,255,255};
const RGB_Color_TypeDef MAGENTA  = {255,0,220};/*二维数组存放最终PWM输出数组,每一行24个
数据代表一个LED,最后一行24个0代表RESET码*/
uint32_t Pixel_Buf[Pixel_NUM+1][24];       /*
功能:设定单个RGB LED的颜色,把结构体中RGB的24BIT转换为0码和1码
参数:LedId为LED序号,Color:定义的颜色结构体
*/
void RGB_SetColor(uint8_t LedId,RGB_Color_TypeDef Color)
{uint8_t i; if(LedId > Pixel_NUM)return; //avoid overflow 防止写入ID大于LED总数for(i=0;i<8;i++) Pixel_Buf[LedId][i]   = ( (Color.G & (1 << (7 -i)))? (CODE_1):CODE_0 );//数组某一行0~7转化存放Gfor(i=8;i<16;i++) Pixel_Buf[LedId][i]  = ( (Color.R & (1 << (15-i)))? (CODE_1):CODE_0 );//数组某一行8~15转化存放Rfor(i=16;i<24;i++) Pixel_Buf[LedId][i] = ( (Color.B & (1 << (23-i)))? (CODE_1):CODE_0 );//数组某一行16~23转化存放B
}/*
功能:最后一行装在24个0,输出24个周期占空比为0的PWM波,作为最后reset延时,这里总时长为24*1.2=30us > 24us(要求大于24us)
*/
void Reset_Load(void)
{uint8_t i;for(i=0;i<24;i++){Pixel_Buf[Pixel_NUM][i] = 0;}
}/*
功能:发送数组
参数:(&htim1)定时器1,(TIM_CHANNEL_2)通道2,((uint32_t *)Pixel_Buf)待发送数组,(Pixel_NUM+1)*24)发送个数,数组行列相乘
*/
void RGB_SendArray(void)
{HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_2, (uint32_t *)Pixel_Buf,(Pixel_NUM+1)*24);
}/*
功能:显示红色
参数:Pixel_Len为显示LED个数
*/
void RGB_RED(uint16_t Pixel_Len)
{uint16_t i;for(i=0;i<Pixel_Len;i++)//给对应个数LED写入红色{RGB_SetColor(i,RED);}Reset_Load();RGB_SendArray();
}/*
功能:显示绿色
参数:Pixel_Len为显示LED个数
*/
void RGB_GREEN(uint16_t Pixel_Len)
{uint16_t i;for(i=0;i<Pixel_Len;i++)//给对应个数LED写入绿色{RGB_SetColor(i,GREEN);}Reset_Load();RGB_SendArray();
}/*
功能:显示蓝色
参数:Pixel_Len为显示LED个数
*/
void RGB_BLUE(uint16_t Pixel_Len)
{uint16_t i;for(i=0;i<Pixel_Len;i++)//给对应个数LED写入蓝色{RGB_SetColor(i,BLUE);}Reset_Load();RGB_SendArray();
}/*
功能:显示白色
参数:Pixel_Len为显示LED个数
*/
void RGB_WHITE(uint16_t Pixel_Len)
{uint16_t i;for(i=0;i<Pixel_Len;i++)//给对应个数LED写入白色{RGB_SetColor(i,WHITE);}Reset_Load();RGB_SendArray();
}//也可以继续添加其他颜色,和颜色变化函数等/*******************************************************************************/
/*                                  添加部分                                       *///显示指定颜色
static void rgb_show(uint32_t Pixel_Len, RGB_Color_TypeDef rgb)
{uint16_t i;for(i=0;i<Pixel_Len;i++){RGB_SetColor(i,rgb);}Reset_Load();RGB_SendArray();
}//颜色循环转换
static RGB_Color_TypeDef Wheel(uint8_t WheelPos)
{RGB_Color_TypeDef rgb;WheelPos = 255 - WheelPos;if (WheelPos < 85){rgb.R = 255 - WheelPos * 3;rgb.G = 0;rgb.B = WheelPos * 3;return rgb;}if (WheelPos < 170){WheelPos -= 85;rgb.R = 0;rgb.G = WheelPos * 3;rgb.B = 255 - WheelPos * 3;return rgb;}WheelPos -= 170;rgb.R = WheelPos * 3;rgb.G = 255 - WheelPos * 3;rgb.B = 0;return rgb;
}//彩虹呼吸灯
static void rainbow(uint8_t wait)
{uint32_t timestamp = HAL_GetTick();uint16_t i;static uint8_t j;static uint32_t next_time = 0;uint32_t flag = 0;if (next_time < wait){if ((uint64_t)timestamp + wait - next_time > 0)flag = 1;}else if (timestamp > next_time){flag = 1;}if (flag)    // && (timestamp - next_time < wait*5)){j++;next_time = timestamp + wait;for (i = 0; i < Pixel_NUM; i++){RGB_SetColor(i, Wheel((i + j) & 255));}}RGB_SendArray();
}//彩虹灯旋转
static void rainbowCycle(uint8_t wait)
{uint32_t timestamp = HAL_GetTick();uint16_t i;static uint8_t j;static uint32_t next_time = 0;static uint8_t loop = 0;if (loop == 0)next_time = timestamp;loop = 1;    //首次调用初始化if ((timestamp > next_time))    // && (timestamp - next_time < wait*5)){j++;next_time = timestamp + wait;for (i = 0; i < Pixel_NUM; i++){RGB_SetColor(i, Wheel(((i * 256 / (Pixel_NUM)) + j) & 255));}}RGB_SendArray();
}static uint8_t rainbow_change_flag = 0;
void led_loop(void)
{int i;rgb_show(8, BLACK);      HAL_Delay(300);for(i = 1; i <= 8 ;i++) { //红rgb_show(i, RED);        HAL_Delay(50);      }for(i = 1; i <= 8 ;i++) {   //橙rgb_show(i, ORANGE);     HAL_Delay(50);      }for(i = 1; i <= 8 ;i++) {   //黄rgb_show(i, YELLOW);     HAL_Delay(50);      }for(i = 1; i <= 8 ;i++) {   //绿rgb_show(i, GREEN);      HAL_Delay(50);      }for(i = 1; i <= 8 ;i++) {   //青rgb_show(i, CYAN);       HAL_Delay(50);      }for(i = 1; i <= 8 ;i++) {   //蓝rgb_show(i, BLUE);       HAL_Delay(50);      }for(i = 1; i <= 8 ;i++) {   //紫rgb_show(i, PURPLE);     HAL_Delay(50);      }HAL_TIM_Base_Start_IT(&htim3); //使能定时器中断->时间:1mswhile(1) {if(!rainbow_change_flag)rainbow(5);else rainbowCycle(2);}}//定时器3中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{/* Prevent unused argument(s) compilation warning */UNUSED(htim);/* NOTE : This function should not be modified, when the callback is needed,the HAL_TIM_PeriodElapsedCallback could be implemented in the user file*/static uint32_t time_counter = 0;if(htim->Instance == TIM3) {if(++time_counter == 10000) {    //10s后切换rainbow_change_flag = ~rainbow_change_flag;time_counter = 0;}}
}

彩灯流水灯

STM32 HAL库 PWM+DMA 驱动WS2812B彩灯(STM32F030F4P6)相关推荐

  1. STM32 HAL库 串口DMA接收不定长数据

    STM32 HAL库 串口DMA接收不定长数据 整体思路:我是用的CUBEMX软件生成的工程,使能了两个串口,串口2用来接收不定长的数据,串口1用来发送串口2接收到的数据:串口2我找了一个UBLOX卫 ...

  2. STM32 HAL库 串口DMA(收发)和STM32串口中断接收(接收时间管理机制)+ESP8266 wifi模组通信问题

    一.HAL库 串口 DMA+ESP8266模组通信问题 用STM32 HAL库串口的DMA发送和空闲中断接收处理数据,单片机发送AT指令给ESP8266 wifi模组问题:单片机连续几次给wifi模组 ...

  3. STM32 HAL库ADC+DMA(非定时器)代码和遇到的问题

    目录 一.整体说明 二.部分知识点预览 三.代码部分 四.遇到的问题及现象 (1)仿真进入错误 (2)非连续模式软件触发时adcbuf里面的数据不对 (3)HAL库的ADC DMA相关中断的嵌套实现 ...

  4. 沁恒CH579M使用PWM+DMA驱动WS2812B程序

    TMR1,TMR2 的强大功能: 首先咱们看看CH579M规格书,只有TMR1和TMR2支持DMA中断 先定义一个数组把数组的初始RAM地址和结束地址放在寄存器里,当前缓冲地址不管 DMA可以循环和不 ...

  5. 【春节歌曲回味 | STM32小音乐盒 】PWM+定时器驱动无源蜂鸣器(STM32 HAL库)

    l  STM32通过PWM与定时器方式控制无源蜂鸣器鸣响 l  STM32小音乐盒,歌曲进度条图形显示与百分比显示,歌曲切换 l  编程使用STM32 HAL库 l  IIC OLED界面编程,动画实 ...

  6. STM32 HAL库PID控制电机 第二章 TB6612FNG芯片驱动GB37-520电机

    STM32 HAL库PID控制电机 第二章 TB6612FNG芯片驱动GB37-520电机(HAL库) 1 电路图 2 TB6612简介 TB6612是双驱动,可同时驱动两个电机 STBY:接单片机的 ...

  7. STM32 HAL库IIC驱动

    1. STM32上IIC的一些争议 关于STM32的IIC驱动,网上有很多争论,究竟是使用STM32自带的硬件IIC还是用IO口和软件模拟IIC呢?下面这个图形象展示了这些争论.总结一些:ST为了规避 ...

  8. 借WS2812 PWM DMA驱动调试浅谈STM32调试思路

    借WS2812 PWM DMA驱动调试浅谈STM32调试思路 ​ 接触STM32差不多有4年了,在学校参加比赛时也需要进行各种调试工作,团队的配合也需要个人具有领域内快速定位与解决BUG的能力,前些日 ...

  9. STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片

    STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片 STM32基础工程生成 首先使用STM32CUBEMX生成STM32的基础工程,配置时钟到7 ...

最新文章

  1. leetcode 131. Palindrome Partitioning
  2. 关于oracle 安装下的LINUX系统参数的优化
  3. vue 导入element-ui css报错解决方法
  4. 人生的12个经典领悟
  5. 新浪云python示例_Python Web框架Flask中使用新浪SAE云存储实例
  6. python中_str_使用方法
  7. 【Python】base64模块对图片进行base64编码和解码
  8. 从问题出发,解密Oracle rdba结构
  9. 如何设置EditPlus保存时不生成bak文件
  10. pandas.read_csv() 详解与如何合适的读取行序号与列名
  11. SQLite之C++封装库CppSQLite使用方法
  12. Unity3D跑马灯脚本
  13. Java代码审计: ClassLoader应用
  14. PuTTY用户手册(十四)
  15. 微搭低代码Tab栏组件使用指南
  16. 6374. 【NOIP2019模拟2019.10.04】结界[生与死的境界]
  17. 关联分析(Apriori,FP-growth)
  18. ucos II任务管理之一:挂起任务
  19. 主流嵌入式操作系统(RTOS)有哪些?看看这14种
  20. 为什么你感觉Java难以入门?

热门文章

  1. 通用串行总线控制器:由于其配置信息(注册表中的)不完整或已损坏,Windows 无法启动这个硬件设备(代码 19
  2. 最好的芳华遇到你,余生都是你
  3. Linux中echo $命令的作用
  4. android tv二级菜单,android TV开发:弹出菜单实现
  5. 如何将mp4转为mp3音频?
  6. PHP 虚拟目录 虚拟主机 域名配置
  7. linux性能提升方法(整理)
  8. 通过组策略来防治U盘病毒
  9. 数据采集(四):用XPath爬取链家网房价数据
  10. php 开启soap扩展,php soap扩展开启与__soapCall使用问题