STM32 HAL库-定时器中断

news2025/2/26 14:48:38

STM32 HAL库-定时器中断

  • 一、STM32F407定时器介绍
    • 定时器计算公式
  • 二、CubeMX配置定时器
  • 三、基本定时器中断配置流程
    • 1)开启定时器时钟
    • 2)初始化定时器参数,设置自动重装值,分频系数,计数方式等
    • 3)使能定时器更新中断,开启定时器计数,配置定时器中断优先级
    • 4)编写中断服务函数(主要是重写回调函数,覆盖原来的)
    • 注意:
  • 四、参考资料
    • 1 HAL库的中断处理
      • 1.1 HAL 库的中断封装
      • 1.2 外部中断处理流程
  • 五、示例


一、STM32F407定时器介绍

STM32F407 有众多的定时器,其中包括 2 个基本定时器(TIM6 和 TIM7)、10 个通用定时
器(TIM2 ~ TIM5、TIM9 ~TIM14)、2 个高级控制定时器(TIM1 和 TIM8),这些定时器彼此完
全独立,不共享任何资源。
在这里插入图片描述
在这里插入图片描述

选择定时器,配置时钟源,设置预分频系数,计数模式,设置自动重装载值

定时器计算公式

在这里插入图片描述

不过一般情况下定时时间都是毫秒级别。
时钟频率是84Mhz这里进行84分频,就是1Mhz,也就是每秒10的6次方个脉冲。而重装载值是1000,每秒可以触发1000个中断,也就是定时时间是1ms。

PSC = 84 -1 = 83;
ARR = 1000 -1 = 999;

二、CubeMX配置定时器

详见正点原子视频教程

三、基本定时器中断配置流程

1)开启定时器时钟

HAL 中定时器使能是通过宏定义标识符来实现对相关寄存器操作的,方法如下:
__HAL_RCC_TIMx_CLK_ENABLE(); /* x=1~14 */

2)初始化定时器参数,设置自动重装值,分频系数,计数方式等

定时器的初始化参数是通过定时器初始化函数 HAL_TIM_Base_Init 实现的。
注意:该函数会调用:HAL_TIM_Base_MspInit 函数,我们可以通过后者存放定时器时钟
和中断等初始化的代码。

3)使能定时器更新中断,开启定时器计数,配置定时器中断优先级

通过 HAL_TIM_Base_Start_IT 函数使能定时器更新中断和开启定时器计数。

通过 HAL_NVIC_EnableIRQ 函数使能定时器中断,通过 HAL_NVIC_SetPriority 函数设置
中断优先级。

4)编写中断服务函数(主要是重写回调函数,覆盖原来的)

定时器中断服务函数为:TIMx_IRQHandler 等,当发生中断的时候,程序就会执行中断服
务函数。
HAL 库提供了一个定时器中断公共处理函数 HAL_TIM_IRQHandler,该函数又会调用HAL_TIM_PeriodElapsedCallback 等一些回调函数,需要用户根据中断类型选择重定义对应的中
断回调函数来处理中断程序。

注意:

1、中断处理最好写在回调函数里面。

往往不止一种情况触发同一个中断,各个情况都有对应回调函数,库函数会去检查相关标志位并调用对应的回调函数,这样就不需要我们自己去检查中断标志来确定中断来源以及清除标志位,比如上面的中断程序可以写在void HAL_TIM_PeriodElapsedCallback里面。
库的回调函数都有__weak修饰,我们可以自己定义回调函数。

2、时钟与它的中断使能可以用函数HAL_TIM_Base_Start_IT()。

四、参考资料

这篇文章介绍的非常不错: 【STM32】基于HAL库的中断详细学习

1 HAL库的中断处理

1.1 HAL 库的中断封装

在上一节中我们介绍了中断的处理过程:当中断发生时,处理器暂停当前程序,根据中断类型号在中断向量表中查找中断服务程序的入口地址,进而执行中断服务程序。执行完成后,返回断点处执行原程序。虽然上述的操作大部分是由硬件完成,但是在针对具体外设的中断处理中,还需要用户完成以下的编程步骤:

① 设置中断触发条件。如外部中断的边沿触发,定时器更新中断的时间间隔。

② 设置中断优先等级。系统中存在多个中断时,需要根据任务的紧迫程度,设置不同的中断优先级。

③ 使能外设的某个中断。微控制器片内集成的外设一般都有多个中断源,这些中断源的使能由外设的寄存器控制。例如,串口通信的发送数据寄存器空中断TXE和发送完成中断TC的使能,就是由串口控制寄存器CR1中的TXEIE位和TCIE位控制。

