STM32的定时中断,就是你定一个时间,STM32会每隔这个时间去打断主函数的运行,去干其他事情
1、定时器
需要实现定时中断,肯定是使用定时器啦
STM32F10x系列总共最多有8个定时器:
2、通用定时器:
平时使用的大多数为通用定时器:
STM32 的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成。STM32 的通用定时器可以被
用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频
器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。
STM3 的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5)定时器功能包括:
1)16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。
2)16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。
3)4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
A.输入捕获
B.输出比较
C.PWM 生成(边缘或中间对齐模式)
D.单脉冲模式输出
4)可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
5)如下事件发生时产生中断/DMA:
A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
C.输入捕获
D.输出比较
E.支持针对定位的增量(正交)编码器和霍尔传感器电路
F.触发输入作为外部时钟或者按周期的电流管理
3、计数器模式
通用定时器可以向上计数、向下计数、向上向下双向计数模式。
①向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
②向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
③中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
4、定时器中断实验相关寄存器
就讲几个主要的寄存器
1)控制寄存器 1(TIMx_CR1)
主要看位0吧,其他为比较少用到,位0是使能位
2)DMA/中断使能寄存器(TIMx_DIER)
主要关注第 0 位,该位是更新中断允许位,其他位,可以自己看一下
3)预分频寄存器(TIMx_PSC)
该寄存器用设置对时钟进行分频,然后提供给计数器,作为计数器的时钟
定时器的时钟来源有 4 个:
1)内部时钟(CK_INT)
2)外部时钟模式 1:外部输入脚(TIx)
3)外部时钟模式 2:外部触发输入(ETR)
4)内部触发输入(ITRx):使用 A 定时器作为 B 定时器的预分频器(A 为 B 提供时钟)。这些时钟,具体选择哪个可以通过TIMx_SMCR 寄存器的相关位来设置。这里的 CK_INT时钟是从 APB1 倍频的来的,除非 APB1 的时钟分频数设置为 1,否则通用定时器 TIMx 的时钟是 APB1 时钟的 2 倍,当 APB1 的时钟不分频的时候,通用定时器 TIMx 的时钟就等于 APB的时钟。这里还要注意的就是高级定时器的时钟不是来自 APB1,而是来自 APB2 的。
4) TIMx_CNT 寄存器,
该寄存器是定时器的计数器,该寄存器存储了当前定时器的计数值。
5)自动重装载寄存器(TIMx_ARR),
该寄存器在物理上实际对应着 2 个寄存器。一个是程序员可以直接操作的,另外一个是程序员看不到的,这个看不到的寄存器在《STM32中文参考手册》里面被叫做影子寄存器。事实上真正起作用的是影子寄存器。根据 TIMx_CR1寄存器中 APRE 位的设置:APRE=0 时,预装载寄存器的内容可以随时传送到影子寄存器,此时 2 者是连通的;而 APRE=1 时,在每一次更新事件(UEV)时,才把预装在寄存器的内容传送到影子寄存器。
6)状态寄存器(TIMx_SR)
该寄存器用来标记当前与定时器相关的各种事件/中断是否发生
5、初始化步骤
示例使用的主要是定时器3的,其他一些定时器也差不多
1 )TIM3 时钟使能。
这里我们通过 APB1ENR 的第 1 位来设置 TIM3 的时钟,因为 Stm32_Clock_Init 函数里面把APB1的分频设置为2了,所以我们的TIM3时钟就是APB1时钟的2倍,等于系统时钟(72M)。
RCC->APB1ENR|=1<<1; //TIM3 时钟使能
2 )设置 TIM3_ARR 和 和 TIM3_PSC 的值。
通过这两个寄存器,我们来设置自动重装的值,以及分频系数。这两个参数加上时钟频率
就决定了定时器的溢出时间。
TIM3->ARR=arr; //设定计数器自动重装值//刚好 1ms
TIM3->PSC=psc; //预分频器 7200,得到 10Khz 的计数时钟
3 )设置 TIM3_DIER 允许更新中断。
因为我们要使用 TIM3 的更新中断,所以设置 DIER 的 UIE 位为 1,使能更新中断。
TIM3->DIER|=1<<0; //允许更新中断
4 )允许 TIM3 工作。
光配置好定时器还不行,没有开启定时器,照样不能用。我们在配置完后要开启定时器,通过 TIM3_CR1 的 CEN 位来设置
TIM3->CR1|=0x01; //使能定时器 3
5 )TIM3 中断分组设置。
在定时器配置完了之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器,以使能TIM3 中断。
MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占 1,子优先级 3,组 2
6 )编写中断服务函数。
在最后,还是要编写定时器中断服务函数,通过该函数来处理定时器产生的相关中断。在中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执行相关的操作,我们这里使用的是更新(溢出)中断,所以在状态寄存器 SR 的最低位。在处理完中断之后应该向 TIM3_SR 的最低位写 0,来清除该中断标志
void TIM3_IRQHandler(void)
{
if(TIM3->SR&0X0001) //溢出中断
{
//这里写想要中断实现的功能,例如:LED亮 LED = 1;
}
TIM3->SR&=~(1<<0); //清除中断标志位
}
附件为例程,包括寄存器版本和库函数版本