【STM32】定时器与PWM的LED控制
一. 探究目的
深入了解STM32定时器原理,掌握脉宽调制pwm生成方法。
二. 探究内容
使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。
接上,采用定时器PWM模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整占空比变化到一个满意效果;使用Keil虚拟示波器,观察 PWM输出波形。
三. 原理探究
3.1 定时器
定时器需要用到计数器,计数器的计数时间周期是固定的,因此到了一定时间只要用计数值*计数时间周期,就能得到一个时间段,这个时间段就是我们定的时间(这就是定时器了)。
3.1.1 STM32定时器
STM32定时器种类多,功能强大,这些定时器完全独立、互不干扰,可以同步操作。
其中有两个比较特殊的定时器,分别为SysTick系统时钟与WatchDog看门狗。
- SysTick系统时钟位于Cortex-M3内核,是一个24位的递减计数器,主要用于:
精确延时,在多任务操作系统中为系统提供时间基准(时基);
任务切换,为每个任务分配时间片。
我们每次用CubeMX新建工程时,都要设置SYS,也就是SysTick,也是因此,我们每个工程建成后,都有代码
“SystemClock_Config();”。 - WatchDog看门狗
当微控制器受到外部干扰或程序中出现不可预知的逻辑故障导致应用程序脱离正常的执行流程时(俗称程序跑飞),在一定的时间间隔内使系统复位,回到初始状态;
看门狗设计是用来监视MCU程序运行状态的,是确保系统可靠稳定运行的一种有效措施。
本次探究使用的F103C8T6芯片,有高级定时器TIM1和TIM8。
3.1.2 定时器功能
3.1.3 CubeMX配置
STM32通用定时器TIMx(x=2,3,4,5)主要由时钟源、时钟单元、捕获和比较通道等构成,核心是可编程预分频驱动的16位自动装载计数器。
配置定时器,选择定时器2来实现定时的功能。选中 TIMx,将定时器x的时钟源设置为内部时钟;设置分频系数为71(因为我们的时钟设置为72MHZ),系统处理的时候会自动加1,所以此处进行的是72分频。72分频后得到1MHZ的时钟;
1MHZ的时钟,计数50000次,得到时间50000/1000000=0.05秒;
实验一中我们想要实现2s周期亮灭,即亮1s灭1s。
每隔0.05秒,定时器2产生一次定时中断。中断产生20次后,改变led的引脚电平。
3.1.4 TIM功能函数
HAL_TIM_Base_Start_IT(&htim2); //TIM启动
HAL_TIM_IC_CaptureCallback是由 STM32 的 HAL(Hardware Abstraction Layer)库提供的,用于处理定时器的定时周期性中断事件。
当定时器的计数器达到设定的周期值(Period)并发生溢出时,就会触发定时器的定时周期性中断。
实验一中我们想要利用定时器实现LED周期性亮灭,就需要调用这个中断函数。
每当电平转换后,定时器开始计时,累计达到1s后转换电平再重新计时。
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//这里灯亮一秒,灭一秒,则中断产生20次改变一次电平
static uint32_t time_cnt =0; //记录中断次数
if(htim->Instance == TIM2)
{
if(++time_cnt >= 20) //判断是否已经达到一秒
{
time_cnt =0; //点灯用的中断次数归零
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9); //改变LED所接引脚的电平
}
}
}
3.2 PWM
脉冲宽度调制(Pulse width modulation,PWM)是一种对模拟信号电平进行数字编码的方法。
STM32的定时器除了TIM6和TIM7(基本定时器)之外,其他的定时器都可以产生PWM输出。其中,高级定时器TIM1、TIM8可以同时产生7路PWM输出。
3.2.1 PWM的工作原理
在 Parameter Settings 页配置预分频系数为 71,计数周期(自动加载值)为 499,定时器溢出频率,即PWM的周期,就是 72MHz/(71+1)/(499+1) = 2kHz
PWM频率:指1秒钟内信号从高电平到低电平再回到高电平的次数(一个周期);
Fpwm =Tclk / ((arr+1)*(psc+1))(单位:Hz)
(arr 是计数器值、psc 是预分频值)
占空比:是一个脉冲周期内,高电平的时间与整个周期时间的比例
duty circle = x / arr(单位:%)
(x 用户设定值)
比如实验一中:
定时器频率Tclk = 72Mhz arr=499 psc=71 那么PWM频率就是720000/500/72= 2000Hz,即2KHz
arr=499,TIM2->CCR1=100 则pwm的占空比为20%
改CCR1可以修改占空比,修改arr可以修改频率。
PWM就是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压。
3.2.2 呼吸灯原理
一般人眼睛对于80Hz 以上刷新频率则完全没有闪烁感。
以电脑屏幕为例,其实显示屏的内容以一个很高的频率刷新内容,但是由于刷新率太高导致人眼无法察觉,然而假如你用手机拍摄就能看到视频中的电脑屏幕有彩色反光,这是电脑屏幕刷新造成的。
呼吸灯则是需要将刷新频率控制下来,从而达成闪烁的效果。
假若我们想要改变LED的亮度,我们可以改变占空比。因为占空比的变化会改变输出的有效电压。
占空比越大,输出电压越大,LED越亮。
所以,在频率一定下,可以用不同占空比改变LED灯的亮度使其达到一个呼吸灯的效果。
3.2.3 PWM功能函数
- HAL_TIM_PWM_Start函数:开启 TIMx 的通道x,输出PWM
void HAL_TIM_PWM_Start(&htimx, TIM_CHANNEL_x);
/*
* @Descript PWM占空比更改
* @param htimx 相关定时器指针
* @param TIM_CHANNEL_x 相关PWM通道
* @param Pulse Duty_cycle = Pulse / Counter Period
* @return void
*/
- __HAL_TIM_SET_COMPARE修改TIMx的通道x的PWM波形的占空比
//修改TIMx的通道x的PWM波形的占空比
void __HAL_TIM_SET_COMPARE(&htimx, TIM_CHANNEL_x, Pulse);
/*
* @Descript PWM频率更改
* @param htimx 相关定时器指针
* @param Counter_Period PWM_fre = TIM_frq / ( Prescaler + 1 ) / ( Counter Period + 1 )
* @return void
*/
四. 代码实现
4.1 实验一
4.1.1 CubeMX配置
4.1.2 代码
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//这里灯亮一秒,灭一秒,则中断产生20次改变一次电平
static uint32_t time_cnt =0; //记录中断次数
if(htim->Instance == TIM2)
{
if(++time_cnt >= 20) //判断是否已经达到一秒
{
time_cnt =0; //点灯用的中断次数归零
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9); //改变LED所接引脚的电平
}
}
}
4.1.3 效果演示
4.2 实验二
4.2.1 CubeMX配置
其它基本和4.1.1一样,除了TIM配置上有区别。
4.2.2 代码
uint16_t pwm=20;
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
/* USER CODE BEGIN WHILE */
while (1)
{
while(pwm<500)
{
pwm = pwm + 10;
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,pwm);
HAL_Delay(20);//延时20毫秒
}
while(pwm>0)
{
pwm = pwm - 10;
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,pwm);
HAL_Delay(20);
}
/* USER CODE END WHILE */
}
4.2.3 实现效果
五. 探究总结
定时器有计数、定时、输入捕获、输出比较以及PWM生成等功能,功能十分强大具有广泛的应用性。
而PWM就是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压。我们经常用其控制电机驱动、呼吸灯等等,应用也十分广泛。
总之,学习定时器对我们STM32的学习及应用有着举足轻重的效用,需要我们多花时间学习理解并应用。
以上则是我本次探究内容,如有错漏请在评论区指正,感谢阅览!