④ 判断中断源。对于有多个中断源的外设,进入中断服务程序后,需要根据中断标志来判断具体发生了哪一种中断。

⑤ 清除中断标志。发生中断后,相应的中断标志位置位,以便MCU查询。这些中断标志要注意及时清除,避免重复进入中断。

⑥ 编写程序。用户根据实际项目的需求来编写中断发生时应该执行的操作。

在上述的六个中断编程步骤中,借助CubeMX软件可以通过图形化的设置方式完成前三个步骤,而后三个步骤可以借助HAL库提供的接口函数进一步简化。

在HAL库中,将中断的处理过程进行了重新的封装,主要有以下几点:

1.统一定义了各个外设的中断通用处理所两数HAL_PPP_IRQHandler()(PPP代表外设名称)。

2.在中断通用处理函数HAL_PPP_IRQHandler()中完成中断标志的判断和清除。

3.将中断中需要执行的操作以回调函数的形式提供给用户,回调函数由中断通用处理函数调用。

回调函数是一个通过函数指针调用的函数。如果把一个函数的指针(即函数的地址)作为另一个函数的参数时,当这个指针被用来调用其所指向的函数时,这个被调用的函数就称为回调函数。

我们通过一个例子来进一步说明回调函数的概念。假设有三个函数:Func1、Func2和 Func3。函数Func1调用函数Func2,同时将函数Func3作为形参传递给Func2,此时,Fun1 可以看作是应用层函数,Func2可以看作是中间层函数,Func3则称为回调函数。

在实际的程序设计中,回调函数一般位于用户程序中,和主程序同属于应用层,而回调函数的调用方通常是第三方提供的库函数。回调函数的执行,相当于从库函数调用应用层的函数,因此称为回调。

回调函数一般用于执行具体的操作,需要用户根据实际项目的需求来编写。无法封装到第三方的库函数里面。因此,库函数提供一个函数指针作为入口参数,主程序将回调函数像参数一样传入库函数。这样一来,只要改变传进库函数的参数,就可以实现不同的功能,并且不需要修改库函数的代码,确保了应用层和库函数的解耦。

以中断服务程序的处理为例:判断中断源,清除中断标志这些流程对任何一个中断都相同的。但是,某一个中断发生之后执行什么具体的操作,却各不相同。比如,1s的定时中断到了,是开启一个指示灯,还是使蜂鸣器鸣响,都由用户根据实际项目的需求来编写。因此,HAL库将中断中需要执行的操作以回调函数的形式提供给用户,简化了中断服务程序的设计。

HAL库在设计回调函数的时候,采用了更为巧妙的方法:在需要使用回调函数的地方,预定义了一个默认的回调函数,该函数的属性设计为“weak”,函数内部不执行任何操作。weak属性的函数表示:如果该函数没有在其他文件中定义,则使用该函数;如果用户在其他地方定义了该函数,则使用用户定义的函数。当用户需要使用回调函数时,可以在应用程序中重新定义一个同名的回调函数,在函数中实现具体的操作。这样,编译器在编译的时候,就会选择用户重新定义的回调函数。

在利用CubeMX软件生成的MDK工程中,与中断处理相关的文件一共有两个:

1.启动文件:startup_stm32fxxx.s (xxx表示芯片型号)

在启动文件中,创建了中断向量表,并预先为每一个中断编写了中断服务程序。这些断服务程序的内部都是死循环,不执行任何具体操作,其目的只是为了初始化中断向量表。中断服务程序的属性设置为“weak”,用户可以在用户文件中重新定义一个同名函数作为实际执行的中断服务程序。

2.中断服务程序文件:stm32fxxx_it.c (xxx表示芯片型号)

中断服务程序文件用于存放各个中断实际执行的中断服务程序,这些中断服务程序可以分成两个部分:

第一部分是Cortex-M内核处理器的异常处理程序,包括不可屏蔽中断(NMI)类型错误(HardFault)以及系统节拍定时器中断(Systick)等。

第二部分是微控制器片内外设的中断服务程序。在使用CubeMX软件进行初始化配置时,如果使能了某一个外设的中断功能,那么在生成代码时,对应外设的中断服务程序将会自动添加到stm32fxxx_it.c文件中,在中断服务程序中再调用该外设所对应的中断通用处理函数HAL_PPP_IRQHandler()。

注意:中断服务程序的函数名在中断向量表中已经由ST公司预先规定,用户必须按照这个规定的函数名来编写中断服务程序。发生中断时,中断服务程序才能被正确调用。

1.2 外部中断处理流程

