引言
“中断” 这个概念,指的是在单片机运行过程中,在指定条件发生时,停下当前所有工作,去执行中断处理函数内的内容。就像我们在教室上课时,突然地震了,不出意外的话我们都需要停下手中学习任务,去进行一系列的避险动作。
这一节我们通过中断的方式,完成通过按键控制LED亮灭的操作。
准备环节
中断相关知识
STM32的中断控制器支持19个外部中断/事件请求。这十九个外部中断为:
- 线0~15:对应外部IO口的输入中断。
- 线16:连接到PVD输出。
- 线17:连接到连接到RTC时钟事件。
- 线18:连接到USB唤醒事件。
配置使用时,需要先将IO口与相应中断线的映射关系建立,再对其进行使用。那映射关系是怎样的呢?
GPIOx.0 ~ GPIOx.15(x = A,B,C,D,E,F,G)分别对应中断线0 ~ 15
配置GPIO与中断线关系的函数是
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
eg:
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);
把GPIO作为EXTI外部中断时,需要打开AFIO时钟。
APIO时钟何时需要打开,具体可以参考这篇文章:
STM32的AFIO时钟什么时候需要开启
嵌套向量中断控制器(NVIC)
初始化完线上中断和中断条件等内容,还需要配置中断分组。配置中断分组之前,我们需要先确定如何进行分组。这里就需要用到NVIC。
关于NVIC的具体内容可查看这篇博文:嵌套向量中断控制器(NVIC)详解。
编码环节
步骤
- 初始化IO口输入
- 开启AFIO时钟
- 设置IO口与中断线的映射关系
- 初始化线上中断、设置触发条件等
- 配置中断分组,并使能中断
- 编写中断服务函数
main.c(以下内容均省略头文件)
int main(void){
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC终端分组2
LED_Init();
KEY_Init();
EXTIX_Init(); //外部中断初始化
LED1 = 0;
}
exti.h
#ifndef __EXTI_H
#define __EXIT_H
#include "sys.h"
void EXTIX_Init(void); //外部中断初始化
#endif
exti.c
void EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure; //外部中断结构体初始化
NVIC_InitTypeDef NVIC_InitStructure; //中断分组结构体初始化
KEY_Init();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO时钟
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //映射IO口与中断线
//以下为配置中断线初始化
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断线
EXTI_InitStructure.EXTI_Line = EXTI_Line0; //中断线标号
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //触发方式
EXTI_Init(&EXTI_InitStructure);
//以下为中断优先级的配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //声明使用的中断是哪一个
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //设置抢占优先级为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //设置子优先级为3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure);
}
void EXTI0_IRQHandler(void) //中断服务函数
{
delay_ms(10); //软件去抖
if(WK_UP==1)
{
LED0 = !LED0;
LED1 = !LED1;
}
EXTI_ClearITPendingBit(EXTI_Line0); //清除中断位
}
补充
中断服务函数
中断服务函数的名称是固定的,写错会导致无法中断。
STM32的IO口外部中断函数只有六个。分别为:
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
EXTI9_5_IRQHandler
EXTI15_10_IRQHandler
中断线0 ~ 4各对应一个中断服务函数,中断线5 ~ 9共用 EXTI9_5_IRQHandler
,中断线10 ~ 15共用 EXTI15_10_IRQHandler
。
中断服务函数常规格式
void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3)!=RESET) //判断中断线上的中断是否发生
{
//这里写需要执行的服务
EXTI_ClearITPendingBit(EXTI_Line3); //清除中断标志位
}
}
我是这耀眼的瞬间,是划过天边的刹那火焰。