STM32驱动全彩LED灯模块WS2812

WS2812全彩LED灯模块系列,可以进行级联实现灯带的效果,MCU端通过一个管脚可以控制所有级联的LED灯的不同发光颜色显示。

级联电路

WS2811(未集成LED)的级联电路如下所示:

WS2812(集成LED)的级联电路如下所示:

STM32是3.3V供电芯片,输出Push-Pull模式只有3.3V,WS2812采用5V供电,输入Vih为0.7*5=3.5V高于3.3V,所以STM32连接WS2812时要采用有FT耐5V电压的管脚,采用Open-drain的输出方式,并外部上拉1K电阻,实现与第一个WS2812的DI的连接,对于后面级联的WS2812,由前一级DO驱动5V信号输出,直接DO连接DI即可。
实现STM32驱动控制WS282的时序信号,由于时序输出翻转延迟达到了百纳秒级,需要硬件资源驱动的管脚输出,可以用SPI总线的MOSI实现。因为MCU的SPI总线资源较少,定时器资源相对较多,因此这里介绍采用TIM PWM方式的驱动实现。
以STM32F103C6T6为例,选择同时具有FT和TIM PWM输出特性的管脚,这里选择PB10:

连接关系简图:

时序说明

  1. 驱动器(STM32)输出RESET指示信号(>280us, 低电平有效), 此信号为双目的,一则WS2812的DI输入识别到有大于280us的低电平信号, 则将之前配置的数据驱动输出给三色/三个LED。二则进入到等待状态,等待下一次的数据配置信号到来。
  2. 数据配置信号为24个位一组,对应R, G, B三色各256级深度,即R, G, B各用一个字节/8位表示,如下所示:

    注意24位对应3个字节并非是R, G, B顺序输出,而是G, R, B顺序输出,每个字节是高位在前进行发送。
  3. 每个位的发送时序都是由高低电平组成,由高电平和低电平的相对时长判断该位是0还是1:

    高电平和低电平有时长范围要求:

    可以看出主要先规划短电平时长和宽电平时长,这里基于STM32F103的72MHz,可以在TIM分频出对应125ns的计数周期,所以选择短电平时长为125 * 3 = 375ns, 选择宽电平时长为125 * 12 = 1500ns = 1.5us,后面进行工程配置和代码编写。

STM32工程配置

这里以STM32CUBEIDE开发平台对STM32F103C6T6芯片进行配置为例,首先建立基本工程并配置时钟主频为72MHz:


然后配置PB10为TIM PWM输出的Open-drain模式:

配置TIM时钟为8MHz,并配置PWM的参数:

这里需要注意,Output compare preload需要配置为Enable, 因为后面的时序逻辑里,会在当前周期的PWM输出时修改PWM输出的占空比,而这个占空比修改的施行是在下一个周期,并不再当前周期。
保存并产生基本工程代码:

STM32工程代码

驱动逻辑的实现主要是通过启动TIM PWM输出时,在不同的时刻控制PWM输出的占空比,如RESET指示信号的输出即为控制输出占空比为0,而逻辑1和逻辑0信号的输出则是在每个逻辑输出前调整PWM占空比以对应逻辑1和逻辑0。

代码里用到的纳秒级延时介绍:
STM32 纳秒级延时 (ns delay) 的指令延时实现方式及测定
代码里用到的半微秒级延时介绍:
STM32 HAL us delay(微秒延时)的指令延时实现方式及优化

