注:本文属博主学习时所作笔记,内容源大参考于野火的《零死角玩转STM32F103》以及部分网络资料,笔记内容仅作为自己参考,免去频繁查询参考手册的麻烦,如有错误,还请指出!
定时器分类
STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器。
类别 |
定时器 |
分辨率 |
计数器类型 |
预分频系数 |
产生DMA |
捕获/比较通道 |
互补输出 |
高级定时器 |
TIM1,TIM8 |
16位 |
向上/向下 |
1~65535 |
可以 |
4 |
有 |
通用定时器 |
TIM2~TIM5 |
16位 |
向上/向下 |
1~65535 |
可以 |
4 |
无 |
基本定时器 |
TIM6,TIM7 |
16位 |
向上 |
1~65535 |
可以 |
0 |
无 |
基本定时器
时钟源 TIMxCLK由APB1预分频提供,库函数中 APB1 预分频系数为 2 ,定时器时钟TIMxCLK = 36 * 2 =72
计数器时钟 CK_CNT 经 PSC 得到,PSC是16位预分频器,可对 TIMxCLK 进行1~65536 之间任意一个数进行分频:CK_INT=TIMxCLK/(PSC + 1)
计数器 CNT 是一个16位的计数器,只能向上计数,最大值位65535,计数值到达自动重装载寄存器时,产生更新时间,清零重新计数
自动重装载寄存器 ARR 是一个16位计数器,存放最大计数值,到达此值,如果开启中断,则定时器产生中断
定时时间计算
定时器的定时时间等于计数器的中断周期乘以中断的次数。这里用定时 500ms 作为例子:
- 设置PSC预分频器为 72 - 1 = 71 MHz,则定时器频率为 72M/(PSC + 1) = 1 MHz
- 设置 ARR = 1000 - 1,0 ~ 999,计数1000次
- 中断周期 T = 1000 * 1 / 1000000 = 1 ms,(1MHz 周期为 1 ns)
定时器初始化结构体
基本定时器只用到TIM_TimeBaseInitTypeDef
结构体:
1 2 3 4 5 6 7
| typedef struct { uint16_t TIM_Prescaler; uint16_t TIM_CounterMode; uint32_t TIM_Period; uint16_t TIM_ClockDivision; uint8_t TIM_RepetitionCounter; } TIM_TimeBaseInitTypeDef;
|
而且只用到两个成员TIM_Prescaler
和TIM_Period
,也就是定时器分配器设置和定时器周期(自动重装载寄存器值)。
代码实例——实现 1s 定时
初始化基本定时器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
#define BASIC_TIM6
#ifdef BASIC_TIM6 #define BASIC_TIM TIM6 #define BASIC_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define BASIC_TIM_CLK RCC_APB1Periph_TIM6 #define BASIC_TIM_IRQ TIM6_IRQn #define BASIC_TIM_IRQHandler TIM6_IRQHandler
#else #define BASIC_TIM TIM7 #define BASIC_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define BASIC_TIM_CLK RCC_APB1Periph_TIM7 #define BASIC_TIM_IRQ TIM7_IRQn #define BASIC_TIM_IRQHandler TIM7_IRQHandler
#endif
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| void BASIC_TIM_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);
TIM_TimeBaseStructure.TIM_Period=1000;
TIM_TimeBaseStructure.TIM_Prescaler= 71;
TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStructure);
TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);
TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);
TIM_Cmd(BASIC_TIM, ENABLE);
BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, DISABLE); }
|
把定时器设置自动重装载寄存器 ARR 的值为 1000,设置时钟预分频器为 71,则驱动计数器的时钟: CK_CNT = CK_INT / (71+1)=1M,则计数器计数一次的时间等于:1/CK_CNT=1us,当计数器计数到 ARR 的值 1000 时,产生一次中断,则中断一次的时间为: 1/CK_CNT*ARR = 1ms。
定时器中断优先级配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void BASIC_TIM_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM_IRQ ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
|
定时器中断服务程序
1 2 3 4 5 6 7
| void BASIC_TIM_IRQHandler (void) { if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET ) { time++; TIM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update); } }
|
定时器中断一次的时间是 1ms,定义一个全局变量 time 表示中断次数。实现一个 1s 的定时,只需判断 time 是否等于 1000 即可, 1000 * 1ms = 1s。然后把 time 清 0,重新计数,在最后,需要将中断标志位清除掉。
主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| int main(void) { LED_GPIO_Config();
BASIC_TIM_Config();
BASIC_TIM_NVIC_Config();
BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);
while (1) { if ( time == 1000 ) { time = 0; LED1_TOGGLE; } } }
|
代码实例——获取指令执行时间