定时器简介:
在stm32中,定时器的基准时钟一般都是主频72MHz
基本计时器
步骤:
- 打开RCC内部时钟(基本每个步骤这个都是第一步)
- 选择时基单元的时钟源
- 配置时基单元(包括PSC,CNT,ARR)
- 配置输出中断控制,允许更新中断输出到NVIC
- 配置NVIC,在NVIC打开定时器中断的通道,并分配一个优先级
- 运行控制
- 再写一个中断函数
当定时器使能后,计数器开始计数,当计数器更新后就会触发中断,进入中断函数
tim库的一些主要函数介绍
// 恢复缺省配置
void TIM_DeInit(TIM_TypeDef* TIMx);
// 时基单元初始化
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
// 给结构体变量赋默认值
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
// 使能计数器>>运行控制
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
// 使能中断输出信号>>中断输出控制
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
// >>时基单元的时钟选择部分
// 选择内部时钟
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
// 选择ITRx其他定时器的时钟
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
// 选择TIx其他定时器的时钟
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
uint16_t TIM_ICPolarity, uint16_t ICFilter);
// 选择ETR通过外部时钟模式1输入的时钟
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t
TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);
// 选择ETR通过外部时钟模式2输入的时钟
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,
uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
// 单独用来配置ETR引脚的预分频器,极性,滤波器等参数
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t
TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);
// 单独来写预分频值
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);
// 用来改变计数器的计数模式
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);
// 自动重装器预装功能配置
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
// 手动给计数器写入一个值
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);
// 给自动重装器写一个值
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);
// 获取当前计数器的值
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);
// 获取当前的预分频器的值
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);
// 获取标志位和清除标志位
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
定时器内部中断:
开始写代码
步骤:
- 打开RCC内部时钟(基本每个步骤这个都是第一步)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
- 选择时基单元的时钟源
TIM_InternalClockConfig(TIM2);//内部时钟
- 配置时基单元(包括PSC,CNT,ARR)
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
//时钟分频,来获取采样频率(其实对时基单元影响不大,所以随便取了一个)
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
//计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
//周期,ARR自动重装器的值
TIM_TimeBaseInitStructure.TIM_Period=10000-1;
//PSC预分频器的值
TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;
//重复计数器的值(高级定时器才有,直接给0)
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
定时1s,也就是定时频率为1Hz,计算如下
定时频率=72M/7200/10000=1s
计算可以查看:如何计算定时器的定时时间?_定时器时间计算-优快云博客
72M被7200分频之后变成72M/7200=0.001MHz=10KHz=10000Hz,此时计10000个数为1s
注意PSC和ARR的取值在0-65535之间,如果自分频给少点,自动重装给多点,这样就是以一个比高的频率计比较多的数
- 配置输出中断控制,允许更新中断输出到NVIC
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
- 配置NVIC,在NVIC打开定时器中断的通道,并分配一个优先级
//NVIC优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
//中断通道
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级
NVIC_Init(&NVIC_InitStructure);
- 运行控制
TIM_Cmd(TIM2,ENABLE);//启动定时器
- 再写一个中断函数
void TIM2_IRQHandler (void)
{
//检查中断标志位
//if获取TIM2的更新中断的中断标志位
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
//code
//清除标志位
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
可以发现一开始的数字是1,刚一上电就立刻进入中断了 ,修改方法如下:(至于原因我还没太理解,暂时不写了)
定时器外部中断:
接线:
PA0是TIM2的ETR引脚
需要修改的地方:
//第二个参数是外部触发预分频器(不分频)
//第三个参数是外部触发的极性(选择了不反向=高电平/上升沿有效)
//第四个函数是外部触发滤波器(以采样频率f采样n个点,如果n个点都一样才会有效输出)
TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NoneInverted, 0x00);
代替原来的内部时钟,又因为用到了GPIO,所以还要在这之前配置GPIO
累了,大概就这样