代码实现单个LED模块驱动,需要驱动多个LED模块, 进行驱动函数扩展即可。完整的代码如下:

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** Copyright (c) 2022 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes *//* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
__IO float semiusDelayBase;
void PY_semiusDelayTest(void)
{__IO uint32_t firstms, secondms;
__IO uint32_t counter = 0;firstms = HAL_GetTick()+1;secondms = firstms+1;while(uwTick!=firstms) ;while(uwTick!=secondms) counter++;semiusDelayBase = ((float)counter)/2000;
}void PY_Delay_semius_t(uint32_t Delay)
{__IO  uint32_t delayReg;
__IO  uint32_t semiusNum = (uint32_t)(Delay*semiusDelayBase);delayReg = 0;while(delayReg!=semiusNum) delayReg++;
}void PY_semiusDelayOptimize(void)
{__IO  uint32_t firstms, secondms;
__IO  float coe = 1.0;firstms = HAL_GetTick();PY_Delay_semius_t(2000000) ;secondms = HAL_GetTick();coe = ((float)1000)/(secondms-firstms);semiusDelayBase = coe*semiusDelayBase;
}void PY_Delay_semius(uint32_t Delay)
{__IO  uint32_t delayReg;uint32_t msNum = Delay/2000;uint32_t semiusNum = (uint32_t)((Delay%2000)*semiusDelayBase);if(msNum>0) HAL_Delay(msNum);delayReg = 0;while(delayReg!=semiusNum) delayReg++;
}
/* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;/* USER CODE BEGIN PV */
#define TX_0 __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 3)
#define TX_1 __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 12)
#define TX_RST __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 0)void PY_RGB_TX_Init(void)
{__HAL_TIM_SetCounter(&htim2, 0);TX_RST;HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);PY_Delay_semius_t(600);
}#define timing_delay {ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;ns_delay >>= 1;}
void PY_RGB_TX_24bits(uint8_t R, uint8_t G, uint8_t B) //Written by Pegasus Yu in 2022
{ //Data transmit in order of GRB, high bit data at first__IO uint32_t ns_delay = 0x55555555;__HAL_TIM_SetCounter(&htim2, 0);if((G<<0)&0x80) TX_1;else TX_0;timing_delayif((G<<1)&0x80) TX_1;else TX_0;timing_delayif((G<<2)&0x80) TX_1;else TX_0;timing_delayif((G<<3)&0x80) TX_1;else TX_0;timing_delayif((G<<4)&0x80) TX_1;else TX_0;timing_delayif((G<<5)&0x80) TX_1;else TX_0;timing_delayif((G<<6)&0x80) TX_1;else TX_0;timing_delayif((G<<7)&0x80) TX_1;else TX_0;timing_delayif((R<<0)&0x80) TX_1;else TX_0;timing_delayif((R<<1)&0x80) TX_1;else TX_0;timing_delayif((R<<2)&0x80) TX_1;else TX_0;timing_delayif((R<<3)&0x80) TX_1;else TX_0;timing_delayif((R<<4)&0x80) TX_1;else TX_0;timing_delayif((R<<5)&0x80) TX_1;else TX_0;timing_delayif((R<<6)&0x80) TX_1;else TX_0;timing_delayif((R<<7)&0x80) TX_1;else TX_0;timing_delayif((B<<0)&0x80) TX_1;else TX_0;timing_delayif((B<<1)&0x80) TX_1;else TX_0;timing_delayif((B<<2)&0x80) TX_1;else TX_0;timing_delayif((B<<3)&0x80) TX_1;else TX_0;timing_delayif((B<<4)&0x80) TX_1;else TX_0;timing_delayif((B<<5)&0x80) TX_1;else TX_0;timing_delayif((B<<6)&0x80) TX_1;else TX_0;timing_delayif((B<<7)&0x80) TX_1;else TX_0;PY_Delay_semius_t(1);TX_RST;PY_Delay_semius_t(600);}
/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @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_TIM2_Init();/* USER CODE BEGIN 2 */PY_semiusDelayTest();PY_semiusDelayOptimize();PY_RGB_TX_Init();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){PY_RGB_TX_24bits(255, 0, 0);PY_Delay_semius_t(4000000);PY_RGB_TX_24bits(0, 255, 0);PY_Delay_semius_t(4000000);PY_RGB_TX_24bits(0, 0, 255);PY_Delay_semius_t(4000000);PY_RGB_TX_24bits(127, 0, 127);PY_Delay_semius_t(4000000);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}
}/*** @brief TIM2 Initialization Function* @param None* @retval None*/
static void MX_TIM2_Init(void)
{/* USER CODE BEGIN TIM2_Init 0 *//* USER CODE END TIM2_Init 0 */TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_OC_InitTypeDef sConfigOC = {0};/* USER CODE BEGIN TIM2_Init 1 *//* USER CODE END TIM2_Init 1 */htim2.Instance = TIM2;htim2.Init.Prescaler = 8;htim2.Init.CounterMode = TIM_COUNTERMODE_UP;htim2.Init.Period = 14;htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim2) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK){Error_Handler();}if (HAL_TIM_PWM_Init(&htim2) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK){Error_Handler();}sConfigOC.OCMode = TIM_OCMODE_PWM1;sConfigOC.Pulse = 3;sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM2_Init 2 *//* USER CODE END TIM2_Init 2 */HAL_TIM_MspPostInit(&htim2);}/*** @brief GPIO Initialization Function* @param None* @retval None*/
static void MX_GPIO_Init(void)
{/* GPIO Ports Clock Enable */__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief  This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef  USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

注意MCU在不同主频下,#define timing_delay 后的 ns_delay >>= 1; 数量应做适应性调整以满足纳秒级时序要求。

STM32工程测试效果

上述代码实现4个延时的循环显示(包括典型的红色,绿色,蓝色),时序波形测试及颜色显示效果如下:







例程下载

STM32F103C6T6驱动W2812例程

–End–

STM32驱动全彩LED灯模块WS2812相关推荐

  1. STM32单片机驱动全彩LED模块遍历百万种颜色

    一.使用硬件 分享一个趣味的实验,单片机PWM驱动全彩LED模块,快速遍历100万种颜色. 单片机为STM32F103C8T6,三色LED模块如下图(图片来源于网络) 二.STM32CubeMx配置 ...

  2. 实战microPython(05)-WS2812全彩LED灯串的控制

    实战microPython(05)-WS2812全彩LED灯串的控制 David Zou 2018-09-17 在喜庆的节日中,我们经常使用彩灯串来增加节日的气氛.最早期的使用的是单色的小灯珠,只有亮 ...

  3. STM32F103VET6实现全彩LED灯

    全彩LED灯的实现 文章目录 全彩LED灯的实现 前言 一.相关知识 1.全彩 LED 灯简介 2.硬件简介 二.代码实现 1.编程要点 2.LED灯硬件相关宏定义 2.初始化 GPIO 3.定时器 ...

  4. 使用Arduino开发板点亮RGB全彩LED灯

    使用Arduino开发板点亮RGB全彩LED灯 我们将了解什么是RGB全彩LED灯以及如何使用Arduino开发板点亮它. 什么是RGB LED灯? RGB LED灯可以通过混合红色.绿色和蓝色这三种 ...

  5. 利用Arduino开发板制作RGB全彩LED灯

    制作所需组件 RGB LED灯 1 个 220欧电阻 3 个 Arduino开发板 1 块 面包 1 块 跳线 4 根 电路原理图 电路图搭建过程 将RGB LED灯接入面包板 将3个电阻的一端引脚分 ...

  6. esp32原理图设计_第十一章 ESP32的PWM全彩LED灯显示

    学习目的及目标 · 学习ESP32 的ADC功能的配置 · 掌握两路ADC采样程序 ESP32的ADC简介(原文) ESP32 集成了 2 个 12 位逐次逼近模数转换器 (SARADC),由 5 个 ...

  7. kotlin设置按钮不可点击_全彩LED显示屏软件空点功能如何设置、使用?

    全彩LED显示屏的显示功能得以实现,所使用的软件功不可没.可以说是显示屏所展现的一切的效果和特性,都得归功于软件和显示屏设备.全彩LED显示屏软件空点功能如何设置.使用,你们知道吗?下面景信科技小编为 ...

  8. ESP32从零开始系列之玩转RGB全彩LED

    ESP32从零开始系列, 适合没有基础的各位工程师, 愿作为钥匙替各位打开ESP32开发的大门. ESP32从零开始系列之玩转RGB全彩LED 一.导入项目到Eclipse 二.源码分析 三.瞎改 四 ...

  9. 01. 全彩RGB LED灯模块使用教程

    全彩RGB LED灯模块使用教程 (适用于Arduino,micro:bit等常见单片机) 文章目录 全彩RGB LED灯模块使用教程 RGB灯模块简介 一.参数介绍 二.使用步骤 1.引脚说明 2. ...

最新文章

  1. sql server 2008 修改sa密码
  2. 如何设计一个高性能CPU?
  3. Windows之建立C++开发环境
  4. Dubbo搭建HelloWorld-搭建服务提供者与服务消费者并完成远程调用(附代码下载)
  5. 打基础和俄罗斯方块的关系
  6. 51php 数据不同步,php避免循环查询数据库优化一对多查询
  7. mysql 恢复空密码_mysql 找回密码
  8. 修改数据库表数据的办法
  9. cocos2dx 云彩特效
  10. LINUX安装C#开发环境
  11. asp.net mvc bundle中数组超出索引
  12. swift5 修改Accessibility order读取的顺序
  13. java模拟洗衣机程序,JAVA洗衣机仿真程序实验报告及代码
  14. 英文网站不用愁,必应在线翻译插件解烦忧
  15. 手把手教你搭建Android开发环境
  16. java 微信小程序 在线学习系统app
  17. 数据结构java实验_20172301 《Java软件结构与数据结构》实验一报告
  18. 小程序开发框架_mpvue(六)卡通照片的实现思路
  19. 2020北航计算机夏令营机试题目个人理解
  20. 最近设计的一个无人机app的界面

热门文章

  1. AIX系统月维护查什么(一)
  2. 快收藏,2023有这些财务分析模板就够了
  3. 贪心算法适用条件_五大常用算法之三:贪心算法
  4. java jdbc excel_详解poi+springmvc+springjdbc导入导出excel实例
  5. Qt图形视图框架:将自定义图形项放入布局
  6. PyQt5 - QSS
  7. javaActiveX控件使用
  8. 气象绘图软件Panoply使用教程 (不定时更新)
  9. Asset Store上常用的40个Unity插件汇总——进阶开发者必备Unity插件
  10. 时间的函数Sleep,clock,GetTickCount,QueryPerformanceCounter