STM32F1x HAL库学习笔记(11)定时器配置及中断(溢出中断,PWM输出,输入捕获)
本文开发环境:
- MCU型号:STM32F103C8T6
- IDE环境: MDK 5.27
- 代码生成工具:STM32CubeMx 5.6.1
- HAL库版本:STM32Cube_FW_F1_V1.8.0
本文内容:
- STM32CubeMx 配置 定时器
- 溢出中断
- PWM输出
- 输入捕获
附件 :
- MDK工程:定时器溢出中断
- MDK工程:定时器PWM输出
- MDK工程:定时器输入捕获
一、 定时器
STM32 定时器其实就是一个计数器,用户可以设置计数的个数,方向(数值越来越大,或数值越来越小),初始值(从多少开始计数),计数的频率等等。
- 溢出中断:当定时器计数结束后,可以产生一个中断
- PWM输出:定时器计数值与用户设置的值匹配时候,改变IO口输出电平
- 输入捕获: 当IO口电平为设置电平时候,定时器将此时计数的值保存到寄存器中,用户可以读取。
1. 溢出中断
溢出中断可以用来做一些周期性的动作,比如设置定时器的计数频率为72MHz,计数个数为72个,初始化值为0,并使能了自动装载(即使定时器计数完成后,自动重新把用户设置的初值装载到计数器中),那么每 1ms 就可以产生一次中断。
2. PWM输出
PWM可以设置极性等,简单来说,用户可以设置定时器的计数频率为72MHz,计数个数为72个,对比数值为36,那么定时器启动以后,就会从0计数到72,计数到第36个时,就改变一次电平,这样就会输出要给方波,用户可以通过不断修改对比值,来产生一系列PWM。、
3. 输入捕获
输入捕获可以用来捕获IO口的电平,用户可以设置定时器的计数频率为72MHz,计数个数为72个,捕获电平为高电平,那么定时器启动以后,就会从0计数到72,如果捕获到高电平,就把该电平的值保存到寄存器中,供用户读取。通常可以用来捕获一个电平的宽度,比如设置高电平捕获,捕获到高电平时候,读取计数的值,然后设置为低电平捕获,捕获到低电平以后,读取这个计数的值,那么两个值的差,就是高电平的时间。
4. 时基与通道
STM32 的定时器可以有多个通道,不同通道可以独立设置,比如PWM输出中不同通道可以有不同的占空比,但是一个定时器同时只能有一个计数频率,用户无法让TIM1(定时器1)通道1输出 38KHz PWM,通道2输出 50KHz PWM,但是可以输出2个 38Khz 占空比不同的 PWM。
二、溢出中断 CubeMx 配置及程序实现
1. CubeMx 配置
基础配置
基础配置是每一个工程都必须的,包括系统时钟,指定延时函数定时器,打开调试口等:
- 选择芯片:STM32F103C8T6
- 配置系统时钟:设置为外部晶振
- 配置系统时钟为最高的72M:
- 打开 SW 调试口:用以ST-LINK下载和调试程序
定时器配置
-
设置定时器的时钟和具体参数
这里设置分频系数的值为7199,即 7200 分频,所以计数频率为 1KHz,计数值为4999,所以需要计算5000个数溢出,可见溢出的时间为500ms。 -
使能溢出中断
-
生成工程:
2. 程序设计
NOTE:本文使用 ST-LINK 输出打印信息作为调试方法,详见:STM32 使用 ITM 输出调试信息
STM32CubeMx 默认是生成 HAL 库函数,HAL 生成的函数会自动添加初始化函数,用户只需要:
- 使能中断:
HAL_TIM_Base_Start_IT();
使能了定时器,并开启了中断。 - 使用中断函数
HAL_TIM_PeriodElapsedCallback()
是定时器溢出后的回调函数,它是一个弱函数,可以直接在其它定义,然后使用它。
示例
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(TIM1 == htim->Instance)
{
static uint16_t cnt = 0;
printf("Update %d! \r\n",cnt++); //每次中断打印一次值
}
}
/* USER CODE END 0 */
int main(void)
{
... ...
HAL_TIM_Base_Start_IT(&htim1); //开启使能定时器中断
while (1)
{
... ...
}
}
启用ST-LINK调试,可以看到Debug窗口每秒打印两次数据:
三、PWM 输出 CubeMx 配置及程序实现
1. CubeMx 配置
配置基本与上文相同,需要稍作修改:
- 打开通道1,作为PWM输出IO口:
- 关闭溢出中断
这里不需要处理溢出中断,所以可以将其关闭:
- 生程工程
如果保持默认,就会刷新原有的工程。
2. 程序设计
HAL 默认是没有打开PWM输出的,所以需要用户打开PWM输出,由于没有使用到PWM中断,所以只需使用库函数:HAL_TIM_PWM_Start();
打开输出即可:
示例
int main(void)
{
... ...
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
while (1)
{
... ...
}
}
通过逻辑分析仪可以看到PA8产生了一个2Hz的方波:
四、输入捕获 CubeMx 配置及程序实现
1. CubeMx 配置
CubeMx 输入捕获的配置与上文基本相同。
- 将通道1设置为输入捕获通道:
- 在 NVIC 中 打开输入捕获中断
- 生成工程
2. 程序设计
STM32CubeMx 默认是上升沿捕获的,用户只需要:
- 开始计数并使能捕获中断:
HAL_TIM_IC_Start_IT();
使能了定时器,并开启了捕获中断。 - 使用中断函数
HAL_TIM_IC_CaptureCallback()
是定时器捕获到指定电平的回调函数,它是一个弱函数,可以直接在其它定义,然后使用它。
注意,这个版本的库函数 TIM_RESET_CAPTUREPOLARITY 宏定义多出一个括号,需要用户改正, 否则无法编译通过:
示例
uint32_t cap_start;
uint32_t cap_end;
uint32_t cap_time;
uint8_t flg_cap = 1; //状态标志位
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(TIM1 == htim->Instance)
{
switch(flg_cap){
case 1:
cap_start = HAL_TIM_ReadCapturedValue(&htim1,TIM_CHANNEL_1); //获取当前的捕获值.
TIM_RESET_CAPTUREPOLARITY(&htim1, TIM_CHANNEL_1); //复位捕获极性
TIM_SET_CAPTUREPOLARITY(&htim1, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING); //设置为下降沿捕获
flg_cap = 0;;
break;
case 0:
cap_end = HAL_TIM_ReadCapturedValue(&htim1,TIM_CHANNEL_1);//获取当前的捕获值.
cap_time = (float)(cap_end - cap_start)/2.5;
printf("高电平时间: %d ms\r\n",cap_time);
}
}
}
... ...
int main(void)
{
... ...
HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_1);;
}
通过PA8 点触 GND 的方法,可以观察到高电平时长的捕获。
五、附件
MDK5 示例工程
提取码:1234