2.定时器中断

xiaoxiao2021-02-28  136

STM32F429总共有14个:

高级定时器:TIM1 和TIM8 通用定时器:TIM2-TIM5,TIM9-TIM14 基本定时器:TIM6 和 TIM7

挂载的总线:高级定时器及TIM9-TIM11的时钟来自APB2,其他来自APB1;

APB2:TIM1 和 TIM8 、TIM9-TIM11

APB1:TIM2-TIM5、TIM6 和 TIM7、TIM12-TIM14

定时器简介

STM32F429 的通用定时器包含一个 16 位或 32 位自动重载计数器( CNT),该计数器由可编程预分频器( PSC) 驱动。

STM32F429 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。

使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。

STM32F429 的每个通用定时器都是完全独立的,没有互相共享的任何资源。 STM32 的通用 TIMx (TIM2~TIM5 和 TIM9~TIM14)定时器功能包括:


  16 位/32 位(仅 TIM2 和 TIM5)向上、向下、向上/向下自动装载计数器(TIMx_CNT),注意: TIM9~TIM14 只支持向上(递增)计数方式。

  16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。

  4 个独立通道(TIMx_CH14TIM9TIM14 最多 2 个通道),这些通道可以用来作为:

A.输入捕获 B.输出比较 C. PWM 生成(边缘或中间对齐模式) ,注意: TIM9~TIM14 不支持中间对齐模式 D.单脉冲模式输出

  可使用外部信号( TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外 一个定时器)的同步电路。

  如下事件发生时产生中断/DMA( TIM9~TIM14 不支持 DMA):

A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) C.输入捕获 D.输出比较 E.支持针对定位的增量(正交)编码器和霍尔传感器电路( TIM9~TIM14 不支持) F.触发输入作为外部时钟或者按周期的电流管理( TIM9~TIM14 不支持)


常用的寄存器

TIMx_CR1:(Control Register 1)控制寄存器1

TIM1 和 TIM8: TIM2-TIM5: TIM9-TIM12 TIM6 和 TIM7: qq空间图片 不会做点进去就是图片的链接,好尴尬。

TIMx_CR2:(Control Register 2)控制寄存器2

分类同TIMx_CR1

TIMx_DIER:(DMA Interrupt Enable Register)DMA/中断使能寄存器

TIMx_PSC:(Prescaler)预分频寄存器

TIMx_ARR:(auto-reload register)重装载寄存器

该寄存器在物理上实际对应着 2 个寄存器,一个是程序员可以直接操作的,另外一个是程序员看不到的,这个看不到的寄存器在《 STM32F4xx 中文参考手册》里面被叫做影子寄存器。事实上真正起作用的是影子寄存器。 根 据 TIMx_CR1 寄存器中 APRE 位的设置:APRE=0 时,预装载寄存器的内容可以随时传送到影子寄存器,此时 2 者是连通的;而 PRE=1 时,在每一次更新事件( UEV)时,才把预装载寄存器( ARR) 的内容传送到影子寄存器。

TIMx_SR:(status register)状态寄存器

步骤

1) TIM3 时钟使能。

这里我们通过 APB1ENR 的第 1 位来设置 TIM3 的时钟,因为 Stm32_Clock_Init 函数里面 把 APB1的分频设置为 4了,所以我们的 TIM3时钟就是 APB1时钟的 2倍,等于系统时钟 ( 90M)。

2) 设置 TIM3_ARR 和 TIM3_PSC 的值。

通过这两个寄存器,我们来设置自动重装的值,以及分频系数。这两个参数加上时钟频率就决定了定时器的溢出时间。

3) 设置 TIM3_DIER 允许更新中断。

因为我们要使用 TIM3 的更新中断,所以设置 DIER 的 UIE 位为 1,使能更新中断。

4) 允许 TIM3 工作。

光配置好定时器还不行,没有开启定时器,照样不能用。我们在配置完后要开启定时器,通过 TIM3_CR1 的 CEN 位来设置。

5) TIM3 中断分组设置。

在定时器配置完了之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器,以使能TIM3 中断。

6) 编写中断服务函数。

在最后,还是要编写定时器中断服务函数,通过该函数来处理定时器产生的相关中断。在中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执行相关的操作,我们这里使用的是更新(溢出)中断,所以在状态寄存器 SR 的最低位。在处理完中断之后应该向 TIM3_SR 的最低位写 0,来清除该中断标志

示例代码

