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

一、适用场景

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

二、器材清单

三色 LED 模组×1

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

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

三、工作原理(要点)

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

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

四、接线示意
GND → GND

标准库

R→ PA6

G→ PA7

B→ PA8

HAL库

R→ PB4

G→ PB5

B→ PB0

五、示例代码

标准库

cpp 复制代码
#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库

cpp 复制代码
/* 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

相关推荐
d111111111d2 小时前
STM32平衡车测试,定时中断读取速度
笔记·stm32·单片机·嵌入式硬件·学习·模块测试
hope_wisdom2 小时前
C/C++数据结构之队列基础
c语言·数据结构·c++·队列·queue
会员果汁2 小时前
算法-拓扑排序-C
c语言·开发语言·算法
Dillon Dong3 小时前
从C到Simulink:什么是MATLAB_MEX_FILE 宏,如何阻挡STM32 HAL 头文件
c语言·stm32·matlab
Darken033 小时前
基于STM32---编码器测速(利用GPIO模拟脉冲信号)
人工智能·stm32·串口助手·gpio模拟编码器
会员果汁3 小时前
算法-并查集-C
c语言·开发语言·算法
电子工程师-C514 小时前
基于51单片机的交通灯远程控制系统
单片机·嵌入式硬件·51单片机
脏脏a4 小时前
链式存储范式下的二叉树:基础操作实现解析
c语言·数据结构·算法·二叉树
国科安芯5 小时前
低轨卫星边缘计算节点的抗辐照MCU选型分析
人工智能·单片机·嵌入式硬件·架构·边缘计算·安全威胁分析·安全性测试