1.简介
STM32F103系列的单片机一共有11个定时器,其中:
- 2个高级定时器(TIM1、TIM8)
- 4个通用定时器(TIM2、3、4、5)
- 2个基本定时器(TIM6、7)
- 2个看门狗定时器(WWDG,IWDG)
- 1个系统嘀嗒定时器
基本定时器功能(TIM6、TIM7):
- 16位向上、向下、向上/下自动装载计数器
- 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意数值
- 触发DAC的同步电路 注:此项是TIM6/7独有功能.
- 位于APB1总线上
通用定时器(TIM2~TIM5)的主要功能:
通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。
它适用于多种场合,包括测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)。
使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。
每个定时器都是完全独立的,没有互相共享任何资源。
高级定时器(TIM1,TIM8)的主要功能:
高级定时器具有基本,通用定时器的所有的功能,
还具有控制交直流电动机所有的功能,
输出6路互补带死区的信号,刹车功能等等
位于APB2总线上
总括:基本定时器就是单纯的定时计数器,通用定时器多了四个通道,相对应的增加了功能,高级定时器具有基本,通用定时器的所有的功能,并且添加了其他功能
2.定时器原理图
以通用定时器的原理图为例子:
通用定时器原理图可以分为四部分:时钟生成、时基、输入捕获、输出,在这五部分中,基础定时器只有个时钟生成部分。
一、时钟生成部分:
图中1部分:1、RCC寄存器中的APB1外设时钟使能寄存器,经过倍频之后输出时钟源,这是因为该寄存器的位0到位5分别表示的是定时器2到定时器7的使能位。(位于图上第一部分)2、外部触发引脚TIMx_ETR的外部触发输入ETR,对应的引脚可以通过查数据手册得到。ETR经过分频得到ETRP,在经过滤波得到ETRF作为时钟信号。(位于图上第一部分)
3、内部触发输入(ITRx),来自其他的定时器的时钟,即将,经过后面的选择器,进入到触发控制器。(位于图上第一部分)
4、外部输入引脚Tix,这个主要来自于TIMx_CHx (四个通道)。(位于图上第四部分)
上图第二部分也属于时钟生成部分,即是时钟生成后经过触发器到其他定时器或者到dac和adc中去
二 时基部分:
这也是定时器的主要部分这部分主要是3这一部分,包括PSC预分频器、自动重装载寄存器和CNT计数器。首先由第一部分产生时钟源,进入PSC预分频器进行分频处理,得到新的时钟信号CK_CNT,使得CNT计数器加1或者减1,此时在自动重装载寄存器中有一个预先设定的装载值,当计数器的值达到装载值的时候,会产生溢出事件,然后触发中断。如何去计算时间后边会附上
三、输入捕获部分:
上图中4,TIMx_CH1——TIMx_CH4 这四个通道,在芯片中都有对应的引脚,当脉冲从通道口进入时,经过输入滤波器(抗干扰的作用),然后经过边沿检测器检测到上升沿(下降沿),经过分频器,输入到公用部分中的捕获寄存器中,然后捕获寄存器记录此刻CNT计数器的值,当下一次下降沿(上升沿)过来时,也记录下CNT计数器的值,这样就可以计算出输入脉冲的宽度。
四、输出比较部分(注意输入捕获和输出比较不可以同时进行)
上图中5,比如在比较寄存器中预先设定一个值,计数器从初始值到装载值之间计数时,当正好等于比较寄存器中的预设值时,控制TIMx_CH1——TIMx_CH4通道输出低电平或者高电平,这样随着计数器不断的计数,就可以获得一个脉冲,通过调整预设值,就可以调整脉冲宽度,调整初始值和装载值就可以调整周期就如同一个闹钟一样。
定时器计数模式
通用定时器可以向上计数、向下计数、向上向下双向计数模式。
向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
简单地理解三种计数模式,可以通过下面的图形:
计数时钟的选择
计数器时钟可由下列时钟源提供:
内部时钟(TIMx_CLK)
外部时钟模式1:外部捕捉比较引脚(TIx)
外部时钟模式2:外部引脚输入(TIMx_ETR) 仅适用TIM2,3,4
内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。
定时器的主从模式: (选看)
定时器一般是通过软件设置而启动,STM32的每个定时器也可以通过外部信号触发而启动,还可以通过另外一个定时器的某一个条件被触发而启动。这里所谓某一个条件可以是定时到时间、定时器超时、比较成功等许多条件。
这种通过一个定时器触发另一个定时器的工作方式称为定时器的同步,发出触发信号的定时器工作于主模式,接受触发信号而启动的定时器工作于从模式
触发条件:
2.工程创建:
1设置RCC
设置高速外部时钟HSE 选择外部时钟源(老生常谈)
2.设置时钟树
3.定时器设置
前两个选项是选择主从模式的,用不到,默认关闭就好。
第三个clock source是时钟来源选择,里面有两个选项
- 选项1 :Internal Clock 内部时钟
- 选项2 : ETR2 外部触发输入(ETR)(仅适用TIM2,3,4)
这里选内部时钟就好
接下来设置一些定时器的参数
Prtscaler (定时器分频系数) : 7199
Counter Mode(计数模式) Up(向上计数模式)
Counter Period(自动重装载值) : 4999
CKD(时钟分频因子) : No Division 不分频
TRGO Parameters 触发输出 (TRGO) 不使能 与本节无关
TRGO: 定时器的触发信号输出 在定时器的定时时间到达的时候输出一个信号(如:定时器更新产生TRGO信号来触发ADC的同步转换)
使能定时器中断:
接下来选择一个引脚连到灯上,方便我们来看定时器的效果。
这里我的板子是PE5连到了灯,就设置PE5.
接下来就创建工程
3.函数讲解
我们上面的工程只是设置了定时器最基本的计数功能,即是当计数器数到某个特定的值溢出时,就触发中断,且自动重装。
那就说下定时器中断处理函数:
定时器中断处理函数:
HAL_TIM_IRQHandler(&htim2);
此函数的作用是判断中断是否正常,是哪一类定时器中断(溢出中断/捕获中断/PWM中断…),然后进入相应的中断回调函数
在stm32f4xx_it.c可以找到TIM2_IRQHandler()定时器处理函数:
通过中断函数我们可以看到相应的中断回调函数
定时器中断回调函数:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
在HAL库中,每进行完一个中断,并不会立刻退出,而是会进入到中断回调函数中,
这里我们使用的是定时器的溢出中断回调函数,流程一般如下:
- 首先进入中断函数( void TIM3_IRQHandler(void) )->
- 之后进入定时器中断处理函数 ( HAL_TIM_IRQHandler(&htim2) ) ->
- 判断产生的是哪一类定时器中断(溢出中断/PWM中断.....) 和定时器通道 ->
- 进入相对应中断回调函数 (void HAL_TIM_PeriodElapsedCallback(&htim2)) ->
接下来我们就需要重新编写我们需要的中断回调函数了。
接下来讲解一下我们中断溢出时间的计算公式:
定时器溢出时间:
这里我们 arr=4999 psc=7199 Tclk=72Mhz Tout = (5000*7200)/72 us = 500ms
接下就改下中断回调函数看下效果:
在这之前我们要先开启一下定时器
在main.c主函数上方初始化使能定时器2
/* USER CODE BEGIN 2 */
/*使能定时器1中断*/
HAL_TIM_Base_Start_IT(&htim2);
/* USER CODE END 2 */
在main.c主函数下方添加中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static unsigned char ledState = 0;
if (htim == (&htim2))
{
if (ledState == 0)
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_15,GPIO_PIN_RESET);
else
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_15,GPIO_PIN_SET);
ledState = !ledState;
}
}
OK,结束。