文章目录
一、什么是中断
1、中断的定义
中断的定义大家都很熟悉,是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行,如图所示。
2、中断的种类
中断的种类由ARM公司进行设计,不同的芯片之间的中断种类是不一样的,ARM的cortex—M3有256种中断,中断的来源有两种,但两种的表现的效果都是一样的:
- 系统异常:由CPU内部产生的紧急事件,例如:非法指令
- 外部中断:由外设产生的外部的紧急事件,例如:GPIO电平的变化、定时器溢出等
二、中断文件
1、中断向量表
这是STM32F103C8T6的中断向量表,由十种系统异常和六十种外部中断组成,其中:Reset(复位端)、NMI、HardFault(硬件异常)三个的优先级是负数,其他的优先级是正数。
2、在函数中位置
程序里,在startup_stm32f103xb.s文件中有中断向量表,里面有当前芯片所支持的中断。当发生中断时,会找到相应的中断处理函数的位置,执行中断函数。
三、中断优先级
中断优先级由NVIC(Nested Vectored lnterrupt Controller)管理所有的中断,包括系统异常和外部中断,优先级由两者组成,优先级值越小优先级高,负数的不能修改,正数不能变成负数:
- 抢占优先级:中断嵌套
- 子优先级:相应顺序
优先级中的顺序问题:
- 抢占优先级高的中断可以中断抢占优先级低的中断:先比较抢占优先级
- 两个中断的抢占优先级相同,后来中断要等前面的中断处理完:抢占优先级相同,已经在执行的,即使后面的子优先级大,也要等待
- 两个中断的抢占优先级相同,同时产生,子优先级高的先执行:抢占优先级相同,同时产生子优先级高的先执行
- 抢占优先级、子优先级相同,同时产生,由中断向量表默认位置决定:抢占优先级和子优先级相同的,按照表的位置决定
下面的四个顺序需要我们思考
四、GPIO中断
GPIO的中断是由外部中断/事件控制器EXTI(External lnterrupt/Event Controller)控制,GPIO有两种中断模式:两者的产生源是相同的
- 中断模式:外部信号产生电平变化时触发中断,执行中断服务函数,完成操作,需要变成自定义功能,需要CPU参与
- 事件模式:外部信号产生电平变化时根据配置联动ADC/定时器等执行相关的操作,硬件触发之后执行相对应的操作,不需要CPU参与,响应的速度更快
将PA0、PB0、PC0、…、PG0归到EXTI0管理,PA1、PB1、PC1、…、PG1归到EXTI1管理,以此类推,PA15、PB15、PC15、…、PG15归到EXTI15管理。
当PA0为中断源是,PB0~PG0都不能为中断源。
五、按键中断切换LED亮灭实验
首先,将按键引脚(PA0)设置成中断的形式
我们在STM32CubeMX软件中查看GPIO引脚,发现已经设置成上升沿触发:当低电平变成高电平时这个中断会触发
我们开启抢占优先级并降低优先级设置为2
将NVIC代码初始化勾选
查看代码
MX_NVIC_Init();
里面有优先级和使能中断
static void MX_NVIC_Init(void)
{
/* EXTI0_IRQn interrupt configuration */
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
我们按下按键,会产生EXTI0中断,调用EXTIO中断服务函数,参数是中断引脚
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(KEY_Pin);
}
会继续调用HAL_GPIO_EXTI_Callback(GPIO_Pin)函数
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
HAL_GPIO_EXTI_Callback(GPIO_Pin)是一个复调函数,是虚函数,需要我们重新复写
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
UNUSED(GPIO_Pin);
}
我们在GPIO.c的文件中进行复写
static uint8_t key_flag = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY_Pin)
{
key_flag = ~key_flag;
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,key_flag?GPIO_PIN_RESET);
}
}