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

相关文章

利用Python调试串口的示例代码

《利用Python调试串口的示例代码》在嵌入式开发、物联网设备调试过程中,串口通信是最基础的调试手段本文将带你用Python+ttkbootstrap打造一款高颜值、多功能的串口调试助手,需要的可以了... 目录概述:为什么需要专业的串口调试工具项目架构设计1.1 技术栈选型1.2 关键类说明1.3 线程模

Python Transformers库(NLP处理库)案例代码讲解

《PythonTransformers库(NLP处理库)案例代码讲解》本文介绍transformers库的全面讲解,包含基础知识、高级用法、案例代码及学习路径,内容经过组织,适合不同阶段的学习者,对... 目录一、基础知识1. Transformers 库简介2. 安装与环境配置3. 快速上手示例二、核心模

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码

《Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码》:本文主要介绍Java中日期时间转换的多种方法,包括将Date转换为LocalD... 目录一、Date转LocalDateTime二、Date转LocalDate三、LocalDateTim

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

jupyter代码块没有运行图标的解决方案

《jupyter代码块没有运行图标的解决方案》:本文主要介绍jupyter代码块没有运行图标的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录jupyter代码块没有运行图标的解决1.找到Jupyter notebook的系统配置文件2.这时候一般会搜索到

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.