STM32笔记(六)---GPIO中断EXTI
GPIO中断EXTI
一、 基础概念
EXTI框图
外部中断通用I/O映像
EXTI 中断/事件线
∴
1.输入线总共有20条,EXTI0~EXTI19
2.通过配置AFIO_EXTICRx寄存器相应位段进行设置:
以框图为配置步骤参考,上升沿与下降沿触发选择寄存器(EXTI_RTSR 、EXTI_FTSR )配置后GPIO触发则边沿检测电路输出1与软件中断事件寄存器(EXTI_SWIER )相或;
上端(中断):输出至请求挂起寄存器(EXTI_PR)置1并同中断屏蔽寄存器(EXTI-IMR)相与输出至NVIC中断控制器(中断服务函数)
下端(事件):输出至与门跟事件屏蔽寄存器(EXTI_EMR )相与输出至脉冲发生器(常常与ADC关联)
上升沿与下降沿触发选择寄存器(EXTI_RTSR 、EXTI_FTSR )
以GPIO上升沿触发选择寄存器(EXTI_RTSR)为例,配置上升沿触发选择寄存器相应位为1
软件中断事件寄存器(EXTI_SWIER )
挂起寄存器(EXTI-PR)
中断屏蔽寄存器(EXTI-IMR)
事件屏蔽寄存器(EXTI_EMR)
二、中断步骤:
-
GPIO触发
-
EXTI配置
-
NVIC配置
-
NVIC中断服务
三、 中断编程:
两个文件: bsp_exti.c 和 bsp_exti.h 文件用来存放 EXTI 驱动程序及相关宏定义,中断服务函数放在 stm32f10x_it.h 文件中。
思路:
- 初始化用来产生中断的 GPIO;
- 初始化 EXTI;
- 配置 NVIC;
- 编写中断服务函数;
EXTI_InitTypeDef结构体
typedef struct {
uint32_t EXTI_Line; // 中断/事件线
EXTIMode_TypeDef EXTI_Mode; // EXTI 模式
EXTITrigger_TypeDef EXTI_Trigger; // 触发类型
FunctionalState EXTI_LineCmd; // EXTI 使能
} EXTI_InitTypeDef
- EXTI_Line: EXTI 中断/事件线选择,可选 EXTI0 至 EXTI19。
- EXTI_Mode: EXTI 模式选择,可选为产生中断(EXTI_Mode_Interrupt)或者产生事件(EXTI_Mode_Event)。
- EXTI_Trigger: EXTI 边沿触发事件,可选上升沿触发(EXTI_Trigger_Rising)、下降沿触发 (EXTI_Trigger_Falling) 或 者 上 升 沿 和 下 降 沿 都 触 发(EXTI_Trigger_Rising_Falling)。
- EXTI_LineCmd:控制是否使能 EXTI 线,可选使能 EXTI 线(ENABLE)或禁用(DISABLE)。
bsp-exti.c
#include "bsp-exti.h"
//配置EXTI中断优先级
//初始化连接EXTI的按键GPIO
//初始化EXTI用于产生中断/事件
//开启AFIO外设时钟
//选择输入线(EXTIConfig)
//初始化NVIC-EXTI中断配置,用于处理中断
//编写中断服务函数
//main函数声明内容
//配置EXTI中断优先级函数(static---只被当前文件调用)
static void EXTI_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //设置中断优先级组:1组(整个系统为同一组)
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; //Channel这里EXTI5~9都是用一个中断源、EXTI10~15也是一个
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; //子优先级0(响应优先级)
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStruct); //初始化
//EXTI13为中断源
NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级1
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; //子优先级0(响应优先级)
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //使能
NVIC_Init(&NVIC_InitStruct); //初始化
}
void EXTI_Key_Config(void)
{
//定义GPIO/NVIC结构体
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStruct;
//配置中断优先级
EXTI_NVIC_Config();
//初始化连接EXTI的按键GPIO
RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK, ENABLE);//RCC时钟开启
//GPIO结构体配置(KEY1--A0)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入模式
GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure); //GPIO初始化
//GPIO结构体配置(KEY2--C13)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入模式
GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure); //GPIO初始化
//初始化EXTI用于产生中断/事件
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO外设时钟
//选择输入线(EXTIConfig)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13);
//初始化NVIC结构体
//“stm32f10x_exti.h”---EXTI_InitTypeDef
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; //A0上升沿触发
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct); //EXTI初始化
EXTI_InitStruct.EXTI_Line = EXTI_Line13;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; //C13下降沿触发
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct); //EXTI初始化
}
IRQHandler—'stm32f10x_it.c’
//在startup_stm32f10x.h中找中断服务函数名称
//EXTI0中断服务函数
void EXTI0_IRQHandler(void)
{
//当中断标志位**时
if(EXTI_GetFlagStatus(EXTI_Line0) != RESET)
{
LED_Delay(0xFFFFFF); //便于观察现象
LED_TOGGLE; //LED翻转
}
//完成翻转服务内容后清除中断标志位
EXTI_ClearITPendingBit(EXTI_Line0);
}
//EXTI13中断服务函数
void EXTI15_10_IRQHandler(void)
{
//当中断标志位**时
if(EXTI_GetFlagStatus(EXTI_Line13) != RESET)
{
LED_Fire(); //LED流水灯函数
}
//完成翻转服务内容后清除中断标志位
EXTI_ClearITPendingBit(EXTI_Line13);
}
main函数
int main(void)
{
LED_GPIO_Config();
EXTI_Key_Config();
while(1)
{
//中断表现为延时期间抢占优先级为1的C13无法打断抢占优先级为0的A0,只有当A0完成中断服务时,才进入C13归属的EXTI中断
//同时C13可以被A0打断
}
}
配置流程总结
配置EXTI中断优先级(NVIC_InitTypeDef结构体配置通道优先级、NVIC_PriorityGroupConfig()配置优先级分组)
初始化连接EXTI的按键GPIO(RCC使能、GPIO配置)
初始化EXTI用于产生中断/事件(开启AFIO外设时钟、选择输入线(EXTIConfig))
初始化NVIC-EXTI中断配置,用于处理中断(EXTI_InitTypeDef结构体中断属性配置)
编写中断服务函数(正确的中断服务函数名称、中断标志位(需要时加入中断线判断))
main函数声明内容(Config配置)
疑问解答
-
PA0/PB0/PC0都挂到EXTI0上,怎么处理中断?
这时中断源设置中的最后设置中断GPIO口会覆盖同中断线上已设置的GPIO口。(AFIO_EXTICR1寄存器设置讲述很清楚)
即同时设置PA0,PD0情况下,PA0若为后设置中断源,由于两者挂载同一中断线,则选择后者(A0)为中断源
解决方法:同中断线通过IO口扫描。 -
可以同时配置共用一个中断服务函数的两个中断源吗,怎么区分?
明内容(Config配置)
上一篇: php nginx 实时输出实例讲解
下一篇: My Sql 1067错误兼编码问题解决