外部中断
1、定义
中断,意味着中途打断现在干的事情,要立即处理紧急的事件。
2.多达 140 个 GPIO(STM32F405xx/07xx 和 STM32F415xx/17xx)通过以下方式连接到 16 个外部中断/事件线。
例如:PA0占用了EXTI0,其他PB0~PI0是不能使用的。
引脚编号决定了对应哪个外部中断。
二、代码思路
1.8051单片机
外部中断的触发方式:低电平触发、下降沿触发 IT0=1
允许外部中断引脚申请中断请求 EX0=1
优先级的配置
中断服务函数
2.STM32
端口A硬件时钟使能
SYSCFG硬件时钟使能
配置引脚的工作模式
将引脚连接到外部中断
中断触发方式:电平触发、边沿触发
允许外部中断引脚申请中断请求
优先级的配置
中断服务函数
注:
中断服务函数是不能被调用,编写格式不能随意编写,这是它特有的存在形式。不同的硬件平台,其编写方法是不一样的。
三、中断优先级
中断优先级的一个意义:出现多个中断同时触发,但是不能同时处理,所以先后顺序之分,要根据实际上的运行环境优先处理重要的中断。
1.概述
STM32 对中断优先级进行分组,共 5 组,组 0~4,这些分组是用于指定当前M4支持多少个抢占优先级和多少个响应优先级。同时,对每个中断设置一个抢占优先级和一个响应优先级。函数原型如下:
/**
* @brief Configures the priority grouping: pre-emption priority and subpriority.
* @param NVIC_PriorityGroup: specifies the priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority //不支持抢占优先级
* 4 bits for subpriority //支持16个响应优先级
* @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority //支持2个抢占优先级
* 3 bits for subpriority //支持8个响应优先级
* @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority //支持4个抢占优先级
* 2 bits for subpriority //支持4个响应优先级
* @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority //支持8个抢占优先级
* 1 bits for subpriority //支持2个响应优先级
* @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority //支持16个抢占优先级
* 0 bits for subpriority //不支持响应优先级
* @note When the NVIC_PriorityGroup_0 is selected, IRQ pre-emption is no more possible.
* The pending IRQ priority will be managed only by the subpriority.
* @retval None
*/
void NVIC_PriorityGroupConfig(uint32_t, NVIC_PriorityGroup)
只要开机初始化一次就可以了。
2.抢占优先级与响应优先级区别
1)高抢占优先级是可以打断正在进行的低抢占优先级的中断。抢占优先级若相同,则不会出现抢占的过程。
2)抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
3)抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
4)抢占优先级相同且响应优先级相同的中断,假如同时发生,会按照硬件内部固定的优先级执行
5)无论是抢占优先级还是响应优先级,优先级数值越小,就代表优先级越高。
四、中断服务函数
要记得清除标志位,告诉CPU,已经完成中断处理。
下面是相关代码及注释
exti.c
#include "stm32f4xx.h"
#include "sys.h"
static GPIO_InitTypeDef GPIO_InitStructure;
static EXTI_InitTypeDef EXTI_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure;
void delay(void)
{
uint32_t i=0x2000000;
while(i--);
}
void exti0_init(void)
{
//使能(打开)端口A的硬件时钟,就是对端口A供电
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//使能系统配置时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
//配置PA0引脚为输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //第0根引脚
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN; //输入模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//高速响应
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使能上下拉电阻
GPIO_Init(GPIOA,&GPIO_InitStructure);
//将PA0和EXTI0连接在一起
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
//外部中断的配置
EXTI_InitStructure.EXTI_Line = EXTI_Line0; //外部中断0
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发,用于识别按键的按下;上升沿触发,用于检测按键的松开;
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //外部中断0的请求通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级0x02
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //响应优先级0x03
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能该通道
NVIC_Init(&NVIC_InitStructure);
}
void exti2_init(void)
{
//使能(打开)端口E的硬件时钟,就是对端口E供电
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
//使能系统配置时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
//配置PE2引脚为输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //第2根引脚
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN; //输入模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//高速响应
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使能上下拉电阻
GPIO_Init(GPIOE,&GPIO_InitStructure);
//将PE2和EXTI2连接在一起
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);
//外部中断的配置
EXTI_InitStructure.EXTI_Line = EXTI_Line2; //外部中断2
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发,用于识别按键的按下;上升沿触发,用于检测按键的松开;
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //外部中断2的请求通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;//抢占优先级0x03
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //响应优先级0x03
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能该通道
NVIC_Init(&NVIC_InitStructure);
}
int main(void)
{
//使能(打开)端口F的硬件时钟,就是对端口F供电
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
//初始化GPIO引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10; //第9 10根引脚
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OUT; //输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增加输出电流能力。
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//高速响应
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使能上下拉电阻
GPIO_Init(GPIOF,&GPIO_InitStructure);
PFout(9)=1;
PFout(10)=1;
//中断优先级的组配置:选择第二组
//优先级,数值越小,优先级就越高
//支持4个抢占优先级:0~3
//支持4个响应优先级:0~3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//exti0初始化
exti0_init();
//exit2初始化
exti2_init();
while(1)
{
}
}
void EXTI0_IRQHandler(void)
{
//判断是否有中断请求
if(EXTI_GetITStatus(EXTI_Line0) == SET)
{
//点亮LED1
PFout(9)=0;
//延时一会
delay();
//熄灭LED1
PFout(9)=1;
//延时一会
delay();
/* 清空标志位,告诉CPU,已经完成当前中断处理;可以响应新的中断请求*/
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
void EXTI2_IRQHandler(void)
{
//判断是否有中断请求
if(EXTI_GetITStatus(EXTI_Line2) == SET)
{
//点亮LED2
PFout(10)=0;
//延时一会
delay();
//熄灭LED2
PFout(10)=1;
//延时一会
delay();
/* 清空标志位,告诉CPU,已经完成当前中断处理;可以响应新的中断请求 */
EXTI_ClearITPendingBit(EXTI_Line2);
}
}