寄存器 /************************/ //C文件内容 #include "tim3.h" void TIM3_IRQHandler(void) { if (TIM3->SR&0x0001) //溢出中断 SR状态寄存器 { LED0=!LED0; } TIM3->SR&=~(1<<0); //状态寄存器清零 } void TIM4_IRQHandler(void) { if (TIM4->SR&0x0001) //溢出中断 SR状态寄存器 { LED1=!LED1; } TIM4->SR&=~(1<<0); //状态寄存器清零 } //通用定时器 3 中断初始化 //这里时钟选择为 APB1 的 2 倍,而 APB1 为 45M //arr:自动重装值。 //psc:时钟预分频数 //定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us. //Ft=定时器工作频率,单位:Mhz //这里使用的是定时器 3! void TIM3_Int_Init(u16 arr,u16 psc) { //0 1 2 3 ... RCC->APB1ENR|=1<<1; //TIM2 TIM3 TIM4 TIM5 ... TIM3->ARR=arr; //自动重装载寄存器 TIM3->PSC=psc; //时钟预分频寄存器 TIM3->DIER|=1<<0; //允许更新中断 TIM3->CR1|=0x01; //控制寄存器1 使能定时器3 MY_NVIC_Init(1,3,TIM3_IRQn,2); //抢占1 ,子优先级 3 } void TIM4_Int_Init(u16 arr,u16 psc) { //0 1 2 3 ... RCC->APB1ENR|=1<<2; //TIM2 TIM3 TIM4 TIM5 ... TIM4->ARR=arr; //自动重装载寄存器 TIM4->PSC=psc; //时钟预分频寄存器 TIM4->DIER|=1<<0; //允许更新中断 TIM4->CR1|=0x01; //控制寄存器1 使能定时器3 MY_NVIC_Init(2,3,TIM4_IRQn,2); //抢占1 ,子优先级 3 } /************************/ //头文件内容 #ifndef __TIM3_H_ #define __TIM3_H #include "sys.h" #include "led.h" void TIM3_Int_Init(u16 arr,u16 psc); void TIM4_Int_Init(u16 arr,u16 psc); #endif 库函数 /*********************/ //c文件 #include "timer.h" TIM_HandleTypeDef TIM2_Handler; TIM_HandleTypeDef TIM3_Handler; //arr:自动重装载 //psc:时钟分频数 void TIM2_Init(u16 arr,u16 psc) { TIM2_Handler.Instance=TIM2; TIM2_Handler.Init.Prescaler=psc; TIM2_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; TIM2_Handler.Init.Period=arr; TIM2_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&TIM2_Handler); //使能 HAL_TIM_Base_Start_IT(&TIM2_Handler); } void TIM3_Init(u16 arr,u16 psc) { TIM3_Handler.Instance=TIM3; TIM3_Handler.Init.Prescaler=psc; TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; TIM3_Handler.Init.Period=arr; TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&TIM3_Handler); //使能 HAL_TIM_Base_Start_IT(&TIM3_Handler); } void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim) { if (htim==&TIM2_Handler) { __HAL_RCC_TIM2_CLK_ENABLE(); //使能 TIM3 时钟 HAL_NVIC_SetPriority(TIM2_IRQn,0,3); //设置中断优先级,抢占 1,子优先级 3 HAL_NVIC_EnableIRQ(TIM2_IRQn); //开启 ITM3 中断 } if (htim==&TIM3_Handler) { __HAL_RCC_TIM3_CLK_ENABLE(); //使能 TIM3 时钟 HAL_NVIC_SetPriority(TIM3_IRQn,1,3); //设置中断优先级,抢占 1,子优先级 3 HAL_NVIC_EnableIRQ(TIM3_IRQn); //开启 ITM3 中断 } } // void TIM2_IRQHandler(void) { HAL_TIM_IRQHandler(&TIM2_Handler); } // void TIM3_IRQHandler(void) { HAL_TIM_IRQHandler(&TIM3_Handler); } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim==&TIM2_Handler) { LED1=!LED1; } if (htim==&TIM3_Handler) { LED0=!LED0; } } /************************************/ //头文件 #ifndef __TIMER_H__ #define __TIMER_H__ #include "sys.h" #include "led.h" void TIM2_Init(u16 arr,u16 psc); void TIM3_Init(u16 arr,u16 psc); #endif
转载请注明原文地址: https://www.6miu.com/read-19104.html

最新回复(0)