1,定时器概述
1.1,软件定时原理
1.2,定时器定时原理
1.3,STM32定时器分类
1.4,STM32定时器特性表
1.5,STM32基本、通用、高级定时器的功能整体区别
1.1,软件定时原理
使用纯软件(CPU死等)的方式实现定时(延时)功能
void delay_us(uint32_t us)
{
us *= 72;
while(us--);
}
缺点:
1,延时不精准
2,CPU死等
1.2,定时器定时原理
使用精准的时基,通过硬件的方式,实现定时功能
定时器核心就是计数器
注意:分频系数在65536
事件默认产生
中断和DMA输出不默认产生
缓冲:减小误差
中断:软件清零
注意:重装载器和预分频都是16位,0~65535
一个数的时间
CounterMode 计数模式,对于基本计数器无效
ClockDivision 时钟分频因子,基本计数器无效
RepetitionCounter 重复计数寄存器的值 基本计数器无效
AutoReloadPreload 自动重装载,有缓存
我用的f4
#include "timer.h"
#include "led.h"
TIM_HandleTypeDef htim;
/*定时器中断初始化*/
void time_init(uint16_t psc,uint16_t arr)
{
htim.Instance=TIM6;
htim.Init.Period=arr;
htim.Init.Prescaler=psc;
HAL_TIM_Base_Init(&htim);
}
/*定时器基础MSP初始化函数*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if (htim->Instance==TIM6)
{
__HAL_RCC_TIM6_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 2, 2 );
HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
}
HAL_TIM_Base_Start_IT(htim);
}
/*定时器6中断服务函数*/
void TIM6_DAC_IRQHandler()
{
HAL_TIM_IRQHandler(&htim);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM6)
{
LED0=!LED0;
HAL_TIM_Base_Start_IT(htim);
}
}
为什么用void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim) { /* Capture compare 1 event 捕获比较1事件*/ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) != RESET) { { __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1); htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1; /* Input capture event 输入捕获偶*/ if ((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00U) { #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->IC_CaptureCallback(htim); #else HAL_TIM_IC_CaptureCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } /* Output compare event 输出比较事件*/ else { #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->OC_DelayElapsedCallback(htim); htim->PWM_PulseFinishedCallback(htim); #else HAL_TIM_OC_DelayElapsedCallback(htim); HAL_TIM_PWM_PulseFinishedCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED; } } } /* Capture compare 2 event 捕获比较2事件*/ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) != RESET) { __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2); htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2; /* Input capture event 输入捕获事件 */ if ((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00U) { #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->IC_CaptureCallback(htim); #else HAL_TIM_IC_CaptureCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } /* Output compare event 输出比较事件 */ else { #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->OC_DelayElapsedCallback(htim); htim->PWM_PulseFinishedCallback(htim); #else HAL_TIM_OC_DelayElapsedCallback(htim); HAL_TIM_PWM_PulseFinishedCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED; } } /* Capture compare 3 event 捕获比较3事件*/ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC3) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC3) != RESET) { __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC3); htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3; /* Input capture event 输入捕获事件*/ if ((htim->Instance->CCMR2 & TIM_CCMR2_CC3S) != 0x00U) { #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->IC_CaptureCallback(htim); #else HAL_TIM_IC_CaptureCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } /* Output compare event 输出比较事件*/ else { #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->OC_DelayElapsedCallback(htim); htim->PWM_PulseFinishedCallback(htim); #else HAL_TIM_OC_DelayElapsedCallback(htim); HAL_TIM_PWM_PulseFinishedCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED; } } /* Capture compare 4 event 捕获比较4事件*/ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC4) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC4) != RESET) { __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC4); htim->Channel = HAL_TIM_ACTIVE_CHANNEL_4; /* Input capture event 输入捕获事件*/ if ((htim->Instance->CCMR2 & TIM_CCMR2_CC4S) != 0x00U) { #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->IC_CaptureCallback(htim); #else HAL_TIM_IC_CaptureCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } /* Output compare event 输出比较事件*/ else { #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->OC_DelayElapsedCallback(htim); htim->PWM_PulseFinishedCallback(htim); #else HAL_TIM_OC_DelayElapsedCallback(htim); HAL_TIM_PWM_PulseFinishedCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED; } } /* TIM Update event TIM更新事件*/ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET) { __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->PeriodElapsedCallback(htim); #else HAL_TIM_PeriodElapsedCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } } /* TIM Break input event 中断输入事件*/ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_BREAK) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_BREAK) != RESET) { __HAL_TIM_CLEAR_IT(htim, TIM_IT_BREAK); #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->BreakCallback(htim); #else HAL_TIMEx_BreakCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } } /* TIM Trigger detection event 触发检测事件 */ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_TRIGGER) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_TRIGGER) != RESET) { __HAL_TIM_CLEAR_IT(htim, TIM_IT_TRIGGER); #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->TriggerCallback(htim); #else HAL_TIM_TriggerCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } } /* TIM commutation event */ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_COM) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_COM) != RESET) { __HAL_TIM_CLEAR_IT(htim, TIM_FLAG_COM); #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->CommutationCallback(htim); #else HAL_TIMEx_CommutCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } } }
/* TIM Update event TIM更新事件*/ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET) { __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->PeriodElapsedCallback(htim); #else HAL_TIM_PeriodElapsedCallback(htim);
HAL_TIM_PeriodElapsedCallback(htim);是更新中断事件
注意:中断标志位已经被清除了
__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
htim.Init.Period=arr;
htim.Init.Prescaler=psc;基础计数器只有arr和psc
预装载理解
关掉预装载
0-100时,到100,此时ARR为200,则100直接到200
0-100时,到100此时ARR为200,则到0,从0-200
HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)
{
/* Check the TIM handle allocation 检查TIM句柄分配*/
if (htim == NULL)
{
return HAL_ERROR;
}
/* Check the parameters 检查参数*/
assert_param(IS_TIM_INSTANCE(htim->Instance));
assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
assert_param(IS_TIM_AUTORELOAD_PRELOAD(htim->Init.AutoReloadPreload));
if (htim->State == HAL_TIM_STATE_RESET)
{
/* Allocate lock resource and initialize it 分配锁资源并初始化*/
htim->Lock = HAL_UNLOCKED;
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
/* Reset interrupt callbacks to legacy weak callbacks */
TIM_ResetCallback(htim);
if (htim->Base_MspInitCallback == NULL)
{
htim->Base_MspInitCallback = HAL_TIM_Base_MspInit;
}
/* Init the low level hardware : GPIO, CLOCK, NVIC */
htim->Base_MspInitCallback(htim);
#else
/* Init the low level hardware : GPIO, CLOCK, NVIC 初始化底层硬件:GPIO, CLOCK, NVIC*/
HAL_TIM_Base_MspInit(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/* Set the TIM state 设置TIM状态*/
htim->State = HAL_TIM_STATE_BUSY;
/* Set the Time Base configuration 设置Time Base配置*/
TIM_Base_SetConfig(htim->Instance, &htim->Init);
/* Initialize the TIM state 初始化TIM状态*/
htim->State = HAL_TIM_STATE_READY;
return HAL_OK;
}
会调用HAL_TIM_Base_MspInit(htim); 回调函数
用来打开时钟
TIM_HandleTypeDef tim;
/*定时器中断初始化*/
void time_init(uint16_t arr ,uint16_t psc ,uint16_t rep )
{
tim.Instance=TIM1;
tim.Init.Prescaler=psc;
tim.Init.CounterMode=TIM_COUNTERMODE_UP;
tim.Init.Period=arr;
tim.Init.ClockDivision=1;//分频因子不会改变定时时间
tim.Init.RepetitionCounter=rep;
tim.Init.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim);
HAL_TIM_Base_Start(&tim);
}void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM1)
{
__HAL_RCC_TIM1_CLK_ENABLE();
}else if (htim->Instance==TIM2)
{
__HAL_RCC_TIM2_CLK_ENABLE();
}else if (htim->Instance==TIM3)
{
__HAL_RCC_TIM3_CLK_ENABLE();
}else if (htim->Instance==TIM4)
{
__HAL_RCC_TIM4_CLK_ENABLE();
}
}
while(1)
{
if(__HAL_TIM_GET_FLAG(&tim, TIM_FLAG_UPDATE) )//有中断进来就标志位
{
__HAL_TIM_CLEAR_FLAG(&tim, TIM_FLAG_UPDATE);//清掉标志位
LED0=!LED0;
}
}关闭时钟时
int16_t num1;
num1++;
if(num1>=5){
HAL_TIM_Base_Stop(&tim); //定时器关闭
HAL_TIM_Base_DeInit(&tim);//关闭时钟,会调用HAL_TIM_Base_MspDeInit
}void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM1)
{
__HAL_RCC_TIM1_CLK_DISABLE();
}else if (htim->Instance==TIM2)
{
__HAL_RCC_TIM2_CLK_DISABLE();
}else if (htim->Instance==TIM3)
{
__HAL_RCC_TIM3_CLK_DISABLE();
}else if (htim->Instance==TIM4)
{
__HAL_RCC_TIM4_CLK_DISABLE();
}}
标志位在宏定义里面
问题:为什么复位后,马上就定时器中断更新
TIM_Base_SetConfig(TIM_TypeDef *TIMx, TIM_Base_InitTypeDef *Structure)里面
/* Generate an update event to reload the Prescaler
and the repetition counter (only for advanced timer) value immediately
生成更新事件以重新加载precaler
并且重复计数器(仅限高级计时器)立即值
*/
TIMx->EGR = TIM_EGR_UG;void time_init(uint16_t arr ,uint16_t psc ,uint16_t rep )
{
tim.Instance=TIM1;
tim.Init.Prescaler=psc;
tim.Init.CounterMode=TIM_COUNTERMODE_UP;
tim.Init.Period=arr;
tim.Init.ClockDivision=1;//分频因子不会改变定时时间
tim.Init.RepetitionCounter=rep;
tim.Init.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim);
__HAL_TIM_CLEAR_FLAG(&tim, TIM_FLAG_UPDATE);//避免马上判断事件输出
HAL_TIM_Base_Start(&tim);
}
2.通用定时器
不同点:基本定时器只能递增计数,而通用定时器计数模式有三种
通用定时器PWM输出实验
typedef struct
{
uint32_t OCMode; /* 输出比较模式选择 */
uint32_t Pulse; /* 设置比较值 */
uint32_t OCPolarity; /* 设置输出比较极性 */
uint32_t OCNPolarity; /* 设置互补输出比较极性 */
uint32_t OCFastMode; /* 使能或失能输出比较快速模式 */
uint32_t OCIdleState; /* 空闲状态下OC1输出 */
uint32_t OCNIdleState; /* 空闲状态下OC1N输出 */
} TIM_OC_InitTypeDef;
PWM只看标红三个
轮询方式程序:
#include "timer.h"
#include "led.h"
TIM_HandleTypeDef htim;
TIM_OC_InitTypeDef sConfig;
//HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim);
//HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef *sConfig, uint32_t Channel);
void Timer_Init(uint16_t arr,uint16_t psc)
{
htim.Instance=TIM14;
htim.Init.Prescaler=psc;
htim.Init.Period=arr;
htim.Init.CounterMode=TIM_COUNTERMODE_UP;
htim.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; /*分频因子*/
//tim1.Init.RepetitionCounter=0 /*只有高级定时器有*/
HAL_TIM_PWM_Init(&htim);
sConfig.OCMode=TIM_OCMODE_PWM1;
sConfig.OCPolarity=TIM_OCPOLARITY_LOW;
sConfig.Pulse=arr/2;
HAL_TIM_PWM_ConfigChannel(&htim, &sConfig,TIM_CHANNEL_1); /*设置PWM通道*/
HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_1); /*轮询方式 打开通道1*/
}
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_Init;
if(htim->Instance== TIM14)
{
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_TIM14_CLK_ENABLE();
GPIO_Init.Alternate=GPIO_AF9_TIM14; /*IO复用*/
GPIO_Init.Mode=GPIO_MODE_AF_PP; /*复用推挽输出*/
GPIO_Init.Pin=GPIO_PIN_9;
GPIO_Init.Pull=GPIO_PULLDOWN; /*下拉*/
GPIO_Init.Speed=GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOF, &GPIO_Init);
}
}
int main(void)
{
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(336,8,2,7); //设置时钟,168Mhz
delay_init(168); //初始化延时函数
uart_init(115200); //初始化USART
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
//TIM3_Init(5000-1,8400-1); //定时器3初始化,定时器时钟为84M,分频系数为8400-1,
//所以定时器3的频率为84M/8400=10K,自动重装载为5000-1,那么定时器周期就是500ms
Timer_Init(8400-1 ,5000-1);
while(1)
{
if(__HAL_TIM_GET_FLAG(&htim, TIM_FLAG_CC1) ) /*查询标志位是否置位*/
{
__HAL_TIM_CLEAR_FLAG(&htim, TIM_FLAG_CC1);
printf("通道1匹配\n");
}
}
}
中断方式程序:
#include "timer.h"
#include "led.h"
TIM_HandleTypeDef htim;
TIM_OC_InitTypeDef sConfig;
//HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim);
//HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef *sConfig, uint32_t Channel);
void Timer_Init(uint16_t arr,uint16_t psc)
{
htim.Instance=TIM14;
htim.Init.Prescaler=psc;
htim.Init.Period=arr;
htim.Init.CounterMode=TIM_COUNTERMODE_UP;
htim.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; /*分频因子*/
//tim1.Init.RepetitionCounter=0 /*只有高级定时器有*/
HAL_TIM_PWM_Init(&htim);
sConfig.OCMode=TIM_OCMODE_PWM1;
sConfig.OCPolarity=TIM_OCPOLARITY_LOW;
sConfig.Pulse=arr/2;
HAL_TIM_PWM_ConfigChannel(&htim, &sConfig,TIM_CHANNEL_1); /*设置PWM通道*/
HAL_TIM_PWM_Start_IT(&htim, TIM_CHANNEL_1); /*中断方式 打开通道1*/
}
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_Init;
if(htim->Instance== TIM14)
{
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_TIM14_CLK_ENABLE();
GPIO_Init.Alternate=GPIO_AF9_TIM14; /*IO复用*/
GPIO_Init.Mode=GPIO_MODE_AF_PP; /*复用推挽输出*/
GPIO_Init.Pin=GPIO_PIN_9;
GPIO_Init.Pull=GPIO_PULLDOWN; /*下拉*/
GPIO_Init.Speed=GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOF, &GPIO_Init);
HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 2 , 2 ); //设定优先级
HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn); //打开中断
}
}
void TIM8_TRG_COM_TIM14_IRQHandler()
{
HAL_TIM_IRQHandler(&htim);
}
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM14)
{
LED0=!LED0;
}
}
PWM1 ARR 比较值 占空比(有效低) 占空比(有效高) 频率
向上 1000-1 200 ( 高电平/全部) 80% ( 低电平/全部) 20% 84M/(psc*arr)
预装载功能:
每次CCR改变时,DMA修改的值会在下次才生效
通用定时器输入捕获![](https://i-blog.csdnimg.cn/blog_migrate/f90c35f8fd475850dc947ec8facf784c.png)