说明:介绍使用STM32 定时器做计时和定时触发一些功能,如点灯。
测试平台:STM32G474RB
1.定时器定义、初始化、点灯
#define LED_GPIO GPIOA
#define LED_PIN GPIO_PIN_0
#define FAN_CTR_GPIO GPIOB
#define FAN_CTR_PIN GPIO_PIN_6
/* step:1 定义定时器分频系数 */
#define HTIM5_PRESCALER (SystemCoreClock /1000000 - 1) /* 定时器的分频系数 */
#define HTIM5_PERIOD (1000 - 1) /* 设置的定时器向上计数的最大值,达到最大值才会产生中断 */
/* step:2 配置定时器的优先级 */
#define HTIM2_NVIC_IRQChannelPreemptionPriority 0 /* 抢占优先级 */
#define HTIM2_NVIC_IRQChannelSubPriority 0 /* 从优先级 */
#define HTIM3_NVIC_IRQChannelPreemptionPriority 0 /* 抢占优先级 */
#define HTIM3_NVIC_IRQChannelSubPriority 0 /* 从优先级 */
#define HTIM4_NVIC_IRQChannelPreemptionPriority 0 /* 抢占优先级 */
#define HTIM4_NVIC_IRQChannelSubPriority 0 /* 从优先级 */
#define HTIM5_NVIC_IRQChannelPreemptionPriority 0 /* 抢占优先级 */
#define HTIM5_NVIC_IRQChannelSubPriority 0 /* 从优先级 */
/* step:3 定义定时器相关变量 */
uint32_t tim5_count = 0; /* 定时器中断次数计数 */
TIM_HandleTypeDef htim5; /* 定时器变量 */
/* 初始化定时器、开启定时器中断
* TIM_TypeDef *TIM_X : 定时器 如 TIM5
* TIM_HandleTypeDef *htim : 定时器变量指针 如 &htim5
* uint32_t Prescaler : 分频系数
* uint32_t Period : 中断周期 ,分频后达到这个计数周期后产生中断。
* . 分频后频率 = 系统时钟 / 分频系数 = SystemCoreClock / Prescaler = SystemCoreClock / ((SystemCoreClock / 1000000) - 1)
*
* */
void Init_TIM_Basic(TIM_TypeDef *TIM_X,TIM_HandleTypeDef *htim ,uint32_t Prescaler ,uint32_t Period)
{
TIM_HandleTypeDef TIM_HandleTypeDef_Structure;
if (TIM_X == TIM2)
{
__HAL_RCC_TIM2_CLK_ENABLE();
}
else if (TIM_X == TIM3)
{
__HAL_RCC_TIM3_CLK_ENABLE();
}
else if (TIM_X == TIM4)
{
__HAL_RCC_TIM4_CLK_ENABLE();
}
else if (TIM_X == TIM5)
{
__HAL_RCC_TIM5_CLK_ENABLE();
}
TIM_HandleTypeDef_Structure.Instance = TIM_X; /* 外设设备选择定时器 */
//TIM_HandleTypeDef_Structure.Init.Prescaler = SystemCoreClock /1000000 - 1; /* 设置定时器的分频系数 */
//TIM_HandleTypeDef_Structure.Init.Period = 1000 - 1; /* 设置的定时器向上计数的最大值,达到最大值才会产生中断 */
TIM_HandleTypeDef_Structure.Init.Prescaler = Prescaler; /* 设置定时器的分频系数 */
TIM_HandleTypeDef_Structure.Init.Period = Period; /* 设置的定时器向上计数的最大值,达到最大值才会产生中断 */
TIM_HandleTypeDef_Structure.Init.CounterMode = TIM_COUNTERMODE_UP; /* 指向上计数 */
TIM_HandleTypeDef_Structure.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 设置时钟分频系数,这里填写TIM_CLOCKDIVISION_DIV1是代表不分频。 */
TIM_HandleTypeDef_Structure.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; /* 定时器自动重装上限值 */
HAL_TIM_Base_Init(&TIM_HandleTypeDef_Structure);
__HAL_TIM_ENABLE(&TIM_HandleTypeDef_Structure);
if (TIM_X == TIM2)
{
HAL_NVIC_SetPriority(TIM2_IRQn, HTIM2_NVIC_IRQChannelPreemptionPriority, HTIM2_NVIC_IRQChannelSubPriority); /* 设置中断优先级 */
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
else if (TIM_X == TIM3)
{
HAL_NVIC_SetPriority(TIM3_IRQn, HTIM3_NVIC_IRQChannelPreemptionPriority, HTIM3_NVIC_IRQChannelSubPriority); /* 设置中断优先级 */
HAL_NVIC_EnableIRQ(TIM3_IRQn);
}
else if (TIM_X == TIM4)
{
HAL_NVIC_SetPriority(TIM4_IRQn, HTIM4_NVIC_IRQChannelPreemptionPriority, HTIM4_NVIC_IRQChannelSubPriority); /* 设置中断优先级 */
HAL_NVIC_EnableIRQ(TIM4_IRQn);
}
else if (TIM_X == TIM5)
{
HAL_NVIC_SetPriority(TIM5_IRQn, HTIM5_NVIC_IRQChannelPreemptionPriority, HTIM5_NVIC_IRQChannelSubPriority); /* 设置中断优先级 */
HAL_NVIC_EnableIRQ(TIM5_IRQn);
}
*htim = TIM_HandleTypeDef_Structure;
HAL_TIM_Base_Start_IT(htim); /* 打开定时器中断 */
}
/* step:4 中断服务函数 */
/* 定时器5中断服务函数 */
void TIM5_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim5);
}
/* step:5 中断回调函数中添加功能代码:如LED闪灯 */
/* 定时器中断更新回调函数 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == htim5.Instance)
{
++tim5_count;
if (tim5_count % 500 == 0)
{
HAL_GPIO_TogglePin(LED_GPIO, LED_PIN); /* LED 翻转 */
}
HAL_GPIO_TogglePin(FAN_CTR_GPIO, FAN_CTR_PIN);
}
}
/* step:6 调用定时器初始化函数 */
Init_TIM_Basic(TIM5,&htim5,HTIM5_PRESCALER,HTIM5_PERIOD); //初始化定时器5
2.定时器计时
定时器用作计时工,记录程序、函数运行时的耗时。
uint32_t time_count;
while (1)
{
rt_thread_mdelay(1000);
//htim5.Instance->CNT = 0; /* 清零定时器计数: 会多耗时一点 */
TIM5->CNT = 0; /* 清零定时器计数: 速度更快,计时更准确 */
HAL_GPIO_TogglePin(LED_GPIO, LED_PIN);
//time_count = htim5.Instance->CNT;
time_count = TIM5->CNT; /* 记录中间的代码的耗时 */
printf("tick_time = %d ,time_count = %d\r\n", rt_tick_get(),time_count);
}