
STM32F103系列的单片机一共有11个定时器: 2个高级定时器 4个通用定时器 2个基本定时器 2个看门狗定时器 1个系统滴答定时器 除去看门狗定时器和滴答定时器,其他8个定时器列表: ![]() 其中, TIM1和TIM8是高级定时器 TIM2 - TIM5是通用定时器 TIM6和TIM7是基本定时器 这8个定时器都是16位的,它们计数的类型除了基本定时器TIM6和TIM7,都支持向上、向下、向上/向下3种计数模式。 计数器的3种计数模式: 向上计数模式:从0开始,计到arr预设值,产生溢出事件,返回重新计时; 向下计数模式:从arr预设值开始,计到0,产生溢出事件,返回重新计时; 中央对齐模式:从0开始向上计数,计到arr产生溢出事件,然后向下计数,计数到1以后,又产生溢出,然后再从0开始向上计数(这种计数方式也叫向上/向下计数)。 基本定时器(TIM6和TIM7)主要功能: 只有最基本的定时功能。基本定时器TIM6和TIM7各包含一个16位自动装载计数器,由各自的可编程预分频器驱动。 通用定时器(TIM2 - TIM5)主要功能: 除了基本的定时器的功能外,还可以测量输入信号的脉冲长度( 输入捕获) 或者产生输出波形( 输出比较和PWM)。 高级定时器(TIM1和TIM8)主要功能: 高级定时器不但具有基本、通用定时器的所有的功能,还具有控制交直流电动机的所有功能。比如它可以输出6路互补带死区的信号,刹车功能等等。 通用定时器的时钟来源: a. 内部时钟(CK_INT) b. 外部时钟模式1:外部输入脚(TIx) c. 外部时钟模式2:外部触发输入(ETR) d. 内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器 自动装载寄存器arr值得计算: Tout = ((arr + 1)*(psc + 1))/Tclk; Tclk:TIMx的输入时钟频率(单位:MHz) Tout:TIMx的溢出时间(单位:us) eg: 计时1秒,输入时钟频率为72MHz,psc预分频的值为35999,那么,((arr + 1)*(psc + 1))/72M = ((arr + 1)*(35999 + 1))/72M = 1s,就可以求解出自动预装载寄存器arr = 1999。 定时器每次计数到预设值后,会产生一次中断更新事件,进入中断服务函数。因此,每个定时器有一个或者多个对应的中断处理函数的入口。 对于STM32F103C8T6,需要注意的是,这款芯片没有基本定时器TIM6和TIM7。它的中断服务函数名如下: ![]() 不知小伙伴们还记不记得上一篇的精准延时?没错啦,精准延时那里就用到了系统滴答定时器。 ARM Cortex-M3内核中有一个Systick定时器,它是一个24位(0~(2^24-1))的倒计数定时器,这个脉冲计数值保存在当前计数值寄存器STK_VAL(Systick current value register)中,当计数到0时,它就会从Load寄存器中自动重装定时初值,只要不把CTRL寄存器中的ENABLE清0,它就永不停。 Systick定时器只能向下计数,每接收到一个时钟脉冲,STK_VAL的值就会向下减1,当减到0时,硬件会自动把重装载寄存器STK_LOAD(Systick reload value register)中保存的数据加载到STK_VAL,重新开始向下计数。如果STK_VAL的值被减至0时,会触发异常产生中断。所以,小伙伴们不要因为好玩,在程序里写一句 delay_ms(0) 或 delay_us(0)。这样会触发异常产生中断,到时你就找不着北啦~ 既然提到了精准延时,那这次小R给小伙伴们分享更加准确的LED灯闪烁时间,我们使用通用定时器中断来实现LED灯闪烁: 1. 新建两个文件,tim.c 和 tim.h ![]() 2. 在头文件 tim.h 添加下面代码:
![]() 3. 把 tim.c 添加到工程中 ![]() 4. 在 tim.c 中添加以下代码:
定时器中断配置步骤: 1. NVIC优先级组配置 2. 使能定时器时钟 3. 初始化定时器 4. 设置定时器允许更新中断 5. 设置定时器中断优先级 6. 使能定时器 7. 编写中断服务函数 ![]() ![]() 5. 实现定时器更新中断LED灯闪烁功能
![]() 需要注意的是:在中断函数中需要检验一下标志位,因为定时器的所有事件共用一个中断。但只使用更新中断不用检验也是没有问题滴。 |