下面我们以GPIO引脚触发的外部中断为例,来详细分析一下HAL库的中断处理流程。假设芯片型号为STM32F411,设置引脚PC0和PC13为外部中断功能(即PC0和PC13与对应的外部中断线EXTI0和EXTI13相连),并使能对应的外部中断。当引脚PC0或PC13出现电平变化时,将触发外部中断,具体的执行过程如下:

1. 查找中断向量表,跳转到中断服务程序

微控制器暂停当前程序的执行,根据中断向量表跳转到EXTIO_IRQHandler()(外部中断线0的中断服务程序)或者EXTI15 10_IRQHandler()(外部中断线10~15的中断服务程序)执行,具体执行哪一个中断服务程序由中断发生的先后顺序及中断的优先级决定。启动文件startup_stm32f411xe.s的中断向量表中预先定义了外部中断线所对应的中断服务程序,如表所示。这些定义的函数都加入了weak属性。
在这里插入图片描述
2.执行中断服务程序

启动文件startup_stm32f411xe.s中定义的中断服务程序默认为死循环,不执行任何具体操作。由于这些函数定义为weak属性,因此用户可以在stm32f4xx_it.c文件中重新定义与该函数同名的中断服务程序。当中断发发生时,将执行在stm32f4xx_it.c文件中重新定义的中断服务程序。

我们在CubeMX软件中使能外部中断线发的中断功能后,将在stm32f4xx_it.c文件中自动添加相关的外部中断服务程序,具体代码支如程序清单所示。

/*
* @brief This function handles EXTI line0 interrupt.
*/
void EXTI0_IRQHandler(void) // 外部中断线日的中断服务程序 
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); // 调用外部中断通用处理函数
}
/*
*@brief This function handles EXTI line[15:10] interrupts.
*/
void EXTI15_10_IRQHandler(void) // 外部中断线 10~15 的中断服务程序 
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13); // 调用外部中断通用处理函数
}

3. 执行外部中断通用处理函数

进入外部中断服务程序EXTIO_IRQHa andler()或EXTI15_10_IRQHandler()后,都将调用HAL库提供的外部中断通用处理函数数HAL_GPIO_EXTI_IRQHandler()。该函数作为HAL库提供的外部中断接口函数,在stm32f4xx_hal_gpio.c文件中定义。

由于所有通过GPIO引脚触发的外部中断都会调用外部中断通用处理函数,因此在函数内部需要判断本次中断具体是由哪一个GPIO引脚触发的,并清除对应的中断标志最后再调用外部中断回调函数HAL_GPIO_ EXTI_Callback()完成具体的中断处理任务。

外部中断通用处理函数的代码如程序清单所示。

/*
* @brief This function handle s EXTI interrupt request.
* @param GPIO_Pin Specifes the pins connected EXTI line
* @retval None
*/
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin)!= RESET)// 检测对应的中断标志是否置位
{
_HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); // 清除对应的中断标志 
HAL_GPIO_EXTI_Callback(GPIO_Pin); // 调用回调函数执行具体任务 
}
}

4.默认的外部中断回调函数

外部中断回调函数HAL_GPIO_EXTI Callback()用于完成具体的中断处理任务。该函数也是HAL库提供的外部中断接口函数数,在stm32f4xx_hal_gpio.c文件中定义。默认的外部中断回调函数添加了weak属性,函数内部没有任何可执行代码,仅仅有一个避免编译器警告的语句:UNUSED(GPIO_Pin)。

默认的外部中断回调函数的代码如程序清单所示。

/*
* @brief EXTI line detection callbacks.
* @param GPIO_Pin Specifes the pins connected EXTI line
* @retval None
*/
_weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(GPIO_Pin);
/*NOTE:This function Should not be modifed, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file*/
}

5.执行用户编写的外部中断回调函数

用户需要在main.c文件中重新编写外部中断回调函数HAL_GPIO_EXTI_Callback(),来完成具体的中断处理任务。中断回调函数一般添加在/* USER CODE BEGIN4*/和/* USER CODE END4*/之间。由于所有通过于GPIO引脚触发的外部中断都会调用该回调函数,因此在回调函数内部,需要根据入口参参数GPIO_Pin判断是哪一个GPIO引脚触发的本次外部中断,然后再执行不同的中断处理任务。如果用户设置了多个GPIO引脚产生外部中断,则可以使用switch-case多分支语句进行判断。

外部中断回调函数的示例代码如程序法清单所示。

