STM32学习笔记之TIM定时中断

系列文章目录

第一章 STM32学习笔记之新建标准库

第二章 STM32学习笔记之GPIO及点灯实例

第N章 STM32学习笔记之OLED屏幕

第N章 STM32学习笔记之EXTI外部中断

第N章 STM32学习笔记之对射式红外传感器计次

第N章 STM32学习笔记之TIM定时中断


目录

系列文章目录

1. TIM定时中断

1.1. 简介

1.2. 定时器类型

1.2.1. 基本定时器

1.2.2. 通用定时器

1.2.3. 高级定时器

1.3. 定时中断基本结构

1.4. 时序图

1.4.1. 预分频器时序

1.4.2. 计数器时序

1.4.3. 计数器无预装时序

1.4.4. 计数器有预装时序

2. 定时器内部时钟配置

2.1. 模块化软件开发

2.2. 初始化函数

2.2.1. RCC时钟开启

2.2.2. 选择时钟源

2.2.3. 配置时基单元

2.2.4. 使能中断

2.2.5. 配置NVIC

2.2.6. 启动定时器

2.3. 中断函数编写

2.4. 声明初始化函数

2.5. main函数处理

3. 定时器外部时钟配置

3.1. 区别

3.1.1. 时钟源

3.1.2. 添加GPIO模块

3.1.3. 时基单元

3.1.4. 功能函数实现

总结


前言:

笔记:跟着B站教学视频做的学习笔记


1. TIM定时中断

1.1. 简介

TIM(Timer)定时器

  • 可以对输入的时钟进行计数,并在计数值达到设定值时触发中断

1.2. 定时器类型

根据定时器的类型,分为了高级定时器、通用定时器和基本定时器

  • 编号:因为同一个芯片有很多个定时器,所以TIM后面会跟一个数字,知道编号和定时器类型对应关系即可
  • 总线:通用定时器和基本定时器连接的是APB1总线,在开启RCC时钟时要注意下

STM32学习笔记之TIM定时中断_第1张图片

1.2.1. 基本定时器

基本定时器可以完成定时中断和主模式触发DAC的功能,但只能选择内部时钟,即系统频率72MHz

  • 预分频器:
  1. 对内部时钟进行预分频,例如写0,就是不分频,或者说是1分频,这时候输出频率=输入频率=72MHz,如果写1,那就是2分频,这时候输出频率=输入频率/2=36MHz...以此类推
  2. 预分频器的值和实际的分频系数相差了1,即实际分频系统=预分频系数的值+1
  3. 这预分频器是16位的,所以最大值可以写65535,即65536分频
  • 计数器:对预分频后的计数时钟进行计数,计数时钟每来一个上升沿,计数器的值就+1,这个计数器也是16位的,所以里面的值可以从0一直加到65535,如果再加的话,计数器就会回到0重新开始
  • 重载寄存器:也是16位的,它是计数的目标值,当计数值=重装值,就会产生一个更新中断和更新事件,CPU响应更新中断,就完成了定时中断的任务了,计数到了这个值后就重新开始
  • TRGO:定时器触发中断后,控制器就把更新事件映射到TRGO这个引脚上,用于触发DAC

STM32学习笔记之TIM定时中断_第2张图片

1.2.2. 通用定时器

通用定时器拥有基本定时器全部功能,还能外接时钟,即它的时钟源可以选择内部的72MHz时钟,还可以选择外部时钟,外部时钟常用的是TIMx_ETR

STM32学习笔记之TIM定时中断_第3张图片

  • TIMx_ETR引脚上的外部时钟,这个ETR(External)引脚的位置,可以参考引脚定义表,也就是可以在TIM2的ETR引脚,即PA0上接一个外部方波时钟,

STM32学习笔记之TIM定时中断_第4张图片

1.2.3. 高级定时器

STM32学习笔记之TIM定时中断_第5张图片

1.3. 定时中断基本结构

即选择时钟后,经过分频,计数器计数,到了重装载值时触发中断,中断信号经过中断输出控制到NVIC申请中断

