STM32第十节(中级篇):EXTI(第二节)——GPIO外部中断代码讲解

2024-04-13 16:12

本文主要是介绍STM32第十节(中级篇):EXTI(第二节)——GPIO外部中断代码讲解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

        好久不见,从今天开始我们接着学习有关EXTI中断的内容。本节课我们通过分析GPIO外部中断代码来讲解我们新的知识点。


STM32第十节(中级篇):EXTI(第二节)——GPIO外部中断代码讲解

        首先,我们拷贝一份上节课的文件,然后进行我们本节课的学习。我们先新建一个文件夹到USER里面,然后写一个.c.h文件,分别为bsp_exti.c以及bsp_exti.h文件。然后导入到keil5中。

EXTI函数库代码讲解

初始化GPIO

        我们打开bsp_exti.c文件,然后创建一个函数void EXIT_Key_Config(void),使得按键初始化,即连接到我们的GPIO端口。首先初始化GPIO,GPIO_InitTypeDef  GPIO_InitStruct; 。在这里,我们之前编写的led函数中就写过关于GPIO的宏定义。并且在bsp_exti.h文件中写入。以下代码就是我们bsp_exti.h文件中所需要的全部代码:

#ifndef  __BSP_EXTI_H_
#define  __BSP_EXTI_H_#include "stm32f10x.h"#define KEY1_INT_GPIO_PIN           GPIO_Pin_0
#define KEY1_INT_GPIO_PORT          GPIOA
#define KEY1_INT_GPIO_CLK           RCC_APB2Periph_GPIOAvoid EXIT_Key_Config(void);#endif /* __BSP_EXTI_H_ */

        我们可以看到,我们初始化GPIO的时候,还是老三样:初始化PIN,PORT以及打开为RCC_APB2Periph_GPIOAde的时钟,并将其宏定义为#define KEY1_INT_GPIO_CLK。

        然后我们打开bsp_exti.c文件,然后编写我们的函数。

        我们首先要打开APB2线路上的时钟,使用RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK, ENABLE);函数。他有两个参量,一个是打开RCC_APB2Periph_GPIOA端口,即KEY1_INT_GPIO_CLK。第二个参量我们设置为ENABLE 使得使能打开

        然后我们配置GPIO结构体内容,包括PIN要设置为KEY1_INT_GPIO_PIN,即Pin0。然后就是MODE的配置,配置为浮空输入模式,就是使用外部决定电压。我们默认有一个电阻拉低了电平。

        最后就是设置GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStruct);    函数,我们在这里就不阐述过多,直接写入成员变量KEY1_INT_GPIO_PORT, &GPIO_InitStruct,表示控制的是GPIOA端口以及取GPIO_InitStruct的地址。代码如下所示:

	GPIO_InitTypeDef  GPIO_InitStruct;// 初始化GPIORCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK, ENABLE);	GPIO_InitStruct.GPIO_Pin = KEY1_INT_GPIO_PIN;  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //浮空输入模式		GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStruct);	

初始化EXTI用于产生中断/事件

        从这个框图中我们可以知道要先选择输入线,那么我们在选择输入线的时候,自然是要配置寄存器,你们我们配置的是那个寄存器呢?显而易见我们要配置的是AFIO_EXTICR1寄存器。 

         首先,我们选择GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);函数来进行初始化EXTI。里面有两个形参,分别是GPIO_PortSourceGPIOA, 以及GPIO_PinSource0。我们刚刚操作的是AFIO外设,我们知道,输入线默认的时钟是关闭的,那么我们就要配置时钟,即    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);函数,打开RCC_APB2Periph_AFIO端口上的时钟。

        然后就是配置GPIO_InitStruct初始化结构体成员:

	EXTI_InitTypeDef  EXTI_InitStruct;// 初始化EXTIRCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);EXTI_InitStruct.EXTI_Line = EXTI_Line0;EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;  //触发选择(上升沿)EXTI_InitStruct.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStruct);	//写入寄存器中(指针)

初始化NIVC处理中断

        我们知道,在刚刚我们已经配置好了选择线,那么现在就要打开NVIC,涉及到中断。那么我们就要配置中断优先级:那么我们就要编写EXTI_NVIC_Config()函数。我们要找到关于NVIC结构体,编写结构体成员变量,我们先定义一个变量,叫NVIC嵌套向量中断寄存器:NVIC_InitTypeDef  NVIC_InitStruct;定义结构体变量。接着我们就要进行中断分组:使用NVIC_PriorityGroupConfig(unit32_t NVIC_PriorityGroup)函数,配置中断分组。

    NVIC_InitTypeDef NVIC_InitStruct;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

        在配置完中断分组之后,我们就要初始化每个结构体成员,接着我们设置一个static关键字,使得该函数只能在该文件下使用,其他的文件函数是调用不了的:

static void EXTI_NVIC_Config(void)
{NVIC_InitTypeDef NVIC_InitStruct;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);
}

        在我们配置中断优先级的时候,我们如果选择组0,那么我们就有0个位来表示(0)我们的主优先级,剩下四个位(16)来表示子优先级,对于剩下的中断优先级分组也是如此:

编写中断服务函数

        编译之后无错误之后,我们的中断服务函数要写在stm32f10x.it.c文件中。我们找到void SysTick_Handler(void)函数,在其下方编写新的函数void EXTI0_IRQHandler(void):

