news 2026/1/11 22:09:03

【stm32简单外设篇】- 三色LED

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【stm32简单外设篇】- 三色LED

一、适用场景
适用场景:状态指示(颜色+亮度表示多种状态)、氛围灯/指示灯、简单人机交互(通过颜色反馈)、学习 PWM 与颜色混合、嵌入式灯光效果(呼吸灯、渐变、跑马灯)与多通道驱动练习。

二、器材清单

三色 LED 模组×1

STM32 开发板(带 TIM / PWM 能力)×1

若干杜邦线(母对母/公对母)×1组

三、工作原理(要点)

三色 LED 内部包含红 (R)、绿 (G)、蓝 (B) 三个发光二极管,分别通过不同比例点亮可混合出多种颜色(加法混色)。

通常用 PWM 控制每一路的占空比实现亮度调节(注意每色的亮度-人眼感知并非线性,若要求美观可做 gamma 校正)。

四、接线示意
GND → GND

标准库

RPA6

GPA7

BPA8

HAL库

RPB4

GPB5

BPB0

五、示例代码
标准库

#include "stm32f10x.h" #include "stdio.h" #include "bsp_SysTick.h" #include "adc_time.h" #include "breathing.h" #include "bsp_usart.h" #define TIM_arr (10-1) #define TIM_psc (72-1) #define TIM_ccr1 5 static void TIM1_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //设置该引脚为复用输出功能,输出TIM1 CH1的PWM脉冲波形 GPIOA.8 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM1_CH1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //设置该引脚为复用输出功能,输出TIM1 CH2的PWM脉冲波形 GPIOA.9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //TIM1_CH2 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //设置该引脚为复用输出功能,输出TIM1 CH3的PWM脉冲波形 GPIOA.10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //TIM1_CH3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //设置该引脚为复用输出功能,输出TIM1 CH4的PWM脉冲波形 GPIOA.11 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //TIM1_CH4 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } void pwm_init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //设置为复用推挽输出 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); TIM_TimeBaseInitStructure.TIM_Period=arr; TIM_TimeBaseInitStructure.TIM_Prescaler=psc; TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure); TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM2; TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable; TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High; TIM_OCInitStruct.TIM_Pulse=12; TIM_OC1Init(TIM3,&TIM_OCInitStruct); TIM_OCInitStruct.TIM_Pulse=24; TIM_OC2Init(TIM3,&TIM_OCInitStruct); TIM_OCInitStruct.TIM_Pulse=36; TIM_OC3Init(TIM3,&TIM_OCInitStruct); TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能预装载寄存器 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能预装载寄存器 TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能预装载寄存器 TIM_Cmd(TIM3,ENABLE); } static void TIM1_Model_Config(void) {TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // 开启定时器时钟,即内部时钟CK_INT=72M RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); /*--------------------时基结构体初始化-------------------------*/ // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 TIM_TimeBaseStructure.TIM_Period=TIM_arr; TIM_TimeBaseStructure.TIM_Prescaler= TIM_psc; // 驱动CNT计数器的时钟 = Fck_int/(psc+1) // 时钟分频因子 ,配置死区时间时需要用到 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //不分频 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;// 计数器计数模式,设置为向上计数 // 重复计数器的值,没用到不用管 TIM_TimeBaseStructure.TIM_RepetitionCounter=0; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);// 初始化定时器 /*-------------------------输出比较结构体初始化---------------------------------*/ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;// 配置为PWM模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 输出通道电平极性配置 TIM_OCInitStructure.TIM_Pulse = 5;// 设置占空比大小red TIM_OC1Init(TIM1, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);//使能TIM1在CCR1上的预装载寄存器 //ch2 PWM模式 TIM_OCInitStructure.TIM_Pulse = 0;// 设置占空比大小greed TIM_OC2Init(TIM1, &TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);//使能TIM1在CCR1上的预装载寄存器 //ch3 PWM模式 TIM_OCInitStructure.TIM_Pulse = 10;// 设置占空比大小blue TIM_OC3Init(TIM1, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);//使能TIM1在CCR1上的预装载寄存器 //ch4 PWM模式 TIM_OCInitStructure.TIM_Pulse = 0;// 设置占空比大小 TIM_OC4Init(TIM1, &TIM_OCInitStructure); TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);//使能TIM1在CCR1上的预装载寄存器 TIM_Cmd(TIM1, ENABLE); // 使能计数器 } void TIM1_Init(void) { TIM1_GPIO_Config(); TIM1_Model_Config(); } //int main(void) //{ // /* 高级定时器初始化 */ // TIM1_Init(); // // while(1) // { // // } //} int main() { int i,j,z; SysTick_Init(); USART_Config(); pwm_init(49,0); while(1) { i++; j--; z++; if(i>=40 || j<=0 | z>=40) { i=j=z=0; } TIM_SetCompare1(TIM3,50); TIM_SetCompare2(TIM3,50); TIM_SetCompare3(TIM3,50); Delay_us(500000); } // return 0; }

HAL库