/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
case GPIO_PIN_0: // 引脚 PCO 对应的中断处理任务 
/* GPIO_PIN_0 EXTI handling */
break;
case GPIO_PIN_13:
/*GPIO_PIN_13 EXTI handling */ // 引脚 PC13 对应的中断处理任务 
break;
case GPIO_PIN_X; // 引脚x对应的中断处理任务 
/* GPIO_PIN_X EXTI handling */ 
break;
……
default:
break;
}
}
/* USER CODE END 4 */
 

根据上述的分析,我们可以用下图来更加清晰地展示HAL库的外部中断处理流程。

从下图可以看到,发生外部中断时处理器在中断向量表找到所对应的中断服务程序,在中断服务程序内部调用外部中断通通用处理函数HAL_GPIO_EXTI_IRQHandler( ),最后再调用外部中断回调函数HAL_GP O_EXTICallback()来完成具体的中断处理任务。
在这里插入图片描述
在HAL库的外部中断处理流程中,外部中断回调函数HAL_GPIO_EXTI_Callback()是放在main.c文件中,作为应用程序的一部分,而它的调用却是由HAL库提供的接口函数触发的,即库函数反过来调用应用层的函类数,因此称为回调函数。

借助CubeMX软件和HAL库,用户的中中断编程步骤大大简化,只需要利用CubeMX软件进行中断的相关配置,包括中断触发条件、中断优先级以及中断使能等,最后在中断回调函数中编写具体的中断处理任务即可。

五、示例

借助CubeMX软件和HAL库,定时器中断调用HAL_TIM_IRQHandler函数,发现它内部是这么实现中断处理的:

由于我们只使用了最基本的定时器更新中断,所以在这个函数里,只会进入TIM Update event这个处理内部,清除中断标志后,还会调用HAL_TIM_PeriodElapsedCallback这个函数。
在这里插入图片描述
在这里插入图片描述
而HAL_TIM_PeriodElapsedCallback这个函数是这么实现的:
在这里插入图片描述
它有一个__weak关键词修饰,函数内部是空的,没做任何处理。

这种有__weak修饰的函数,是可以被用户重写的。HAL_TIM_PeriodElapsedCallback这类函数一般称为回调函数,是留给用户的接口函数,用于给用户重写实现,以加入自己的功能。

