记录一下,方便以后翻阅~
主要内容:
1) 外部中断概述;
2) 外部中断库函数一般设置。
官方资料:《STM32中文参考手册V10》第9章——中断和事件
1. 外部中断基础知识
1.1 STM32的每个I/O都可以作为外部中断输入;
1.2 STM32的中断控制器支持19个外部中断/事件请求:
线0~15:对应外部IO口的输入中断;
线16:连接到PVD输出;
线17:连接到RTC闹钟事件;
线18:连接到USB唤醒事件。
1.3 每个外部中断线可以独立的配置触发方式(上升沿,下降沿或者双边沿触发),触发/屏蔽,专用的状态位;
1.4 从上面可以看出,STM32供I/O使用的中断线只有16个,但是STM32F10x系列的I/O口多达上百个,如STM32F103ZET6(112个),STM32F103RCT6(51个);
1.5 外部中断通用I/O映像:
GPIOx.0映射到EXTI0;
GPIOx.1映射到EXTI1;
…
GPIOx.15映射到EXTI15。
备注:同一时间,只能有一个I/O口映射到中断线EXTIx上。
1.6 对于每个中断线,可以设置相应的触发方式(上升沿触发,下降沿触发,边沿触发)以及使能;
1.7 I/O口外部中断在中断向量表中只分配了7个中断向量,也就是只能使用7个中断服务函数(下表缺EXTI0);
从上表中可以看出,外部中断线5~ 9分配一个中断向量,共用一个服务函数,外部中断线10~15分配一个中断向量,共用一个中断服务函数。
2. 外部中断服务函数列表
void EXTI0_IRQHandler (void);
void EXTI1_IRQHandler (void);
void EXTI2_IRQHandler (void);
void EXTI3_IRQHandler (void);
void EXTI4_IRQHandler (void);
void EXTI9_5_IRQHandler (void);
void EXTI15_10_IRQHandler (void);
3. 外部中断常用库函数
3.1 库函数一
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
//设置IO口与中断线的映射关系,例如GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);//
2.2 库函数二
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
//初始化中断线:触发方式等//
2.3 库函数三
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
//判断中断线中断状态,是否发生,用在写中断服务函数时开头//
2.4 库函数四
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
//清除中断线上的中断标志位,用在写中断服务函数时末尾//
3. EXTI_Init函数解读
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
typedef struct
{
uint32_t EXTI_Line; //指定要配置的中断线//
EXTIMode_TypeDef EXTI_Mode; //模式:事件OR中断,对于外部就选择中断//
EXTITrigger_TypeDef EXTI_Trigger; //触发方式:上升沿/下降沿/双沿触发//
FunctionalState EXTI_LineCmd; //使能 OR失能//
}
EXTI_InitTypeDef;
案例:
//*申明一个结构体,名字为EXTI_InitStructure,结构体原型由EXTI_InitTypeDef确定*//
EXTI_InitTypeDef EXTI_InitStructure;
//使能复用功能时钟//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//设置I/O口与中断线的映射关系//
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2); //GPIOE.2//
//GPIOE.2 中断线以及中断初始化配置,下降沿触发//
EXTI_InitStructure.EXTI_Line=EXTI_Line2;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
//*根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器*//
EXTI_Init(&EXTI_InitStructure);
4. 外部中断的一般配置步骤
4.1 初始化IO口为输入;
GPIO_Init();
4.2 开启IO口复用时钟;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
4.3 设置IO口与中断线的映射关系;
void GPIO_EXTILineConfig();
4.4 初始化线上中断,设置触发条件等;
EXTI_Init();
4.5 配置中断分组(NVIC),并使能中断;
NVIC_Init();
4.6 编写中断服务函数;
EXTIx_IRQHandler();
4.7 清除中断标志位。
EXTI_ClearITPendingBit();
5. 外部中断实验
实现功能:启动后,LED0亮,WK_UP按键控制蜂鸣器叫与不叫,KEY2按键控制LED0亮与灭,KEY1按键控制LED1亮与灭,KEY0按键同时控制LED0和LED1亮灭,这些按键操作的同时,串口会将按键的相关信息传输至PC端。跑马灯,蜂鸣器,按键输入,串口初始化相关代码可参考之前的文章。
5.1exti.h外部中断头文件
#ifndef __EXTI_H
#define __EXTI_H
//申明一个EXTIx_Init初始化函数//
void EXTIx_Init(void);
#endif
5.2exti.c外部中断.c文件
#include "led.h"
#include "beep.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "usart.h"
#include "sys.h"
//编写EXTIx_Init初始化函数,包括中断线配置和每个中断线的优先级配置//
void EXTIx_Init(void)
{
//*申明一个结构体,名字为EXTI_InitStructure,结构体原型由EXTI_InitTypeDef确定*//
EXTI_InitTypeDef EXTI_InitStructure;
//*申明一个结构体,名字为NVIC_InitStructure,结构体原型由NVIC_InitTypeDef确定*//
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟AFIO//
//设置I/O口与中断线的映射关系//
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2); //PE2对应KEY2//
//PE2中断线初始化配置,中断模式,下降沿触发,使能//
EXTI_InitStructure.EXTI_Line=EXTI_Line2; //GPIOx,Pin2对应EXTI2中断线//
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式//
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发//
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能//
//中断线初始化,GPIOE,Pin2映射到EXTI2中断线,中断模式,下降沿触发,使能//
EXTI_Init(&EXTI_InitStructure);
//设置I/O口与中断线的映射关系//
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3); //PE3对应KEY1//
//PE3中断线初始化配置,中断模式,下降沿触发,使能//
EXTI_InitStructure.EXTI_Line=EXTI_Line3; //GPIOx,Pin3对应EXTI3中断线//
//中断线初始化,GPIOE,Pin3映射到EXTI3中断线,中断模式,下降沿触发,使能//
EXTI_Init(&EXTI_InitStructure); //EXTI_InitStructure结构体参数只改中断线//
//设置I/O口与中断线的映射关系//
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4); //PE4对应KEY0//
//PE4中断线初始化配置,中断模式,下降沿触发,使能//
EXTI_InitStructure.EXTI_Line=EXTI_Line4; //GPIOx,Pin4对应EXTI4中断线//
//中断线初始化,GPIOE,Pin4映射到EXTI4中断线,中断模式,下降沿触发,使能//
EXTI_Init(&EXTI_InitStructure); //EXTI_InitStructure结构体参数只改中断线//
//设置I/O口与中断线的映射关系//
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //PA0对应WK_UP//
//PA0中断线初始化配置,中断模式,上升沿触发,使能//
EXTI_InitStructure.EXTI_Line=EXTI_Line0; //GPIOx,Pin0对应EXTI0中断线//
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发//
//中断线初始化,GPIOA,Pin0映射到EXTI0中断线,中断模式,上降沿触发,使能//
EXTI_Init(&EXTI_InitStructure); //EXTI_InitStructure结构体参数改中断线和触发//
//对上述配置好的每个中断进行优先级初始化//
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //选择EXTI0外部中断通道,即PA0,即K_UP
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //响应优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能//
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //选择EXTI2外部中断通道,即PE2,即KEY2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //响应优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能//
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //选择EXTI3外部中断通道,即PE3,即KEY1
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //响应优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能//
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //选择EXTI4外部中断通道,即PE4,即KEY0
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //响应优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能//
NVIC_Init(&NVIC_InitStructure);
}
//编写EXTI0中断服务函数//
void EXTI0_IRQHandler(void)
{
delay_ms(10); //消抖
if(WK_UP==1) //判断WK_UP按键是否按下,按下则WK_UP==1,if(1)
{
BEEP=!BEEP;
printf("蜂鸣器值转换\r\n");
}
EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位
}
//编写EXTI2中断服务函数//
void EXTI2_IRQHandler(void)
{
delay_ms(10); //消抖
if(KEY2==0) 判断KEY2按键是否按下,按下则KEY2==0,if(1)
{
LED0=!LED0;
printf("LED0值转换\r\n");
}
EXTI_ClearITPendingBit(EXTI_Line2); //清除LINE2上的中断标志位
}
//编写EXTI3中断服务函数//
void EXTI3_IRQHandler(void)
{
delay_ms(10); //消抖
if(KEY1==0) 判断KEY1按键是否按下,按下则KEY1==0,if(1)
{
LED1=!LED1;
printf("LED1值转换\r\n");
}
EXTI_ClearITPendingBit(EXTI_Line3); //清除LINE3上的中断标志位
}
//编写EXTI4中断服务函数//
void EXTI4_IRQHandler(void)
{
delay_ms(10); //消抖
if(KEY0==0) 判断WK_UP按键是否按下,按下则KEY0==0,if(1)
{
LED0=!LED0;
LED1=!LED1;
printf("LED0和LED1值转换\r\n");
}
EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中断标志位
}
5.3 main.c主函数
#include "led.h"
#include "beep.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "usart.h"
#include "sys.h"
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口波特率设置为115200
LED_Init(); //初始化与LED连接的硬件接口
BEEP_Init(); //初始化蜂鸣器端口
KEY_Init(); //初始化与按键连接的硬件接口
EXTIx_Init(); //外部中断初始化
LED0=0; //点亮LED0
while(1)
{
printf("OK\r\n");
delay_ms(1000);
}
}
旧知识点
1)复习如何新建工程模板,可参考STM32学习心得二:新建工程模板;
2)复习基于库函数的初始化函数的一般格式,可参考STM32学习心得三:GPIO实验-基于库函数;
3)复习寄存器地址,可参考STM32学习心得四:GPIO实验-基于寄存器;
4)复习位操作,可参考STM32学习心得五:GPIO实验-基于位操作;
5)复习时钟使能相关函数,可参考STM32学习心得七:STM32时钟系统框图解读及相关函数;
6)复习延迟函数,可参考STM32学习心得九:Systick滴答定时器和延时函数解读;
7)复习ST-LINK调试方法,可参考STM32学习心得十一:ST-LINK调试原理+软硬件仿真调试方法;
8)复习如何对GPIO进行复用,可参考STM32学习心得十二:端口复用和重映射;
9)复习中断相关知识,可参考STM32学习心得十三:NVIC中断优先级管理;
10)复习串口通信相关知识,可参考STM32学习心得十四:串口通信相关知识及配置方法。