目录
一、定时器原理介绍
1、定时器的工作
2、定时器分类
3、通用定时器介绍
4、定时器计数模式
5、定时器时钟源
6、定时器溢出时间计算公式
二、使用定时器中断点亮LED小灯
1、初始化GPIO口引脚
2、初始化定时器函数
3、启动定时器中断服务函数
4、调用定时器中断服务回调函数
5、重写定时器中断服务回调函数
6、把上述的定时器中断服务回调函数,放入main主函数里
7、结果演示
使用精准的时基,通过硬件的方式,实现定时功能。定时器核心就是计数器。
基本定时器(TIM6~TIM7)
通用定时器(TIM2~TIM5)
高级定时器(TIM1和TIM8)
1) 16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。
2) 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的
任意数值。
3)4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
A.输入捕获
B.输出比较
C.PWM 生成(边缘或中间对齐模式)
D.单脉冲模式输出
4)可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)
的同步电路。
5)如下事件发生时产生中断/DMA:
A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
C.输入捕获
D.输出比较
E.支持针对定位的增量(正交)编码器和霍尔传感器电路
F.触发输入作为外部时钟或者按周期的电流管理
Tout:设定的时间
PSC:预分频系数
ARR:自动重装载值
Tclk:时钟晶振的大小
例如,要定时500ms,则:PSC=7199,ARR=4999,Tclk=72M
需求:使用定时器中断方法,每500ms翻转一次LED1灯状态。
1. RCC配置
2. LED1灯配置
3. 时钟数配置
4. TIM2配置
编写代码
#include "gpio.h"
void MX_GPIO_Init(void) //初始化GPIO口引脚函数
{
GPIO_InitTypeDef GPIO_InitStruct = {0}; //初始化设置GPIO的结构体
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB时钟
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET); //GPIO B8 引脚输出1的函数
/*Configure GPIO pin : PB8 */
GPIO_InitStruct.Pin = GPIO_PIN_8; //配置GPIO口引脚:PB8
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出;推挽输出可以真正的输出高电平
GPIO_InitStruct.Pull = GPIO_NOPULL; //内部电阻既不拉高也不拉低
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; //GPIO引脚输出的频率
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); //根据上述内容,初始化GPIOB引脚
}
#include "tim.h"
TIM_HandleTypeDef htim2; //调用定时器外设结构体
void MX_TIM2_Init(void) //初始化定时器函数的过程
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
//定时器外设结构体参数初始化
htim2.Instance = TIM2; //外设设备选择定时器2
htim2.Init.Prescaler = 7199; //设置定时器预分频系数
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; //定时器计数方式,对于基本定时器指向上计数
htim2.Init.Period = 4999; //计时周期
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //设置时钟分频系数,这里代表不分频
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; //自动重装载:使能
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) //初始化TIM2时基
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; //时钟源:内部
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) //配置TIM2的时钟源
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; //每次更新时间TRGO1输出一个上升沿
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; //使能TIM2主模式
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) //配置TIM2的主模式
{
Error_Handler();
}
}
#include "main.h"
#include "stm32f1xx_it.h"
void TIM2_IRQHandler(void) //中断服务函数
{
HAL_TIM_IRQHandler(&htim2); //调用定时器中断服务函数
}
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim) //定时器中断服务函数
{
HAL_TIM_PeriodElapsedCallback(htim); //3880行
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //每一次定时器时间到了,就调用此中断回调函数
{
if(htim->Instance == TIM2) //判断定时器是否是TIM2
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8); //翻转GPIO B8的引脚
}
}
#include "main.h"
#include "tim.h"
#include "gpio.h"
void SystemClock_Config(void);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //每一次定时器时间到了,就调用此中断回调函数
{
if(htim->Instance == TIM2)
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
}
}
int main(void)
{
HAL_Init(); //初始化HAL库函数
SystemClock_Config(); //初始化系统时钟
MX_GPIO_Init(); //初始化GPIO引脚
MX_TIM2_Init(); //初始化TIM2定时器
HAL_TIM_Base_Start_IT(&htim2); //启动定时器
}
void SystemClock_Config(void) //系统时钟函数
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
LED灯亮500ms后,自动灭灯,然后再亮500ms循环