前言:定时器分为普通和特殊定时器,我们可以利用定时器监测电平变化(上升沿,下降沿),并记录下变化的时间,通常可以用来测量外部信号的频率或者电平持续的时间。高级控制定时器比通用定时器增加了可编程死区互补输出、重复计数器、带刹车(断路)功能,这些功能都是针对工业电机控制方面。另外可以用定时器的方式来解决中断中不能加延时函数的问题。
目录
2、实验要求:利用定时器2的输入捕获功能测量按下KEY6键后低电平持续的时间
一、定时器介绍
1、STM32F4定时器介绍
- STM32F4xx 系列微控制器具有多达14个定时器。
- 其中包括2个基本定时器,10 个通用定时器2个高级定时器
- 其中最大定时器时钟可通过 RCC_DCKCFGR 寄存器配置为 84MHz 或者 168MHz。一般是默认配置
定时器计数模式:
(1)向上计数模式计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
(2)向下计数模式计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
(3)中央对齐模式(向上/向下计数)计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。它的工作原理是先从0开始计数到自动加载值(TIMx_ARR)产生事件,但不跳跃回0,而是继续向下计数到0产生事件,又开始从0计数到自动加载值(TIMx_ARR),如此反复。
2、几种定时器功能比较
基本定时器TIM功能
主要运用于定时计数以及驱动DAC
通用定时器TIM功能
定时器定时计数●
输入捕获
输出比较
PWM输出●
使用外部信号控制定时器和定时器互连的同步电路
高级定时器TIM功能
通用定时器的有功能带死区控制和紧急刹车,可用于PWM控制电机
3、定时器的计数原理
数据手册,对应不同的APB总线
定时器时钟遵循一个公式,如果分频需要*2,否则就是*1
定时器的时基部分
1时钟源:定时器时钟 TIMxCLK,即内部时钟 CK_INT,经 APB 预分频器后分频提供
2计数器时钟:定时器时钟经过 PSC 预分频器之后,即 CK_CNT,用来驱动计数器计数 计数器3CNT: 是一个 16 位/32的计数器
4自动重装载寄存器:这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断
计时中断时间: 1/(TIMxCLK/(PSC+1)) * (ARR+1)
4、定时器输入捕获与输出比较
(1)输入捕获
输入捕获可以用来捕获外部事件,比如引脚的电平变化(上升沿,下降沿),并记录下变化的时间,通常可以用来测量外部信号的频率或者电平持续的时间。
(2)输出比较
此项功能是用来控制一个输出波形,当计数器与捕获/比较寄存器的内容相同时,输出比较功能做出相应动作,比如电平的翻转。通常用于生产PWM波形
二、定时间中断实验
实验: 利用基本定时器实现定时1秒中断,并在中断处理函数中打印输出字符
1、cubmx配置
(1)打开TIM6,并设置中断
(2)设置系统时钟,tim6对应APB2时钟频率84Mhz
(3)1S=1/(84M/psc预分频器16位(设置8400-1))*arr自动重新装载计数器16位(设置10000-1)16位最大是2^16。
上面图中写错了,计数1相当于10ms,1秒/(1000000/10000)=1/100秒
(4) 生成keil文件,找到回调函数,写一个printf的重定向文件,然后利用TIM6串口打印一条信息。这里用到一个HAL函数HAL_TIM_Base_Start_IT(&htim6)
int fputc(int ch ,FILE *p){
while(!(USART1->SR & (1<<7)));
USART1->DR = (uint8_t)ch;
return ch;
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
*
* @retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM6_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("uart is ok\r\n");
HAL_TIM_Base_Start_IT(&htim6);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM6)
{
printf("TIM6\r\n");
}
}
(5)实验效果
三、高级定时器功能分析
1、定时器通道
高级控制定时器比通用定时器增加了可编程 死区互补输出、重复计数器、带刹车(断路)功能,这些功能都是针对工业电机控制方面。

