STM32定时器定时及其应用
- 定时器概述
- ☆定时器相关配置
- CubeMX工程配置及程序实现
- 固件库程序设计及实现
定时器概述
-
1. 工作原理
使用精准的时基,通过硬件的方式,实现定时功能。定时器核心就是计数器
-
2. 定时器分类
基本定时器(TIM6~TIM7)
通用定时器(TIM2~TIM5)
高级定时器(TIM1和TIM8)定时器类型 主要功能 基本定时器 没有输入输出通道,常用作时基,即定时功能 通用定时器 具有多路独立通道,可用于输入捕获/输出比较,也可用作时基 高级定时器 除具备通用定时器所有功能外,还具备带死区控制的互补信号输出刹车输入等功能 -
3. STM32F103C8T6资源
-
4. 通用定时器介绍
- 16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。
- 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。
- 4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
A.输入捕获
B.输出比较
C.PWM 生成(边缘或中间对齐模式)
D.单脉冲模式输出 - 可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
- 如下事件发生时产生中断/DMA:
A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
C.输入捕获
D.输出比较
-
5. 定时器计数模式
计数模式 计数器溢出值 计数器重装值 向上计数 CNT = ARR CNT = 0 向下计数 CNT = 0 CNT = ARR 中心对齐计数 CNT = ARR - 1 CNT = ARR CNT = 1 CNT = 0
-
6. 定时器时钟源
- 时钟源:定时器时钟TIMxCLK,即内部时钟CK_INT,经APB预分频后分频提供
- 计数器时钟:定时器时钟经过PSC预分频器之后,即CK_CNT,用来驱动计数器计数。
- 计数器CNT:是一个16位/32的计数器
- 自动重装载寄存器:这里面装着的计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。
- 计数中断时间:1/(TIMxCLK/(PSC+1))*(ARR+1))
-
7. 定时器溢出时间公式☆
例如,要定时500ms,则:PSC=7199,ARR=4999,Tclk=72M
☆定时器相关配置
- 使能时钟配置
- 定时器参数配置
- NVIC中断配置
- 中断服务函数
CubeMX工程配置及程序实现
-
时钟配置
- 采用外部高速晶振
- 时钟树配置
- 采用外部高速晶振
-
定时器配置
-
开启定时器
-
参数设置
-
使能中断NVIC
-
-
程序设计
//初始化TIM2用于计时 HAL_TIM_Base_Start_IT(&htim2); //定时器中断服务程序 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if( htim->Instance == TIM2) { HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin); } }
固件库程序设计及实现
-
使能时钟配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //初始化定时器时钟
-
定时器结构体配置
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定时器结构体定义 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //不分频 TIM_TimeBaseStructure.TIM_Prescaler = psc; //设置预分频系数 TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseInit( TIM2, &TIM_TimeBaseStructure ); //初始化结构体 TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE); //使能中断 允许更新中断源 TIM_Cmd( TIM2, ENABLE); //使能定时器2
-
NVIC中断配置
NVIC_InitTypeDef NVIC_InitStructure; //NVIC结构体定义 //NVIC初始化 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //中断通道 TIM2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级 NVIC_Init(&NVIC_InitStructure); //初始化NVIC结构体
-
定时器2初始化函数设计
void TIM2_Init(u16 psc, u16 arr) //500ms { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //初始化定时器时钟 //定时器初始化 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //不分频 TIM_TimeBaseStructure.TIM_Prescaler = psc; TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit( TIM2, &TIM_TimeBaseStructure ); //初始化结构体 TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE); //使能中断 允许更新中断源 //NVIC初始化 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure); TIM_Cmd( TIM2, ENABLE); //使能定时器2 }
-
中断服务函数
//TIM2 中断服务函数 void TIM2_IRQHandler(void) { if( TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET ) //中断标志位判断,确认进入中断 { LED1 = !LED1; TIM_ClearFlag(TIM2, TIM_IT_Update); //清除中断标志位 } }