STM32F103定时器中断详解
目录
目录
目录
前言
一.什么是定时器
1.1 STM32F103定时器概述
1.2基本定时器
1.2通用定时器
1.3高级定时器
1.4 三种定时器区别
基本定时器(Basic Timer)
通用定时器(General-Purpose Timer)
高级定时器(Advanced Timer)
二.时基单元结构(重点)
2.1重点掌握
2.2 PSC预分配器
2.3自动重装载寄存器
2.4 CNT 计数器
2.5计数模式
三.通用定时器中断配置步骤
四.相关代码
4.1 定时器中断初始化
4.2 主函数代码
前言
详细图解介绍:自动重装载寄存器,CNT计算器,PSC预分频器的工作原理。通用定时器通过PSC预分频器把接入的72MHZ的时钟进行分频。再通过CNT以分频后的时钟频率进行计数。定时器TIMx分为三种定时器:(基本定时器、通用定时器、高级定时器)接下来逐个介绍.....
一.什么是定时器
1.1 STM32F103定时器概述
定时器就是计数器:
定时器是一种电子设备或软件模块,用于测量时间间隔或生成周期性信号。它广泛应用于各
种电子系统和计算机程序中,用于控制时间相关的任务,如调度、测量、同步等。
定时器的工作原理:
定时器通常有一个计数器,它可以从预设的初始值开始递增或递减。当计数器达到特定的值时,可以触发一个事件或中断,通知系统进行特定的操作。
TIMx简介
通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。 它适用于多种场合,包括测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)。 使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个 毫秒间调整。 每个定时器都是完全独立的,没有互相共享任何资源。它们可以一起同步操作。
定时器TIMx分为三种定时器:(基本定时器、通用定时器、高级定时器)接下来逐个介绍
1.2基本定时器
基本定时器:(TIM6和TIM7)
TIM6和TIM7定时器的主要功能包括:
● 16位自动重装载累加计数器
● 16位可编程(可实时修改)预分频器,用于对输入的时钟按系数为1~65536之间的任意数值 分频
● 触发DAC的同步电路
● 在更新事件(计数器溢出)时产生中断/DMA请求
1.2通用定时器
通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:
● 16位向上、向下、向上/向下自动装载计数器
● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意 数值
● 4个独立通道:
─ 输入捕获
─ 输出比较
─ PWM生成(边缘或中间对齐模式)
─ 单脉冲模式输出
● 使用外部信号控制定时器和定时器互连的同步电路
● 如下事件发生时产生中断/DMA:
─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) ─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
─ 输入捕获
─ 输出比较
● 支持针对定位的增量(正交)编码器和霍尔传感器电路
● 触发输入作为外部时钟或者按周期的电流管
1.3高级定时器
TIM1和TIM8定时器的功能包括:
● 16位向上、向下、向上/下自动装载计数器
● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意 数值
● 多达4个独立通道:
─ 输入捕获
─ 输出比较
─ PWM生成(边缘或中间对齐模式)
─ 单脉冲模式输出
● 死区时间可编程的互补输出
● 使用外部信号控制定时器和定时器互联的同步电路
● 允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器
● 刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态
● 如下事件发生时产生中断/DMA:
─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
─ 输入捕获
─ 输出比较
─ 刹车信号输入
● 支持针对定位的增量(正交)编码器和霍尔传感器电路
● 触发输入作为外部时钟或者按周期的电流管理高级控制定时器(TIM1和TIM8)
1.4 三种定时器区别
在微控制器中,定时器通常根据其功能和复杂性被分为不同的类型,包括基本定时器、通用定时器和高级定时器。以下是这三种定时器的比较:
基本定时器(Basic Timer)
- 功能:基本定时器通常提供最基本的计时功能,如计数器、简单的中断和事件触发。
- 计数模式:一般只支持向上计数或向下计数。
- 输入捕获:可能不支持输入捕获功能,即无法捕获外部信号的精确时间。
- 输出比较:可能只支持简单的输出比较功能,用于生成单一的PWM信号或简单的定时事件。
- 通道数量:通常只有一个通道或非常有限的通道数量。
- 中断:可能只提供单一的中断源。
通用定时器(General-Purpose Timer)
- 功能:通用定时器比基本定时器提供更多的功能,如更复杂的计数模式、多个输入/输出比较和捕获通道。
- 计数模式:支持多种计数模式,包括向上计数、向下计数、中心对齐模式等。
- 输入捕获:支持输入捕获功能,可以捕获外部事件的精确时间。
- 输出比较:支持多个输出比较通道,可以用于生成多个PWM信号或控制多个定时事件。
- 通道数量:通常有多个通道,可以进行更复杂的时间控制。
- 中断:提供多个中断源,可以根据不同的事件触发中断。
高级定时器(Advanced Timer)
- 功能:高级定时器提供最复杂的功能,包括高级计数模式、多个高级输入/输出比较和捕获通道,以及通信接口同步等。
- 计数模式:支持所有通用定时器的计数模式,可能还包括编码器模式、霍尔传感器接口等。
- 输入捕获:支持高级输入捕获功能,可以进行时间间隔测量、脉冲计数等。
- 输出比较:支持多个高级输出比较通道,可以生成复杂的PWM信号或控制多个高级定时事件。
- 通信接口同步:可以与其他定时器或通信接口同步,实现复杂的同步操作。
- 死区控制:在PWM信号生成中,支持死区时间设置,用于提高电机控制的稳定性。
- 中断:提供丰富的中断源,可以根据多种事件触发中断。
总结来说,基本定时器通常功能较为简单,适用于不需要复杂控制的应用。通用定时器和高级定时器则提供了更多的功能和灵活性,适用于更复杂的定时和控制任务。
二.时基单元结构(重点)
2.1重点掌握
时基单元结构:接下来会逐个介绍:PSC(预分频器) 、自动重装载寄存器、CNT(计数器)
2.2 PSC预分配器
这里大多数人都有个疑惑,为什么STM32通用定时器的时钟来源是72MHZ,是因为在APB1中已经倍频率了。
系统结构如下:
时钟树:
通用定时器结构
因为APB1总线的时钟频率是32MHZ(在系统结构图那里),但是给定时器的频率是乘以2倍的(在时钟树图哪里),所以预分频器是给72MHZ进行分频,
2.3自动重装载寄存器
自动重装载寄存器(Auto-Reload Register)是一种特殊的寄存器,通常在微处理器或计算机系统中用于存储某些需要周期性重置或更新的值。这种寄存器的主要用途包括:
-
定时器控制:在定时器或计数器中,自动重装载寄存器可以存储定时器的初始值,当计数器达到零时,自动重装载寄存器的值会被重新加载到计数器中,从而实现周期性的操作。
-
中断管理:在中断系统中,自动重装载寄存器可以用于设置中断服务程序的执行周期,确保中断服务能够定期执行。
-
性能监控:在性能监控中,自动重装载寄存器可以用于设置性能计数器的阈值,当计数器达到这个阈值时,自动重装载寄存器的值会被重新加载,从而实现性能计数器的周期性监控。
-
电源管理:在电源管理系统中,自动重装载寄存器可以用于设置电源状态的切换周期,以实现节能和性能的平衡。
-
DMA(直接内存访问)控制:在DMA传输中,自动重装载寄存器可以用于设置DMA传输的块大小,当DMA传输完成一个块后,自动重装载寄存器的值会被重新加载,以继续下一个块的传输。
自动重装载寄存器通过减少软件干预,提高了系统的效率和可靠性,使得某些周期性任务可以更加自动化和精确地执行。
2.4 CNT 计数器
CNT计数器,通常指的是在计算机硬件或软件中使用的计数器,它用于跟踪和控制事件或操作的次数。CNT计数器的用途非常广泛,包括但不限于以下几个方面:
-
定时和计数:在硬件定时器中,CNT计数器可以用于生成精确的时间间隔或周期性事件。
-
性能监控:在软件或硬件的性能分析中,CNT计数器可以用来统计特定操作或事件的发生次数,以评估系统性能。
-
数据采样:在数据采集系统中,CNT计数器可以用于控制采样频率,确保数据以均匀的时间间隔被采集。
-
事件调度:在操作系统或任务调度中,CNT计数器可以用来跟踪任务执行的次数或时间,以实现任务的周期性调度。
-
循环控制:在编程中,CNT计数器常用于控制循环结构的迭代次数,确保循环按照预定的次数执行。
-
资源管理:在资源有限的系统中,CNT计数器可以用于跟踪资源的使用情况,以避免资源耗尽。
-
状态机控制:在状态机设计中,CNT计数器可以用于跟踪状态转换的次数或时间,以控制状态机的流程。
-
通信协议:在通信系统中,CNT计数器可以用于实现协议规定的重传机制,确保数据的可靠传输。
-
硬件测试:在硬件测试中,CNT计数器可以用于模拟特定的操作次数,以测试硬件的耐久性和稳定性。
-
用户界面:在用户界面设计中,CNT计数器可以用于跟踪用户操作的次数,以实现动态的用户反馈或交互效果。
2.5计数模式
上升沿触发的:向上计数、和向下计数、中心对齐计数
三.通用定时器中断配置步骤
1. 使能定时器时钟。RCC_APB1PeriphClockCmd();// TIM4 是挂载在 APB1 之下
2.初始化定时器,配置ARR(自动重装载寄存器),PSC(预分频器)。
TIM_TimeBaseInit();
3.开启定时器中断,TIM4 的更新中断 void TIM_ITConfig();
配置NVIC,在主函数设置优先级。
NVIC_Init();
4.使能定时器。
TIM_Cmd();
5.编写中断服务函数。
TIMx_IRQHandler();//向上(下)溢出,事件发生中断
四.相关代码
4.1 定时器中断初始化
#include "time.h" #include "led.h" /******************************************************************************* * 函 数 名 : TIM4_Init * 函数功能 : TIM4初始化函数 * 输 入 : per:重装载值 psc:分频系数 * 输 出 : 无 *******************************************************************************/ void TIM4_Init(u16 per,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//使能TIM4时钟 TIM_TimeBaseInitStructure.TIM_Period=per; //自动装载值 TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式 TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure); TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //开启定时器中断 TIM_ClearITPendingBit(TIM4,TIM_IT_Update); NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;//定时器中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM4,ENABLE); //使能定时器 } /******************************************************************************* * 函 数 名 : TIM4_IRQHandler * 函数功能 : TIM4中断函数 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void TIM4_IRQHandler(void) { if(TIM_GetITStatus(TIM4,TIM_IT_Update)) { LED0=!LED0; } TIM_ClearITPendingBit(TIM4,TIM_IT_Update); }
4.2 主函数代码
在定时器初始化函数TIM4_Init(2000,36000-1)中,需要对预分频器,计数器,自动重装载值寄存器进行初始化赋值。
72MHZ=7200KHZ
7200KHZ/36000=2KHZ=0.5ms
0.5ms*2000=1s
在定时器中断函数中每1s进行LED的亮灭
int main() { delay_init(); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组 LED_Init(); TIM4_Init(2000,36000-1); //定时1000ms while(1) { } }
void TIM4_IRQHandler(void) { if(TIM_GetITStatus(TIM4,TIM_IT_Update)) { LED0=!LED0; } TIM_ClearITPendingBit(TIM4,TIM_IT_Update); }
-