//定时器开启的时候记得设置CUBE里面的NVIC
uint16_t t3_count;
uint16_t t3_count2;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *hitm)
{
	if(hitm ->Instance ==TIM1)
	{
	}
	if(hitm ->Instance ==TIM3)//定时器3,定时时间10ms
	{
		t3_count++;
		if(t3_count>=100)//1s
		{
			t3_count=0;
			Led0_Toggle;
			t3_count2++;
			if(t3_count2>=10)//10s
			{
				Led1_Toggle;
				t3_count2=0;
			}
		}
	}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/347511.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu 系统 OpenCV 4 无法打开视频文件解决方案

目录 一、我的运行环境 二、问题描述 三、问题定位及分析 四、解决方案 一、我的运行环境 设备NVIDIA Jetson Nano处理器ARMv8 Processor rev 1 (v8l) 4 GPUNVIDIA Tegra X1 (nvgpu)/integrated操作系统ubuntu 18.04 LTSOpenCV版本4.6.0语言C 二、问题描述 之前一直用的O…

8 冒泡排序

文章目录1 基本介绍1 代码实现1.1 java1.1 scala1 基本介绍 冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使…

存储管理(6)

存储管理 1 程序的装入与链接 编译:源代码——目标代码 链接:目标代码所需库函数装入模块 装入:将装入模块装入内存,该过程也叫做地址重定位,也称地址映射 地址空间: 源程序经编译后得到的目标程序&…

Leetcode 1223. 掷骰子模拟【动态规划】

有一个骰子模拟器会每次投掷的时候生成一个 1 到 6 的随机数。 不过我们在使用它时有个约束,就是使得投掷骰子时,连续 掷出数字 i 的次数不能超过 rollMax[i](i 从 1 开始编号)。 现在,给你一个整数数组 rollMax 和一…

WebDAV之葫芦儿·派盘+NMM

NMM 支持WebDAV方式连接葫芦儿派盘。 推荐一款文件管理器,可以对手机中的文件进行多方面的管理,支持语法高亮和ftp等远程的文件的管理。支持从WebDav服务器连接葫芦儿派盘服务下载文件和上传文件。 NMM文本编辑器是一款文件管理器,在功能上面更加的适合于一些编程人员进行使…

2023年应该了解的黑客知识

网络犯罪的艺术处于不断变化和演变的状态。与这些趋势保持同步是网络安全人员工作的重要组成部分。 今天的现代网络安全必须确保他们始终为下一个大趋势做好准备并保持领先于对手。 当我们开始迈向 2023 年时,安全格局与一年前相比已经发生了变化,更不…

Spark on hive Hive on spark

文章目录Spark on hive & Hive on sparkHive 架构与基本原理Spark on hiveHive on sparkSpark on hive & Hive on spark Hive 架构与基本原理 Hive 的核心部件主要是 User Interface(1)和 Driver(3)。而不论是元数据库&a…

webpack(高级)--性能优化-代码分离

webpack webpack性能优化 优化一:打包后的结果 上线时的性能优化 (比如分包处理 减少包体积 CDN服务器) 优化二:优化打包速度 开发或者构建优化打包速度 (比如exclude cache-loader等) 大多数情况下我们侧…

css 安全区域 safe-area-inset-

前言 安全区域与边界是iOS11 新增特性。 安全区域 安全区域的内容不受圆角(corners)、齐刘海(sensor housing)、小黑条(Home Indicator)影响。Webkit 为此增加了相应的CSS 函数,用于获取安全…

B树系列与MySQL数据库

前篇提到B树及其实现:一文看懂---B树及其简单实现_b树实现_且随疾风前行->的博客-CSDN博客 本篇继续谈B树系列的B树,B*树和它们与MySQL数据库的关系。 目录 B树系列 B树 B树的特性: B*树 B树系列总结 MySQL索引简介 MyISAM Inno…

Sphinx文档生成工具(二)

rst语法 官方的语法手册 行内的样式: #斜体 *message* #粗体 **message** #等宽 不能有换行 message标题 一级标题 ^^^^^^^^ 二级标题 --------- 三级标题 >>>>>>>>> 四级标题 ::::::::: 五级标题六级标题 """"…

Vue+node.js医院预约挂号信息管理系统vscode

网上预约挂号系统将会是今后医院发展的主要趋势。 前端技术:nodejsvueelementui,视图层其实质就是vue页面,通过编写vue页面从而展示在浏览器中,编写完成的vue页面要能够和控制器类进行交互,从而使得用户在点击网页进行操作时能够正…

关于 mysql数据库插入中文变空白 的解决方法

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/129048030 红胖子网络科技的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软…

Session详解,学习 Session对象一篇文章就够了

目录 1 Session概述 2 Session原理 3 Session使用 3.1 获取Session 3.2 Session保存数据 3.3 Session获取数据 3.4 Session移除数据 4 Session与Request应用区别 4.1 Session和request存储数据 4.2 获取session和request中的值 4.3 session和request区别效果 5 Sess…

Transformer:开启CV研究新时代

来源:投稿 作者:魔峥 编辑:学姐 起源回顾 有关Attention的论文早在上世纪九十年代就提出了。 在2012年后的深度学习时代,Attention再次被翻了出来,被用在自然语言处理任务,提高RNN模型的训练速度。但是由…

数据库(4)--视图的定义和使用

一、学习目的 加深对视图的理解,熟练视图的定义、查看、修改等操作 二、实验环境 Windows 11 Sql server2019 三、实验内容 学生(学号,年龄,性别,系名) 课程(课号,课名,…

收藏|一文掌握数据分析在企业的实际流程

一、数据分析概念 1.1 数据分析 是指用适当的统计分析方法对收集来的大量数据进行分析,将他们加以汇总和理解并消化,以求最大化地开发数据的功能,发挥数据的作用。 1.2 数据分析包括 描述性数据分析(初级数据分析)…

兼职平台小程序【源码好优多】

简介 微信小程序兼职平台以及问答悬赏平台的整合项目,兼职平台以及问答社区,是一个可以用于学生项目开发或者毕设的小型项目。 功能介绍 微信授权登录 用户兼职选择 优质学长/学姐推荐 兼职推荐 问答板块 评论/回复板块 用户个人中心 页面截图 …

深度学习Week15-common.py文件解读(YOLOv5)

目录 简介 一.基本组件 1.1autopad 1.2Conv 1.3 Focus 1.4Bottleneck 1.5BottleneckCSP 1.6 C3 1.7 SPP 1.8Concat 1.9Contract、Expand 二、重要类 2.1非极大值抑制(NMS) 2.2AutoShape 2.3 Detections 2.4 Classify 三、实验 &#x1f…

WGCNA | 值得你深入学习的生信分析方法!~(网状分析-第三步-模块与特征分析)

1写在前面 之前我们完成了WGCNA输入数据的清洗,网络构建和模块识别。😘 而且还介绍了如何对大型数据分级处理,有效地减少了内存的负担。😷 接着就是最重要的环节了,将不同module与表型或者临床特征相联系,进…