STM32学习笔记之TIM定时中断_第6张图片

1.4. 时序图

1.4.1. 预分频器时序

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

  • CK_PSC是源时钟,开启预分频使能后,如果PSC是0,计数器的频率就是源时钟频率,1就是原始中频率的一半

STM32学习笔记之TIM定时中断_第7张图片

1.4.2. 计数器时序

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

  • UIF为1时就会去申请中断,中断响应后需要手动清零,不然就会一个申请中断

STM32学习笔记之TIM定时中断_第8张图片

1.4.3. 计数器无预装时序

无预装时,当重装载值发生改变,计数寄存器会直接更新,如果计数到了就直接变,如果计数已经超过了,它会默认先计数到FFFF再重新回到0重新开始

STM32学习笔记之TIM定时中断_第9张图片

1.4.4. 计数器有预装时序

有预装时,会多了一个影子寄存器,当自动加载寄存器发生改变时,它先等计数器计数到位了,影子寄存器才发生改变,计数器重新开始计数,而不是立即改变

STM32学习笔记之TIM定时中断_第10张图片

2. 定时器内部时钟配置

根据定时器基本结构图,得出配置定时器外部时钟主要有以下步骤:

STM32学习笔记之TIM定时中断_第11张图片


本次实操是基于新建好标准库工程之后

2.1. 模块化软件开发

新增Timer.c和Timer.h文件到System组里,具体操作见《STM32模块化软件开》链接

2.2. 初始化函数

2.2.1. RCC时钟开启

根据STM32的系统结构得出TIM定时器是挂在APB1总线上的,开启时钟后,定时器的基准时钟和整个外设的工作时钟都会同时开启,

STM32学习笔记之TIM定时中断_第12张图片

  1. 调用该函数开启RCC时钟
void Timer_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}

2.2.2. 选择时钟源

对于定时中断,选择内部的时钟源,

  • 在tim.h里找到"TIM_InternalClockConfig()"函数,即选择为内部时钟,时基单元是TIM2
void Timer_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    TIM_InternalClockConfig(TIM2);
}

2.2.3. 配置时基单元

  • 在tim.h里找到"TIM_TimeBaseInit()"来初始化时基单元,第一个参数是TIMx,第二个参数是一个结构体

STM32学习笔记之TIM定时中断_第13张图片

  • 第一个参数写TIM2,第二个参数点去定义里查找下

STM32学习笔记之TIM定时中断_第14张图片

  • 复制以下,根据它来定义一个结构体,把这个结构体的地址放在初始化函数里即可

STM32学习笔记之TIM定时中断_第15张图片

  • 把结构体成员都列出来进行初始化

STM32学习笔记之TIM定时中断_第16张图片

  • TIM_ClockDivision:去它的定义里查找后,分频选择DIV1,也就是不分频

STM32学习笔记之TIM定时中断_第17张图片

  • TIM_CounterMode:计数模式选择向上计数

STM32学习笔记之TIM定时中断_第18张图片

  • TIM_Period:周期(ARR自动重装值):

根据公式CK_PSC /(PSC+1) / (ARR + 1),为了配1秒的中断(1Hz),所以ARR选择为(10000-1),即72000000 /(PSC+1) / (10000 - 1 + 1)

  • TIM_Prescaler:PSC:

根据公式CK_PSC /(PSC+1) / (ARR + 1),为了配1秒的中断(1Hz),所以PSC选择为(7200-1),即72000000 /(7200 - 1+1) / (10000 - 1 + 1)= 1Hz

  • TIM_RepetitionCounter:高级定时器才有的,这里用不到,写0
void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1;
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct) ;
}

2.2.4. 使能中断

使能中断,就是允许中断更新中断输出到NVIC中

  • 在tim.h里找到"TIM_ITConfig()"来使能中断
  • 第一个参数选择"TIM2",第二个参数跳转到定义里去看,选择更新中断

STM32学习笔记之TIM定时中断_第19张图片

  • 第三个参数选择"ENABLE"
void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1;
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct) ;
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
}

2.2.5. 配置NVIC

