stm32的TIM简介(一)——定时器中断

该文章是记录我学习stm32定时器的过程,若有不正确的地方请多指正,万分感谢!!!!

TIM简单介绍

TIM(Timer)定时器
1.定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断.
2.定时器中含有由16位计数器(CNT)、预分频器(PSC)、自动重装寄存器(ARR)时基单元,在72MHz计数时钟下可以实现最大59.65s的定时.
3.定时器不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能.
4.定时器的种类有高级定时器、通用定时器、基本定时器三种类型.
类型编号总线功能
高级定时器TIM1,TIM8APB2

拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能

通用定时器

TIM2,TIM3,

TIM4,TIM5

APB1

拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能

基本定时器TIM6,TIM7APB1

拥有定时中断、主模式触发DAC的功能

基本定时器

主要功能

● 16位自动重装载累加计数器
● 16位可编程(可实时修改)预分频器,用于对输入的时钟按系数为1~65536之间的任意数值
分频
● 触发DAC的同步电路
● 在更新事件(计数器溢出)时产生中断/DMA请求

框图分析

基本定时器的时钟源只能选择内部时钟作为时钟源,内部时钟源经过控制器到达预分频器(PSC)经过分频后传递给计数器(CNT),由计数器对经过分频后的内部时钟进行计数,并与自动重装寄存器(ARR)中的数值进行比较,当数值与自动重装寄存器中的数值相等的时候就会将计数器清零并产生中断信号和更新事件,中断事件经过主模式触发控制器映射到TRGO的位置并由TRGO接到DAC转换引脚上。主模式触发的更新事件不需要软件的参与,由硬件自动完成。

通用定时器

主要功能

● 16位向上、向下、向上/向下自动装载计数器
● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意
数值
● 4个独立通道:
─ 输入捕获
─ 输出比较
─ PWM生成(边缘或中间对齐模式)
─ 单脉冲模式输出
● 使用外部信号控制定时器和定时器互连的同步电路
● 如下事件发生时产生中断/DMA:
─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
─ 输入捕获
─ 输出比较
● 支持针对定位的增量(正交)编码器和霍尔传感器电路
● 触发输入作为外部时钟或者按周期的电流管理

框图分析

首先时钟源的来源比基本定时器更加丰富,有内部时钟源,TIM_ETR引脚输入的信号作为时钟源,ITR0~ITR3来自其他时钟的定时器信号作为时钟源(定时器的主模式输出TRGO可以将定时器的信号传输给另外一个定时器)见下表,此外还可以是来自引脚TIMx_CH_1(TI1F_ED或TI1FP1传输到控制器)和TIMx_CH_2(TI2FP2传输到控制器).

其次,时基单元部分与基本定时器相比较有(向下计数,向上计数,中央对齐计数模式).

最后,有关输入捕获和输出捕获寄存器是和PWM有关,可以参照后续文章。

高级定时器

主要功能

● 16位向上、向下、向上/下自动装载计数器
● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意
数值
● 多达4个独立通道:
─ 输入捕获
─ 输出比较
─ PWM生成(边缘或中间对齐模式)
─ 单脉冲模式输出
● 死区时间可编程的互补输出
● 使用外部信号控制定时器和定时器互联的同步电路
● 允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器
● 刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态
● 如下事件发生时产生中断/DMA:
─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
─ 输入捕获
─ 输出比较
─ 刹车信号输入
● 支持针对定位的增量(正交)编码器和霍尔传感器电路
● 触发输入作为外部时钟或者按周期的电流管理
框图分析
首先,时钟源部分和通用寄存器基本一致,此文不在赘述。
其次,时基单元多了一个重复次数寄存器,可以实现多个计数周期后才发生中断。
最后,图中的DTG叫死区生成电路用于解决在开关切换的瞬间由于器件的不理想造成的直通现象,后面的输出控制器变成了三个一对的互补输出,可以生成一对互补的PWM波用于驱动三相无刷电机。
为了给电机驱动提供安全保障,当内部时钟失效或者外部产生刹车信号时会切断对电机的输出,防止意外发生。

使用定时器计数的初始化一般步骤

1.定时器时钟使能

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

 2.选择一个定时器的时钟源是内部时钟(以TIM2选择内部时钟源为例)

TIM_InternalClockConfig(TIM2);

3.时基单元的初始化以及中断的使能

计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)

计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / (PSC + 1) / (ARR + 1)

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=10000-1;
TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);

注意:由于我们的预分频器的值要起作用必须是在更新事件发生以后, TIM_TimeBaseInit函数中使用软件中断来产生了一个更新事件然后进入中断函数,使用我们要走初始化函数后面加一个清除中断标志位的函数防止设置初始化造成的中断函数调用。

4.NVIC优先级分组以及初始化

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStructure);

5.启动定时器

TIM_Cmd(TIM2,ENABLE);

 最后,每次执行完中断函数以后要清除中断标志位(注意中断函数名在启动文件中的中断向量表里面)。

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
	{
		
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}

 完整初始化代码

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=10000-1;
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);

  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果您的STM32单片机屏幕一直闪烁,可能是因为您的程序中使用了循环延时的方式,导致CPU一直忙碌而无法及时刷新屏幕。为了解决这个问题,可以使用STM32定时器中断来实现LED的闪烁,从而释放CPU资源,让它能够及时地刷新屏幕。 以下是使用TIM中断方式实现LED闪烁的示例代码: ```c #include "stm32f10x.h" void TIM2_IRQHandler(void) // 定时器2中断服务函数 { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) // 检查是否发生了更新事件 { static uint8_t led_state = 0; if (led_state == 0) { GPIO_SetBits(GPIOC, GPIO_Pin_13); // PC13输出高电平 led_state = 1; } else { GPIO_ResetBits(GPIOC, GPIO_Pin_13); // PC13输出低电平 led_state = 0; } TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除中断标志位 } } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // 使能GPIOC时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 使能TIM2时钟 // 配置GPIOC.13为推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); // 配置TIM2 TIM_TimeBaseStructure.TIM_Period = 999; // 自动重载值 TIM_TimeBaseStructure.TIM_Prescaler = 7199; // 预分频器 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 使能更新中断 TIM_Cmd(TIM2, ENABLE); // 启动定时器 // 配置NVIC NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); while (1) { // 空闲循环 } } ``` 在上面的代码中,我们使用了定时器TIM2,并把它配置为1ms的定时器。在定时器中断服务函数中,我们通过改变LED的状态来实现LED的闪烁。由于使用了中断方式,CPU不会一直忙碌,从而可以释放CPU资源,让它能够及时地刷新屏幕。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值