/* TIM3 init function */ void MX_TIM3_Init(void) { /* USER CODE BEGIN TIM3_Init 0 */ /* USER CODE END TIM3_Init 0 */ TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; /* USER CODE BEGIN TIM3_Init 1 */ // 72000000/720/2000=50 1/50=20ms /* USER CODE END TIM3_Init 1 */ htim3.Instance = TIM3; htim3.Init.Prescaler = 200-1; htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 1024-1; htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_PWM_Init(&htim3) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM2; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM3_Init 2 */ /* USER CODE END TIM3_Init 2 */ HAL_TIM_MspPostInit(&htim3); } 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_USART1_UART_Init(); MX_TIM3_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);//定时器PWM初始化 HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);//定时器PWM初始化 HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);//定时器PWM初始化 HAL_TIM_Base_Start_IT(&htim4); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ /* */ pwm_output=1; while (1) { __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 1023); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0); HAL_Delay(500); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 1023); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0); HAL_Delay(500); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 1023); HAL_Delay(500); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 1023); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 1023); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0); HAL_Delay(500); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 1023); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 1023); HAL_Delay(500); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 1023); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 1023); HAL_Delay(500); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 1023); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 1023); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 1023); HAL_Delay(500); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 1023); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 512); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0); HAL_Delay(500); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 1023); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 512); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 768); HAL_Delay(500); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 512); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 1023); HAL_Delay(500); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 512); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 256); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0); HAL_Delay(500); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 512); // 50%占空比 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 768); HAL_Delay(500); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }

六、讲解视频

https://www.bilibili.com/video/BV1DmmoBYEXY/?spm_id_from=333.1387.upload.video_card.click&vd_source=f7dfe1b14f260b9cc3a146d2dbfd0719

https://www.bilibili.com/video/BV1dBmoBzEgZ/?spm_id_from=333.1387.upload.video_card.click&vd_source=f7dfe1b14f260b9cc3a146d2dbfd0719

https://www.bilibili.com/video/BV1RBmoBzEdp/?spm_id_from=333.1387.upload.video_card.click&vd_source=f7dfe1b14f260b9cc3a146d2dbfd0719

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/11 9:15:35

高效文件去重工具使用指南:从存储告急到系统优化的完整解决方案

还在为电脑存储空间频繁告急而烦恼吗&#xff1f;看着硬盘里堆积如山的重复文件却无从下手&#xff1f;文件去重工具正是解决这一痛点的专业利器。本文将带你采用"诊断→清理→优化"的全新思路&#xff0c;系统掌握文件去重技巧&#xff0c;实现存储空间的彻底优化。…

作者头像 李华
网站建设 2026/1/11 15:16:58

PyBaMM参数调优实战:从电压异常到精准仿真的解决之道

"为什么我的电池模型一改参数就崩&#xff1f;"这恐怕是每个PyBaMM用户在参数调优过程中最常发出的疑问。作为Python电池数学建模的利器&#xff0c;PyBaMM提供了丰富的参数接口&#xff0c;但参数间的微妙平衡往往让初学者踩坑不断。今天&#xff0c;我们就来彻底解…

作者头像 李华
网站建设 2026/1/8 10:09:13

HTTP 协议发展整理

每次发展都是在优化和解决上一代协议存在的问题&#xff0c;并拓展新功能。 HTTP/0.9&#xff08;1991 年&#xff09; HTTP/0.9 是最初的版本&#xff0c;功能非常简单&#xff1a; 只能请求页面&#xff1a;规定服务器只能发送 HTML 和字符串。单一请求方法&#xff1a;只…

作者头像 李华
网站建设 2026/1/8 8:08:10

AMI医学图像处理工具高效入门指南:轻松掌握3D医学影像分析

AMI医学图像处理工具高效入门指南&#xff1a;轻松掌握3D医学影像分析 【免费下载链接】ami AMI Medical Imaging (AMI) JS ToolKit 项目地址: https://gitcode.com/gh_mirrors/am/ami 在数字医疗快速发展的今天&#xff0c;医学图像处理技术正成为临床诊断和科研分析的…

作者头像 李华
网站建设 2026/1/7 12:49:07

CREO到URDF转换终极教程:机器人仿真的完美桥梁

还在为手动编写URDF文件而烦恼吗&#xff1f;&#x1f914; creo2urdf工具将彻底改变你的机器人开发工作流程&#xff01;这款智能转换器能够自动解析CREO机制模型&#xff0c;生成标准的URDF格式&#xff0c;让CAD设计与机器人仿真实现无缝对接。✨ 【免费下载链接】creo2urdf…

作者头像 李华
网站建设 2026/1/8 6:11:06

开源医学图像处理工具终极指南:从零构建3D可视化应用

开源医学图像处理工具终极指南&#xff1a;从零构建3D可视化应用 【免费下载链接】ami AMI Medical Imaging (AMI) JS ToolKit 项目地址: https://gitcode.com/gh_mirrors/am/ami 在数字化医疗快速发展的今天&#xff0c;如何快速搭建专业的医学图像处理系统成为许多开发…

作者头像 李华