void EXTI0_IRQHandler(void)
{if(EXTI_GetITStatus(EXTI_Line0) != RESET){LED_G_TOGGLE;}EXTI_ClearITPendingBit(EXTI_Line0);
}

        我们还需要在stm32f10x.it.c文件中添加bsp_led,h文件,这样我们的中断函数就写完啦。接下来是代码展示(包括KEY2的搭建):

代码展示

bsp_exti.c文件

static void NVIC_Configuration(void)
{NVIC_InitTypeDef NVIC_InitStructure;/* 配置NVIC为优先级组1 *//* 提示 NVIC_PriorityGroupConfig() 在整个工程只需要调用一次来配置优先级分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);/* 配置中断源:按键1 */NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;/* 配置抢占优先级 */NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;/* 配置子优先级 */NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;/* 使能中断通道 */NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);/* 配置中断源:按键2,其他使用上面相关配置 */  NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;NVIC_Init(&NVIC_InitStructure);
}/*** @brief  配置 IO为EXTI中断口,并设置中断优先级* @param  无* @retval 无*/
void EXTI_Key_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure;/*开启按键GPIO口的时钟*/RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);RCC_APB2PeriphClockCmd(KEY2_INT_GPIO_CLK,ENABLE);/* 配置 NVIC 中断*/NVIC_Configuration();/*--------------------------KEY1配置-----------------------------*//* 选择按键用到的GPIO */	GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;/* 配置为浮空输入 */	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);/* 选择EXTI的信号源 */GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE); EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;/* EXTI为中断模式 */EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;/* 上升沿中断 */EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;/* 使能中断 */	EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);/*--------------------------KEY2配置-----------------------------*//* 选择按键用到的GPIO */	GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;/* 配置为浮空输入 */	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);/* 选择EXTI的信号源 */GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, KEY2_INT_EXTI_PINSOURCE); EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;/* EXTI为中断模式 */EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;/* 下降沿中断 */EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;/* 使能中断 */	EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);
}

bsp_exti.h文件

#ifndef __EXTI_H
#define	__EXTI_H#include "stm32f10x.h"//引脚定义
#define KEY1_INT_GPIO_PORT         GPIOA
#define KEY1_INT_GPIO_CLK          (RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO)
#define KEY1_INT_GPIO_PIN          GPIO_Pin_0
#define KEY1_INT_EXTI_PORTSOURCE   GPIO_PortSourceGPIOA
#define KEY1_INT_EXTI_PINSOURCE    GPIO_PinSource0
#define KEY1_INT_EXTI_LINE         EXTI_Line0
#define KEY1_INT_EXTI_IRQ          EXTI0_IRQn#define KEY1_IRQHandler            EXTI0_IRQHandler#define KEY2_INT_GPIO_PORT         GPIOC
#define KEY2_INT_GPIO_CLK          (RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO)
#define KEY2_INT_GPIO_PIN          GPIO_Pin_13
#define KEY2_INT_EXTI_PORTSOURCE   GPIO_PortSourceGPIOC
#define KEY2_INT_EXTI_PINSOURCE    GPIO_PinSource13
#define KEY2_INT_EXTI_LINE         EXTI_Line13
#define KEY2_INT_EXTI_IRQ          EXTI15_10_IRQn#define KEY2_IRQHandler            EXTI15_10_IRQHandlervoid EXTI_Key_Config(void);#endif /* __EXTI_H */

stm32f10_it.c文件

void KEY1_IRQHandler(void)
{//确保是否产生了EXTI Line中断if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) {// LED1 取反		LED1_TOGGLE;//清除中断标志位EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);     }  
}void KEY2_IRQHandler(void)
{//确保是否产生了EXTI Line中断if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) {// LED2 取反		LED2_TOGGLE;//清除中断标志位EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);     }  
}

小结

        我们本节的内容到这里就都结束啦,下节课开始我们就开始学习有关SysTick(滴答计时器)相关的内容。

这篇关于STM32第十节(中级篇):EXTI(第二节)——GPIO外部中断代码讲解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/900608

相关文章

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

嵌入式数据库SQLite 3配置使用讲解

《嵌入式数据库SQLite3配置使用讲解》本文强调嵌入式项目中SQLite3数据库的重要性,因其零配置、轻量级、跨平台及事务处理特性,可保障数据溯源与责任明确,详细讲解安装配置、基础语法及SQLit... 目录0、惨痛教训1、SQLite3环境配置(1)、下载安装SQLite库(2)、解压下载的文件(3)、

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

Python如何去除图片干扰代码示例

《Python如何去除图片干扰代码示例》图片降噪是一个广泛应用于图像处理的技术,可以提高图像质量和相关应用的效果,:本文主要介绍Python如何去除图片干扰的相关资料,文中通过代码介绍的非常详细,... 目录一、噪声去除1. 高斯噪声(像素值正态分布扰动)2. 椒盐噪声(随机黑白像素点)3. 复杂噪声(如伪

Java Spring ApplicationEvent 代码示例解析

《JavaSpringApplicationEvent代码示例解析》本文解析了Spring事件机制,涵盖核心概念(发布-订阅/观察者模式)、代码实现(事件定义、发布、监听)及高级应用(异步处理、... 目录一、Spring 事件机制核心概念1. 事件驱动架构模型2. 核心组件二、代码示例解析1. 事件定义