目录
TIM(Timer)定时器
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断 16位计数器、预分频器(16位)、自动重装寄存器(16位)的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
最大定时=1/(72Mhz/65536(16位)/65536)(中断频率) 可通过级联方式增加定时时长
(一个定时器的输出,当作另一个计时器的输入最大可达35万亿年的计时)
不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
定时器类型
高级定时器
通用定时器
基本定时器
定时器基本参数
时钟源
计数器模式
通用计时器支持
TIM_CounterMode_Up 向上计时,从0到重装值
TIM_CounterMode_Down 向下计时,从重装值到0
TIM_CounterMode_CenterAligned 中央对齐,从0到重装,再从重装到0,如此反复
时基单元
PSC预分频器:计数的频率,(72Mhz/PSC)多久计一个数(0~65535)
ARR自动重装器:一共计多少个数(到达后归0重装)(0~65535)
CNT计数器:当前的计数值
TIM_RepetitionCounter=0;//(高级定时器)重复计数器的值
计算公式
1s=1000ms=1000000us
1Hz=1s
1khz=1000Hz=1ms
1Mhz=1000000Hz=1us
CK_PSC(72Mhz)/ (PSC + 1) / (ARR + 1)=CK_CNT_OV
72000000/7200/10000=1s
在72Mhz/7200=10k 0.1ms计一个数,共计10000个数,0.1*10000=1000ms=1s
理论知识(不看也行)
RCC时钟树
定时器基本函数解析
1.定时器初始化
2.时基单元初始化
3.时基单元赋个默认值
4.定时器使能
5.定时器中断输出控制配置
6~11 外部时钟选择
6.内部时钟
7.ITRx其他定时器的时钟
8.选择TIx捕获通道的时钟
9.ETR通过外部时钟1输入的时钟
10.ETR通过外部时钟2输入的时钟
11.配置ETR引脚的预分频器、极性、滤波器
12.写预分频值
13.改变计时器的计时模式
14.配置有无预装时序
15.手动设置计数值
16.给自动重装器写一个值
17.获取当前计数器的值
18.获取当前预分频的值
19~22 获取,清除中断标志位(带IT为在中断中使用)
定时中断
初始化代码如下 timer.c
#include "stm32f10x.h" // Device header
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//RCC时钟定时器使能开启
TIM_InternalClockConfig(TIM2);//指定内部时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//时基单元配置
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数器模式
TIM_TimeBaseInitStructure.TIM_Period=10000-1;
//时基单元ARR自动重装器(计多少个数)的值0~65535
TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;
//时基单元PSC预分屏器(计数频率)的值0~65535
//计数器溢出频率CK_CNT_OV = CK_PSC(72Mhz)/ (PSC + 1) / (ARR + 1)
//这里是在10k的频率(72Mhz/7200)下计10000个数 1s=1hz
//这里没有时基单元CNT计数器,需要的可以使用SetCounter和GetCounter来操作
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//(高级定时器)重复计数器的值
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
//这里的作用很细节,在TIM_TimeBaseInit中的最后一句
//TIMx->EGR = TIM_PSCReloadMode_Immediate;(生成一个更新事件,重新装载预分频器和重复计数器
//的值,立刻)
//这样会让更新事件和更新中断同时发生,从而一上电中断标志位就成了SET,就立刻进入了中断
//因此要养成初始化清除标志位的好习惯
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//中断控制:更新中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructrue;
NVIC_InitStructrue.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructrue.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructrue.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructrue.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructrue);
TIM_Cmd(TIM2,ENABLE);
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
注意:
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
这里的作用很细节,在TIM_TimeBaseInit中的最后一句
TIMx->EGR = TIM_PSCReloadMode_Immediate;(生成一个更新事件,重新装载预分频器和重复计数器的值,立刻)
这样会让更新事件和更新中断同时发生,从而一上电中断标志位就成了SET,就立刻进入了中断
因此要养成初始化清除标志位的好习惯
外部时钟(中断可不用)
初始化代码如下 timer.c
TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_Inverted,0x0F);
//ETR外部时钟2指定计时器,预分频器(有预分频器则多少次CNT才加1),极性,滤波器
极性:
TIM_ExtTRGPolarity_Inverted下降沿计数一次
TIM_ExtTRGPolarity_NonInverted上升沿计数一次
ExtTRGFilter:
外部滤波:在固定频率F下采样,连续N个采样点都为相同的电平,那么代表信号稳定,则输出采样值。 若不同就有抖动,保持上一个采样值,或者输出低电平,频率越低采样数越高,效果越好,但是信号延迟会变大
#include "stm32f10x.h" // Device header
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//RCC时钟定时器使能开启
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructrue;
GPIO_InitStructrue.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructrue.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructrue.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructrue);
TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_Inverted,0x0F);
//ETR外部时钟2指定计时器,预分频器(有预分频器则多少次CNT才加1),极性,滤波器
//TIM_InternalClockConfig(TIM2);//指定内部时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//时基单元配置
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数器模式
TIM_TimeBaseInitStructure.TIM_Period=10-1;//时基单元ARR自动重装器(计多少个数)的值0~65535
TIM_TimeBaseInitStructure.TIM_Prescaler=1-1;//时基单元PSC预分屏器(计数频率)的值0~65535
//计数器溢出频率CK_CNT_OV = CK_PSC(72Mhz)/ (PSC + 1) / (ARR + 1)
//这里是在10k的频率(72Mhz/7200)下计10000个数 1s=1hz 1000hz=1ms 10000hz=1us
//这里没有时基单元CNT计数器,需要的可以使用SetCounter和GetCounter来操作
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//(高级定时器)重复计数器的值
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
//这里的作用很细节,在TIM_TimeBaseInit中的最后一句
//TIMx->EGR = TIM_PSCReloadMode_Immediate;(生成一个更新事件,重新装载预分频器和重复计数器的值,立刻)
//这样会让更新事件和更新中断同时发生,从而一上电中断标志位就成了SET,就立刻进入了中断
//因此要养成初始化清除标志位的好习惯
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//中断控制:更新中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructrue;
NVIC_InitStructrue.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructrue.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructrue.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructrue.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructrue);
TIM_Cmd(TIM2,ENABLE);
}
uint16_t Timer_GetCounter(void)
{
return TIM_GetCounter(TIM2);
}
//void TIM2_IRQHandler(void)
//{
// if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
// {
//
// TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
// }
//
//}