在NVIC中打开定时器中断的通道,并分配一个优先级,详细步骤见《STM32学习笔记之EXTI应用实例》链接

因为NVIC是内核外设,它的库函数被ST发配到misc.h(杂项)文件里,在这里找它的库函数

  • NVIC_PriorityGroupConfig:指定下中断的分组,这里选择两位抢占两位响应
  • 定义一个NVIC结构体
  • NVIC_IRQChannel:因为库函数所以兼容所以的F1系列芯片,但是不同的芯片中断通道列表是不一样的,所以有很多条件编译,这里选择MD(中等密度)里的TIM2_IRQn

STM32学习笔记之TIM定时中断_第20张图片

  • NVIC_IRQChannelCmd:指定中断通道是使能还是失能,选择“ENABLE”
  • NVIC_IRQChannelPreemptionPriority:抢占优先级,这里只有一个中断源,比较随意,设置为1即可
  • NVIC_IRQChannelSubPriority:响应优先级,这里只有一个中断源,比较随意,设置为1即可
  • 调用NVIC初始化函数初始化结构体
void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1;
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct) ;
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStruct);
	
}

2.2.6. 启动定时器

  1. 在tim.h里找到"TIM_Cmd()"来启动定时器
  2. 第一个参数选择"TIM2",第二个参数给"ENABLE"
void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1;
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct) ;
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStruct);
	
	TIM_Cmd(TIM2,ENABLE);
}

2.3. 中断函数编写

在STM32中,中断通道的名字都是固定的,每个中断通道都对应一个中断函数,可以在启动文件里查看,里面以“ IRQHandler ”结尾的字符串就是中断函数的名字

STM32学习笔记之TIM定时中断_第21张图片

  • 找到"TIM2_IRQHandler",编写中断函数,记住要清除标志位
  • 先对TIM2的更新事件中断标志位进行判断,响应后清除标志位
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

2.4. 声明初始化函数

在.h文件里声明刚刚编写的传感器初始化函数,这样在别的文件里就能调用该函数了,中断函数不用声明

STM32学习笔记之TIM定时中断_第22张图片

2.5. main函数处理

声明红外传感器.h文件和调用初始化函数

STM32学习笔记之TIM定时中断_第23张图片

通过OLED屏显示时间:功能函数如下

STM32学习笔记之TIM定时中断_第24张图片

3. 定时器外部时钟配置

外部时钟采用红外传感器计数来模拟时钟,因为使用的是TIM2_CH1_ETR这个外部时钟,对应的引脚是PA0,所以要将红外传感器的AO口接到PA0引脚上

STM32学习笔记之TIM定时中断_第25张图片

3.1. 区别

3.1.1. 时钟源

把2.2.2里的时钟源"TIM_InternalClockConfig函数"换成TIM_ETRClockMode2Config函数"

  • 第一个参数给TIM2,第二个参数进入定义看一下

STM32学习笔记之TIM定时中断_第26张图片

  • 第三个参数去定义里看,根据需要来,这里选择不反向

STM32学习笔记之TIM定时中断_第27张图片

  • 第四个参数是外部触发滤波器:即以一个采样频率f采样N个点,如果N个点都一样,才会有效输出,这个值对应的f和N的关系如下,这里就选择不要滤波器了,即0x00

STM32学习笔记之TIM定时中断_第28张图片

3.1.2. 添加GPIO模块

开启时钟并且初始化GPIO

STM32学习笔记之TIM定时中断_第29张图片

3.1.3. 时基单元

将周期改成10,分频改成1,即触发一次加一次,加到10后触发中断

STM32学习笔记之TIM定时中断_第30张图片

3.1.4. 功能函数实现

计数函数:

uint16_t Timer_GetCounter(void)
{
	return TIM_GetCounter(TIM2);
}

主函数:

STM32学习笔记之TIM定时中断_第31张图片

END


总结

本章节记录了STM的定时器相关操作,无论是内部时钟或者外部时钟都有样例讲解

你可能感兴趣的:(STM32,stm32,学习,笔记)