数据手册2.2,查看再哪个APB总线上。数据手册3引脚,查看复用功能是否含有定时器TIM
2、高级定时器功能框图
①时钟源②控制器③时基单元④输入捕获⑤公共部分⑥输出比较
(1)时钟源
- 内部时钟 (CK_INT)
- 外部时钟模式 1:外部输入引脚TIx(x=1,2,3,4)
- 外部时钟模式 2:外部触发输入 ETR(专用引脚)
- 外部触发输入 (ITRx):使用一个定时器作为另一定时器的预分频器,例如,可将定时器1 配置为定时器 2 的预分频器。(串联)
- 注:一般情况下,我们都是使用内部时钟
(2)控制器
高级控制定时器控制器部分包括触发控制器、从模式控制器以及编码器接口。
- 触发控制器用来针对片内外设输出触发信号,比如为其它定时器提供时钟和触发 DAC/ADC 转换。
- 编码器接口专门针对编码器计数而设计。
- 从模式控制器可以控制计数器复位、启动、递增/递减、计数。
(3)时基单元
高级控制定时器时基单元包括四个寄存器
- 预分频器 PSC:对输入时钟进行分频得到计数器的驱动时钟CK_CNT
- 计数器 CNT: 在外部时钟的驱动下实时的进行计数
- 自动重载寄存器 ARR:用来存放与计数器 CNT 比较的值,如果两个值相等就递减重复计数器。
- 重复计数器 RCR:高级定时器特有,在定时器发生上溢或下溢事件时递减重复计数器的值,只有当重复计数器为 0 时才会生成更新事件
(4)输入捕获
输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,常用来测量输入信号的脉宽和频率。TIMx_chx是外部得输入信号,通过输入滤波器(例如高于1M的信号屏蔽)和边沿检测器进行监测。预分屏器如果是2,就是2次上升沿或下降沿再去记录1次。
原理:监测到上升沿或下降沿信号时,会通过捕获寄存器CCR保存CNT的值,然后继续等待第二次信号得监测,获取之后进行比较。
(5)公共部分
CCR寄存器计入cnt得值,可以配置为比较寄存器
(6)输出比较
- 输出比较就是通过定时器的计数比较控制外部引脚对外输出高低电平
- 比较输出有很多种模式,其中PWM模式是输出比较中使用的最多的模式。
(7)死区控制、互补输出
高级定时器还多了中间这部分功能
高级控制定时器比通用定时器增加了可编程死区互补输出功能,常应用在工业电机控制方面。上图中的延时就是一个死区控制。
四、输入捕获实验
输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,常用来测量输入信号的脉宽和频率。输入捕获模式可以用来测量频率或者电平持续的时间。
1、输入捕获测量低电平举例:
假定定时器工作在向上计数模式,图中t1-t2的时间就是我们需要测量的低电平时间。测量方法为:首先设置定时器通道x为下降沿捕获,在t1时刻就会捕获到当前的CNT值,然后立即清零CNT,并设置通道x为上升沿捕获,到t2时刻又会发送捕获事件,得到此时的CNT值(记为CCRx2)。在t1-t2之间可能产生N次定时器溢出,因此需要对定时器溢出做处理,防止低电平太长导致数据不准确。
t1-t2之间计数的次数为:N * ARR + CCRx2,再乘以CNT计数周期即可得到低电平持续时间
2、实验要求:利用定时器2的输入捕获功能测量按下KEY6键后低电平持续的时间
stm32f4xx_hal_tim.h
(1)根据原理图
只有PA0 KEYUP复用到了定时器功能,对应TIM5、TIM2
(2)cubmx配置
(3) rcc配置
(4)key_up需要设置下拉,需要配置
(5) 使能中断:中断中处理捕获
(6)keil实现函数功能
a.printf重写,引入两个使能中断函数,溢出更新中断,输入捕获使能中断
int fputc(int ch,FILE *p)
{
while(!(USART1->SR & (1<<7)));
USART1->DR = (uint8_t) ch;
return ch;
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
*
* @retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM5_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim5);
HAL_TIM_IC_Start_IT (&htim5, TIM_CHANNEL_1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
b.中断处理入口函数都在it.c文件内点进去
c.输入捕获回调函数和定时回调函数重写,这里我们把函数写在tim.c下面
/* USER CODE BEGIN 1 */
uint8_t rise_flag = 0;//设置一个上升捕获标志位
uint32_t cap_value =0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
//1.È·ÈÏÊÇ·ñÊÇTIM5
if(htim->Instance == TIM5)
{
if(!rise_flag)
{
printf(“捕获到了上升沿\r\n");
HAL_Delay(20);
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_SET) //按键消抖
{
rise_flag = 1;
//关闭定时器,清除CNT计数器
__HAL_TIM_DISABLE(htim);
__HAL_TIM_SET_COUNTER(htim,0);
//清除定时器原来的设置,设置为下降沿监测
TIM_RESET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1);
TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);
//开启定时器
__HAL_TIM_ENABLE(htim);
}
}
else
{
printf("捕获到了下降沿\r\n");
rise_flag = 0;
//
//最终的时间=溢出的时间+两次计数差值+消抖时间
cap_value = cap_value + HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1) + 20000 ;
printf("高电平持续时间= %d秒:%d毫秒:%d微妙\r\n",cap_value/1000000,cap_value%1000000/1000,cap_value%1000);
cap_value = 0;
__HAL_TIM_DISABLE(htim); //关闭定时器
TIM_RESET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1); //清除原来的设置
TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING); //设置为上升沿捕获
__HAL_TIM_ENABLE(htim); //开启定时器
HAL_Delay(20);
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim->Instance == TIM5)
{
if(rise_flag)
{
cap_value += 1000000;
printf("update int \r\n");
}
}
}
3、实验展示
STM32定时器实验用例-按键捕获实验演示