news 2026/4/23 19:39:04

【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/4/19 16:04:36

解锁机器人仿真新姿势:CREO转URDF的5分钟快速上手指南 [特殊字符]

还在为机器人仿真中的模型转换烦恼吗&#xff1f;&#x1f914; CREO转URDF其实比你想象的简单&#xff01;creo2urdf这款实用工具能让你的CAD设计在5分钟内变身标准URDF模型&#xff0c;为机器人开发插上翅膀。 【免费下载链接】creo2urdf Generate URDF models from CREO mec…

作者头像 李华
网站建设 2026/4/18 9:51:40

大模型推理服务SLA保障:从TensorRT配置入手

大模型推理服务SLA保障&#xff1a;从TensorRT配置入手 在当今AI应用加速落地的背景下&#xff0c;大语言模型&#xff08;LLM&#xff09;正广泛应用于智能客服、内容生成、搜索推荐等关键业务场景。然而&#xff0c;一个现实挑战摆在工程团队面前&#xff1a;如何在高并发请求…

作者头像 李华
网站建设 2026/4/18 23:01:52

Keil5破解工具下载来源可靠性评估

为什么我不再碰“Keil5破解”&#xff1f;一位嵌入式工程师的血泪反思 几年前&#xff0c;我为了赶一个毕业设计项目&#xff0c;在搜索引擎里输入了“Keil5破解工具下载”。三分钟后&#xff0c;我从某个挂着“绿色软件、无毒免杀”标签的小网站上下载了一个名为 Keil5_UV4_…

作者头像 李华
网站建设 2026/4/22 23:39:10

手把手教程:Multisim元件库下载后如何正确安装

手把手教程&#xff1a;Multisim元件库下载后如何正确安装 你是不是也遇到过这种情况——在用 Multisim 画电路图时&#xff0c;想找个常用的芯片&#xff08;比如 STM32 的电源管理模块或 TI 新出的 LDO&#xff09;&#xff0c;结果翻遍了“Sources”和“Power”分类都找不到…

作者头像 李华
网站建设 2026/4/21 17:43:42

PyVRP终极指南:多行程车辆路径规划与智能调度方案

PyVRP终极指南&#xff1a;多行程车辆路径规划与智能调度方案 【免费下载链接】PyVRP Open-source, state-of-the-art vehicle routing problem solver in an easy-to-use Python package. 项目地址: https://gitcode.com/gh_mirrors/py/PyVRP 在现代物流配送和运输管理…

作者头像 李华
网站建设 2026/4/23 14:42:57

7大实用技巧让胡桃工具箱成为你原神游戏的得力助手

7大实用技巧让胡桃工具箱成为你原神游戏的得力助手 【免费下载链接】Snap.Hutao 实用的开源多功能原神工具箱 &#x1f9f0; / Multifunctional Open-Source Genshin Impact Toolkit &#x1f9f0; 项目地址: https://gitcode.com/GitHub_Trending/sn/Snap.Hutao 你是否…

作者头像 李华