什么是中断
-
打断CPU执行正常的程序,转而处理紧急程序,然后返回原暂停的程序继续运行
中断的作用意义
-
高效处理紧急程序,不会占用CPU资源
-
实时控制:在确定时间内对相应事件作出响应,如:温度监控
-
故障处理:检测到故障,需要第一时间处理,如:电梯门夹人了
-
数据传输:不确定数据何时会来,如:串口数据接收
NVIC基本概念
Nested vectored interrupt controller,嵌套向量中断控制器,属于内核
NVIC支持:256个中断(16内核 + 240外部),支持:256个优先级
中断优先级基本概念
-
抢占优先级:高抢占优先级可以打断正在执行的低抢占优先级中断
-
响应优先级:当抢占优先级相同时,响应优先级高的先执行,但是不能相互打断
-
数值越小,优先级越高
-
优先级分组 AIRCR[10:8] IPRx bit[7:4]分配 分配结果 0 111 None :[7:4] 0位抢占优先级,4位响应优先级 24,16个响应优先级 1 110 [7] :[6:4] 1位抢占优先级,3位响应优先级 2 101 [7:6] :[5:4] 2位抢占优先级,2位响应优先级 3 100 [7:5] :[4] 3位抢占优先级,1位响应优先级 4 011 [7:4] :None 4位抢占优先级,0位响应优先级
编号 | 自然优先级 | 对应外设 | 抢占 | 响应 | 执行顺序 |
---|---|---|---|---|---|
3 | 10 | RTC | 2 | 1 | 2 |
6 | 13 | EXTI0 | 3 | 0 | 4 |
7 | 14 | EXTI1 | 2 | 0 | 1 |
-1 | 6 | Systick | 3 | 0 | 3 |
NVIC的配置方法
1.设置中断分组 HAL_NVIC_SetPriorityGrouping
2.设置中断优先级 HAL_NVIC_SetPriority
3.使能中断 HAL_NVIC_EnableIRQ
上面相关函数是定义在stm32f1xx_hal_cortex.c里面的
注意:void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)
IRQn_Type IRQn 中断名,这个形参是个枚举类型,直接把要用的宏复制过来就行(双击他然后右键go to过去可以查看)
uint32_t PreemptPriority 抢断优先级
uint32_t SubPriority 响应优先级
EXTI基本概念
External(Extended) interrupt/event Controller,外部(扩展)中断事件控制器
外部中断,是指一些涉及GPIO引脚电平变化或者RTC和USB等外设唤醒事件所触发的中断,由外部中断控制器EXTI管理
中断和事件的理解:
中断:要进入NVIC,有相应的中断服务函数,需要CPU处理
事件:不进入NVIC,仅用于内部硬件自动控制的,如:TIM、DMA、ADC
-
中断触发方式有三种:上升沿触发、下降沿触发和双边沿触发。我们把通过GPIO引脚产生的中断简称为外部中断
-
STM32将GPIO引脚进行了分组:尾号相同的引脚作为一组,通过1个多路选择器连接到1个EXTI外部中断线。同组的引脚只能由1个与外部中断线连接,其他引脚就不能作为外部引脚,本质上可供用户同时使用的外部中断引脚最多只有16个
-
NVIC为EXTI所管理的16个外部中断线提供了7个中断通道。EXTI0~EXTI4 连接到独立的中断通道,有单独的ISR。EXTI5~EXTI9 共享1个中断通道,EXTI10~EXTI15共享1个中断通道。
EXTI的HAL库设置步骤(外部中断)
-
使能GPIO时钟 __HAL_RCC_GPIOx_CLK_ENABLE
-
GPIO/AFIO(SYSCFG)/EXTI HAL_GPIO_Init,一步到位
-
设置中断分组 HAL_NVIC_SetPriorityGrouping,此函数仅需设置一次!(在HAL_Init里已经设置)
-
设置中断优先级 HAL_NVIC_SetPriority
-
使能中断 HAL_NVIC_EnableIRQ
-
设计中断服务函数 EXTIx_IRQHandler,中断服务函数,清中断标志!
HAL库中断回调处理机制
HAL库中断处理公用函数 HAL_GPIO_EXTI_IRQHandler
HAL库数据处理回调函数 HAL_GPIO_EXTI_Callback
在led.c里得加一个灯,及用PA0和PA1
exti.c
#include "exti.h"
#include "delay.h"
void EXTI_init(void)
{
GPIO_InitTypeDef GPIO_Init; //声明结构体,命名为GPIO_Init
__HAL_RCC_GPIOE_CLK_ENABLE(); //使能时钟
GPIO_Init.Pin = GPIO_PIN_0; //引脚号
GPIO_Init.Mode = GPIO_MODE_IT_FALLING; //具有下降沿触发检测的外部中断模式
GPIO_Init.Pull = GPIO_PULLUP;
GPIO_Init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//可配可不配
HAL_GPIO_Init(GPIOE,&GPIO_Init); //第二个参数是结构体指针,所以要取个地址
//HAL_NVIC_SetPriorityGrouping该函数在hal.c文件的HAL_Init里已经定义F1分组为2,F4分组为4
HAL_NVIC_SetPriority(EXTI0_IRQn,2,0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms (20); //消抖 注意在上添加"delay.h"头文件
if(GPIO_Pin==GPIO_PIN_0)//判断是哪个中断线进来了
{
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_0)==0)
{
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_1);
}
}
}
exti.h
#ifndef _EXTI_H_
#define _EXTI_H_
#include "main.h"
void EXTI_init(void);
#endif
main.c
#include "main.h"
int main(void)
{
HAL_Init(); /*初始化HAL库*/
delay_init(); /*延时初始化*/
Stm32_Clock_Init(); /*设置时钟*/
led_init(); /*LED初始化*/
EXTI_init();
while(1)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);//置1熄灭
delay_ms(500); //延时500ms
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);//置0亮
delay_ms(500);
// LED_Ctrl(LED_PIN_0, LED_OFF);
// delay_ms(500);
// LED_Ctrl(LED_PIN_0, LED_ON);
// delay_ms(500);
}
}
main.h
#ifndef __MAIN_H
#define __MAIN_H
#include "stm32f4xx_hal.h"
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "exti.h"
#endif