使用PWM来个呼吸灯.先来点理论知识:
什么是PWM 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。PWM工作原理SMT32F1系列共有8个定时器:高级定时器(TIM1、TIM8);通用定时器(TIM2、TIM3、TIM4、TIM5);基本定时器(TIM6、TIM7)。SMT32F4系列共有15个定时器:高级定时器(TIM1、TIM8);通用定时器(TIM2、TIM3、TIM4、TIM5、TIM9~TIM14);基本定时器(TIM6、TIM7)。STM32的每个通用定时器都有独立的4个通道可以用来作为:输入捕获、输出比较、PWM输出、单脉冲模式输出等。STM32的定时器除了TIM6和TIM7(基本定时器)之外,其他的定时器都可以产生PWM输出。其中,高级定时器TIM1、TIM8可以同时产生7路PWM输出。
开发板下面照还Arduino兼容接口:
PWM的工作模式: PWM模式1(向上计数) :计数器从0计数加到自动重装载值(TIMx_ARR),然后重新从0开始计数,并且产生一个计数器溢出事件 PWM模式2(向下计数) :计数器从自动重装载值(TIMx_ARR)减到0,然后重新从重装载值(TIMx_ARR)开始递减,并且产生一个计数器溢出事件 设置寄存器TIMx_CCMR1的OC1M[2:0]位来确定PWM的输出模式: PWM模式1:在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。 PWM模式2:在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。
参考程序的方向:
在主程序中,编写代码来控制PWM的占空比,以实现呼吸灯效果。这通常涉及到在定时器中断服务例程中更新PWM的占空比。
为了实现呼吸效果,可以设定一个变量(如pwm_value)来表示PWM的占空比,并在每个定时器中断周期中增加或减少该变量的值。当pwm_value达到最大值或最小值时,改变增加或减少的方向。
使用HAL库中的函数(如__HAL_TIM_SET_COMPARE)来设置TIM3_CH2的占空比。
参考示例:
while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ while (pwmVal< 500) { pwmVal++; __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, pwmVal); //修改比较值,修改占空比 // TIM3->CCR1 = pwmVal; 与上方相同 HAL_Delay(1); } while (pwmVal) { pwmVal--; __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, pwmVal); //修改比较值,修改占空比 // TIM3->CCR1 = pwmVal; 与上方相同 HAL_Delay(1); } HAL_Delay(200); /* USER CODE END 3 */ }
详细的代码示例:
#include "stm32u5xx_hal.h" // 假设你已经使用STM32CubeMX配置了一个PWM通道(例如TIM2_CH1) TIM_HandleTypeDef htim2; // 假设这是你的PWM定时器句柄 uint16_t pwm_value = 0; // PWM占空比初始值 int8_t direction = 1; // 控制PWM值增加或减少的方向 // 定时器中断服务例程(ISR) void TIM2_IRQHandler(void) { HAL_TIM_IRQHandler(&htim2); } // 定时器周期结束回调 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { // 更新PWM值以实现呼吸效果 pwm_value += direction; if (pwm_value == 0 || pwm_value == htim2.Init.Period) { direction = -direction; // 改变方向 } __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm_value); // 更新PWM通道1的占空比 } } // 主函数或其他初始化函数中的代码 int main(void) { // HAL库初始化等代码... // 初始化PWM定时器 HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // 启动定时器中断 HAL_TIM_Base_Start_IT(&htim2); // 主循环或其他逻辑... // 无限循环 while (1) { // 你的主循环代码... } }
LED的简单GPIO驱动改成PWM方式的呼吸灯。
选择PC7驱动的GREEN绿色LED。
CUBE配置:
定时器3
下面是自己写的代码:
// 循环,当pwmVal小于500时执行 while (pwmVal < 500) { // pwmVal递增 pwmVal++; // 使用HAL库函数设置TIM3的PWM比较值,从而改变PWM占空比 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, pwmVal); // 注释掉的代码与上一行功能相同,直接操作CCR1寄存器来设置比较值 // TIM3->CCR1 = pwmVal; // 与上方相同 // 延时1毫秒 HAL_Delay(1); } // 循环,当pwmVal大于0时执行 while (pwmVal) { // pwmVal递减 pwmVal--; // 使用HAL库函数设置TIM3的PWM比较值,从而改变PWM占空比 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, pwmVal); // 注释掉的代码与上一行功能相同,直接操作CCR1寄存器来设置比较值 // TIM3->CCR1 = pwmVal; // 与上方相同 // 延时1毫秒 HAL_Delay(1); } // USER CODE END 3 标志结束 /* USER CODE END 3 */ // 定义TIM_MasterConfigTypeDef结构体变量,用于TIM主从模式配置 TIM_MasterConfigTypeDef sMasterConfig = {0}; // 定义TIM_OC_InitTypeDef结构体变量,用于PWM输出通道配置 TIM_OC_InitTypeDef sConfigOC = {0}; // USER CODE BEGIN TIM3_Init 1 标志开始 /* USER CODE BEGIN TIM3_Init 1 */ // USER CODE END TIM3_Init 1 标志结束 /* USER CODE END TIM3_Init 1 */ // 初始化htim3结构体,设置TIM3的参数 htim3.Instance = TIM3; htim3.Init.Prescaler = PRESCALER_VALUE; // 设置预分频值 htim3.Init.CounterMode = TIM_COUNTERMODE_UP; // 设置计数器模式为向上计数 htim3.Init.Period = PERIOD_VALUE; // 设置自动重装载寄存器周期的值 htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 设置时钟分频因子 htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 设置是否允许在运行时更改自动重载寄存器的值 // 调用HAL_TIM_PWM_Init函数初始化TIM3的PWM功能 if (HAL_TIM_PWM_Init(&htim3) != HAL_OK) { // 如果初始化失败,调用错误处理函数 Error_Handler(); } // 配置TIM3的主输出触发源和主从模式 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; // 调用HAL_TIMEx_MasterConfigSynchronization函数配置TIM3的主从同步 if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) { // 如果配置失败,调用错误处理函数 Error_Handler(); } // 配置TIM3的PWM通道2 sConfigOC.OCMode = TIM_OCMODE_PWM1; // 设置PWM模式 sConfigOC.Pulse = PULSE_VALUE; // 设置PWM脉冲宽度 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 设置PWM输出极性为高 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 设置PWM快速模式为禁用 // 调用HAL_TIM_PWM_ConfigChannel函数配置TIM3的PWM通道2 if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) { // 如果配置失败,调用错误处理函数 Error_Handler(); } // USER CODE BEGIN TIM3_Init 2 标志开始 /* USER CODE BEGIN TIM3_Init 2 */ // USER CODE END TIM3_Init 2 标志结束 /* USER CODE END TIM3_Init 2 */ // 调用HAL库提供的函数完成TIM3的Msp层初始化 HAL_TIM_MspPostInit(&htim3);
使用STM32 HAL库来配置TIM3的PWM输出,以及如何通过递增和递减PWM值来模拟呼吸灯效果。
逻辑分析仪采样:
总结:
功能总结初始化:
定义了PWM占空比的初始值pwmVal为0。
定义了控制PWM值增加或减少的方向变量direction为1(表示初始时PWM值将增加)。
初始化了一个定时器(假设为TIM3),并设置了相关的参数,如预分频值、计数模式、周期值等。
配置了TIM3的中断,包括设置中断优先级和使能中断。
启动了定时器的中断功能(HAL_TIM_Base_Start_IT)和PWM通道(HAL_TIM_PWM_Start)。
定时器中断服务例程:
当TIM3的更新中断被触发时,执行TIM3_IRQHandler中断服务例程。
在中断服务例程中,首先通过HAL库函数处理TIM3的中断。
检查TIM3的更新中断标志位是否被设置。
如果更新中断标志位被设置,则清除该标志位,并更新PWM占空比的值。
更新PWM占空比时,根据direction变量的值增加或减少pwmVal的值。
当pwmVal达到预设的最大值(PERIOD_VALUE)或最小值(0)时,切换direction变量的值以改变PWM值的增减方向。
通过HAL库函数设置TIM3的通道2的比较值,从而改变PWM的占空比。
呼吸效果:
由于PWM占空比的值在最大值和最小值之间来回变化,并且变化的速率也在改变(由direction变量控制),因此连接到TIM3通道2的PWM输出将产生类似呼吸灯的效果。