• STM32CubeIDE基础学习-EXTI外部中断实验


    STM32CubeIDE基础学习-EXTI外部中断实验



    前言

    中断概念:让CPU打断正在执行的程序,进而去执行紧急的程序,退出中断后回到原打断中断处继续执行。

    前面学习了GPIO作为输入功能的实验,现在来学习使用中断的方式实现GPIO功能的控制,直接在KEY的工程基础上进行添加中断的功能代码就行,其它的功能不用修改。

    外部中断实验和KEY按键实验的现象是一样的,只是本实验采用的是中断的方式实现而已,前面按键使用的查询方式,比较耗CPU。

    这里说明一下:
    前面按键使用的是轮询的方式,本实验将采用中断的方式来实现功能的控制,本实验之所以可以用按键来控制蜂鸣器和LED,是因为刚好按键的引脚和中断线是重合的,所以就很好的借用了按键来触发边沿检测进而触发中断,实质和按键关系不是很大。当没有接按键,用杜邦线把该引脚接3.3V 或 GND也可以实现功能,有兴趣可以测试下。

    STM32CubeIDE基础知识学习回顾

    实验目的:
    学习外部中断功能的使用,实现按键控制BEEP和LED状态翻转功能。


    第1章 硬件介绍

    本实验使用的开发板主控芯片是STM32F103C8T6,其核心原理图如下:

    在这里插入图片描述

    时钟来源使用的是外部高速8M晶振作为高速时钟。

    KEY_UP按键接到芯片的PA0引脚上,KEY按键接到芯片的PA2引脚上,原理图如下图所示:

    在这里插入图片描述

    第2章 工程配置

    本实验直接采用上一个按键实验的工程作为基础模板,直接拷贝粘贴即可,然后在上面添加EXTI和NVIC的相关功能配置即可,其它不用修改,就不用再新建工程了。

    2.1 工程外设配置部分

    配置GPIO,鼠标左键点击该引脚,前面按键输入实验设置的功能是输入的,现在是外部中断的实验,那么就需要设置为EXTI的方式了。如下图所示:

    在这里插入图片描述

    在这里插入图片描述

    选择完成后如下图所示:

    在这里插入图片描述

    这个软件有一个好处就是能实时检测同一个中断线不能多个共存,当你选择了EXTI2后,其它EXTI2的引脚就选不了这个外部中断功能了,比如选了PA2引脚再选择PB2引脚,则会把PA2选择的功能覆盖掉只留下PB2的,这样就说明它们是不能同时使用的,后面就不会存在引脚冲突的问题了。

    接下来就可以配置具体端口功能了。

    端口功能配置如下:
    1、模式配置为上升沿、下降沿和双边沿触发模式。
    2、更据硬件原理图来设置输出上拉或下拉。
    3、User Label建议定义一个自己喜欢见名知意的名字,方便写程序时查看和方便使用。

    模式配置说明如下:

    在这里插入图片描述
    后面几个事件模式本实验没有用到,这里就不展开描述了。

    注意
    为了确保能稳定正确读取到按键的触发电平,这里KEY_UP是需要配置下拉输入。
    为了确保能稳定正确读取到按键的触发电平,这里KEY是需要配置上拉输入。

    配置EXTI0和EXTI2具体的引脚配置如下图所示:

    在这里插入图片描述

    KEY_UP引脚采取上升沿的触发方式,配置为下拉输入。

    在这里插入图片描述

    KEY引脚采取下降沿的触发方式,配置为上拉输入。

    配置完EXTI了之后,就可以进行配置NVIC了,主要设置中断使能、中断分组、中断优先级等信息。如下图所示:

    在这里插入图片描述

    在这里插入图片描述

    设置后如上图所示:要注意标号2处的抢占优先级选择问题,默认是15的,后面代码需要用到延时消抖,如果选择了默认15的话,优先级是最低的,触发中断后会一直卡死在延时里面而出不来,所以这里需要设置的优先级比外部中断的都要高才行,不然就会让程序出问题的。

    一般情况下的程序不建议在中断里面放阻塞函数,比如延时、printf等,避免程序执行出错,而且中断执行需要遵循快进快出的原则,不用过多的嵌套复杂代码。

    RCC时钟、调试接口都不用修改,保持默认配置即可。

    最终配置的功能如下图所示:

    在这里插入图片描述

    到此,整个工程需要新增的功能就配置完成了,接下来就可以生成代码工程进行代码编写了。

    2.2 生成工程代码部分

    可以按快捷键ALT+K,或者点击生成图标按钮生成代码工程。

    生成后最终会显示下图这样的代码:

    在这里插入图片描述

    可以看到继承了前面的外设功能代码,接着就可以在上面添加自己需要实现的中断控制功能的代码了。

    第3章 代码编写

    进入main函数后如下图所示:

    在这里插入图片描述

    可以看到有这个stm32f1xx_it.c文件,里面存放了生成中断相关的函数代码,可以双击进去看具体的函数定义。如下图所示:

    在这里插入图片描述

    可以看到有两个中断服务处理函数,接着就发现两个中断处理服务程序都调用了HAL_GPIO_EXTI_IRQHandler()函数,函数里面的参数是中断所在的引脚号,那么再跳进去HAL_GPIO_EXTI_IRQHandler()函数里面看具体定义,可以看到下面这个函数的定义情况。如下图所示:

    在这里插入图片描述

    进入之后,可以看到这个中断服务程序先判断中断线的,然后清除中断标志,最后就调用HAL_GPIO_EXTI_Callback()函数。

    接着再进去HAL_GPIO_EXTI_Callback()这个函数,发现该函数在库里面是弱定义的,提示需要用户自己重新定义才行。如下图所示:

    在这里插入图片描述

    接着就可以在这个函数里面编写自己的代码了,可以看到这个函数是库提供的,是一个弱定义的函数,说明如果用户没有定义和该函数一样名字的函数,则执行这里面的代码,有检测到定义则执行用户定义的函数功能。

    一般情况下都不会直接在这个函数这里面写功能代码的,需要拷贝这个函数到其它地方或其它文件进行编写,具体位置没有强制要求,但一般习惯拷贝到stm32f1xx_it.c里面其它位置进行功能代码编写。

    编写完中断处理代码内容如下图所示:

    在这里插入图片描述

    代码片示例如下:

    /* USER CODE BEGIN 1 */
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
     	HAL_Delay(10);         /* 延时消抖 */
    	switch(GPIO_Pin)
    	{
    		case KEY_UP_Pin :
    			if(HAL_GPIO_ReadPin(KEY_UP_GPIO_PORT, KEY_UP_GPIO_PIN) == GPIO_PIN_SET)/* KEY_UP按下 */
    			{
    				HAL_GPIO_TogglePin(BEEP_GPIO_PORT, BEEP_GPIO_PIN);   /* BEEP翻转 */
    				break;
    			}
    
    		case KEY_Pin :
    			if(HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY_GPIO_PIN) == GPIO_PIN_RESET)/* KEY按下 */
    			{
    				HAL_GPIO_TogglePin(LED_GPIO_PORT, LED_GPIO_PIN);     /* LED翻转 */
    				break;
    			}
    	}
    }
    /* USER CODE END 1 */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    中断执行逻辑方式和前面按键查询方式是差不多的,当中断线被触发了之后就执行里面的功能代码。KEY_UP是上升沿触发中断,KEY是下升沿触发中断。

    到此,采用中断方式控制BEEP和LED的代码就写完了,编译下载后按下对应的按键就可以看到蜂鸣器和LED翻转情况了。

    附加部分
    前面学习了按键使用宏定义的方式,那么也可以引入到这里来,可以让代码量看上去少了很多。如下图所示:

    在这里插入图片描述

    代码片示例如下:

    /* USER CODE BEGIN 1 */
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
     	HAL_Delay(10);         /* 延时消抖 */
    	switch(GPIO_Pin)
    	{
    		case KEY_UP_Pin :
    			if(KEY_UP == GPIO_PIN_SET)           /* KEY_UP按下 */
    			{
    				HAL_GPIO_TogglePin(BEEP_GPIO_PORT, BEEP_GPIO_PIN);/* BEEP翻转 */
    				break;
    			}
    		case KEY_Pin :
    			if(KEY == GPIO_PIN_RESET)            /* KEY按下 */
    			{
    				HAL_GPIO_TogglePin(LED_GPIO_PORT, LED_GPIO_PIN);/* LED翻转 */
    				break;
    			}
    	}
    }
    /* USER CODE END 1 */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    要注意,这里使用了相关的外设,则还要把相关头文件引入到这个stm32f1xx_it.c里面才行,不然会报错找不到定义的。如下图所示:

    在这里插入图片描述

    实现这个外部中断的功能就只需要在这个stm32f1xx_it.c文件里面完成代码编写即可,main函数的while里面以及其它所有的文件都不需要再添加写任何的代码了。

    到此,整个中断控制的代码就全部写完了。

    第4章 实验现象

    编译下载代码后,按开发板的KEY_UP按键,可以听到蜂鸣器的状态发生了变化,当再一次按下按键时,蜂鸣器的状态也会翻转。当按下开发板的KEY按键后,可以看到LED灯的状态翻转了,再一次按下时,LED的状态又发生了翻转。当长按按键不松手,则程序会一直保持该执行的状态,能看到这些现象之后则说明这个代码编写逻辑是没有问题的。


    总结

    这个外部中断的内容不是特别难理解,代码逻辑和按键实验的差不多,当检测到IO的电平发生变化时,即可触发外部中断,进而执行中断服务函数。重点是理解中断线和回调函数的使用问题。

    中断执行流程:
    按键按下 > 检测到边沿信号从而触发外部中断线 > 跳转到中断服务程序执行该中断 > 最后进行执行中断回调函数。

    注意事项:
    1)STM32所有IO都支持外部中断功能,但是不同的端口(PORTA ~ PORTC)相同的PIN(PIN0 ~ PIN15)引脚就不能同时使用外部中断。

    2)前面判断中断线时,在case里面用了if判断,这个是用于确认按键按下的,目的是为了更准确的判断该中断是否真正的被触发,如果不要这个if判断也是没有问题的,想要程序执行稳定,建议加上的。

  • 相关阅读:
    python计算程序开始、结束以及运行的时间
    hadoop103 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)
    数据结构与算法-Hash算法
    NVIDIA平台的兼容性表,其中包括nano、agx xavier 、tx兼容的deepstream和cuda等版本信息
    ubuntu 18.04 LTS交叉编译opencv 3.4.16并编译工程[全记录]
    基于Java的网络流量分析软件设计
    3. 无重复字符的最长子串
    Pytorch 多卡并行(1)—— 原理简介和 DDP 并行实践
    vue3中全局配置axios
    开源OCR模型对比
  • 原文地址:https://blog.csdn.net/weixin_53944340/article/details/136764535