STM32驱动全彩LED灯模块WS2812
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:
连接关系简图:
时序说明
- 驱动器(STM32)输出RESET指示信号(>280us, 低电平有效), 此信号为双目的,一则WS2812的DI输入识别到有大于280us的低电平信号, 则将之前配置的数据驱动输出给三色/三个LED。二则进入到等待状态,等待下一次的数据配置信号到来。
- 数据配置信号为24个位一组,对应R, G, B三色各256级深度,即R, G, B各用一个字节/8位表示,如下所示:
注意24位对应3个字节并非是R, G, B顺序输出,而是G, R, B顺序输出,每个字节是高位在前进行发送。 - 每个位的发送时序都是由高低电平组成,由高电平和低电平的相对时长判断该位是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相关推荐
- STM32单片机驱动全彩LED模块遍历百万种颜色
一.使用硬件 分享一个趣味的实验,单片机PWM驱动全彩LED模块,快速遍历100万种颜色. 单片机为STM32F103C8T6,三色LED模块如下图(图片来源于网络) 二.STM32CubeMx配置 ...
- 实战microPython(05)-WS2812全彩LED灯串的控制
实战microPython(05)-WS2812全彩LED灯串的控制 David Zou 2018-09-17 在喜庆的节日中,我们经常使用彩灯串来增加节日的气氛.最早期的使用的是单色的小灯珠,只有亮 ...
- STM32F103VET6实现全彩LED灯
全彩LED灯的实现 文章目录 全彩LED灯的实现 前言 一.相关知识 1.全彩 LED 灯简介 2.硬件简介 二.代码实现 1.编程要点 2.LED灯硬件相关宏定义 2.初始化 GPIO 3.定时器 ...
- 使用Arduino开发板点亮RGB全彩LED灯
使用Arduino开发板点亮RGB全彩LED灯 我们将了解什么是RGB全彩LED灯以及如何使用Arduino开发板点亮它. 什么是RGB LED灯? RGB LED灯可以通过混合红色.绿色和蓝色这三种 ...
- 利用Arduino开发板制作RGB全彩LED灯
制作所需组件 RGB LED灯 1 个 220欧电阻 3 个 Arduino开发板 1 块 面包 1 块 跳线 4 根 电路原理图 电路图搭建过程 将RGB LED灯接入面包板 将3个电阻的一端引脚分 ...
- esp32原理图设计_第十一章 ESP32的PWM全彩LED灯显示
学习目的及目标 · 学习ESP32 的ADC功能的配置 · 掌握两路ADC采样程序 ESP32的ADC简介(原文) ESP32 集成了 2 个 12 位逐次逼近模数转换器 (SARADC),由 5 个 ...
- kotlin设置按钮不可点击_全彩LED显示屏软件空点功能如何设置、使用?
全彩LED显示屏的显示功能得以实现,所使用的软件功不可没.可以说是显示屏所展现的一切的效果和特性,都得归功于软件和显示屏设备.全彩LED显示屏软件空点功能如何设置.使用,你们知道吗?下面景信科技小编为 ...
- ESP32从零开始系列之玩转RGB全彩LED
ESP32从零开始系列, 适合没有基础的各位工程师, 愿作为钥匙替各位打开ESP32开发的大门. ESP32从零开始系列之玩转RGB全彩LED 一.导入项目到Eclipse 二.源码分析 三.瞎改 四 ...
- 01. 全彩RGB LED灯模块使用教程
全彩RGB LED灯模块使用教程 (适用于Arduino,micro:bit等常见单片机) 文章目录 全彩RGB LED灯模块使用教程 RGB灯模块简介 一.参数介绍 二.使用步骤 1.引脚说明 2. ...
最新文章
- sql server 2008 修改sa密码
- 如何设计一个高性能CPU?
- Windows之建立C++开发环境
- Dubbo搭建HelloWorld-搭建服务提供者与服务消费者并完成远程调用(附代码下载)
- 打基础和俄罗斯方块的关系
- 51php 数据不同步,php避免循环查询数据库优化一对多查询
- mysql 恢复空密码_mysql 找回密码
- 修改数据库表数据的办法
- cocos2dx 云彩特效
- LINUX安装C#开发环境
- asp.net mvc bundle中数组超出索引
- swift5 修改Accessibility order读取的顺序
- java模拟洗衣机程序,JAVA洗衣机仿真程序实验报告及代码
- 英文网站不用愁,必应在线翻译插件解烦忧
- 手把手教你搭建Android开发环境
- java 微信小程序 在线学习系统app
- 数据结构java实验_20172301 《Java软件结构与数据结构》实验一报告
- 小程序开发框架_mpvue(六)卡通照片的实现思路
- 2020北航计算机夏令营机试题目个人理解
- 最近设计的一个无人机app的界面
热门文章
- AIX系统月维护查什么(一)
- 快收藏,2023有这些财务分析模板就够了
- 贪心算法适用条件_五大常用算法之三:贪心算法
- java jdbc excel_详解poi+springmvc+springjdbc导入导出excel实例
- Qt图形视图框架:将自定义图形项放入布局
- PyQt5 - QSS
- javaActiveX控件使用
- 气象绘图软件Panoply使用教程 (不定时更新)
- Asset Store上常用的40个Unity插件汇总——进阶开发者必备Unity插件
- 时间的函数Sleep,clock,GetTickCount,QueryPerformanceCounter