GPIO 和中断控制 LED 的状态
中断的概念
中断是 MCU 强行从正常的主任务切换到由某些内部或外部条件的紧急任务。中断的优先程度远远高于主任务,MCU 会暂时把主任务挂起,转而处理中断任务,之后再执行主任务。
引起中断的外部条件来自于外围设备、硬件断点请求、访问错误和复位等。引起中断的内部条件有指令不对、界错误、违反特权级和跟踪等。
中断服务程序
当一个中断发生之后,如何处理这个中断呢?从软件层面来理解:由一个函数来处理这个中断内容,称之为中断服务程序(Interrupt Service Routine,ISR)。
中断向量号
给 MCU 能够识别的每个中断源编号,就是中断向量号。中断向量表按照中断向量号从小到大的顺序填写中断服务程序的首地址,且不能遗漏。
中断号 IRQ
中断号 IRQ 把内核中断和非内核中断加以区分,对于非中断内核,IRQ 从 0 开始递增;对于内核中断,IRQ 从 -1 开始递减。IRQ 位于 stm32l431xx.h:
中断向量表
基本上每一个中断源都有与之对应的中断服务程序,中断源被 MCU 识别之后,要执行相应的中断服务程序。这些中断服务程序被存储在中断向量表中,中断向量表一般位于工程的启动文件中,startup_stm32l431xp.s:
中断处理过程
中断处理的基本过程分为中断请求、中断检测、中断响应与中断处理灯过程。
中断源 MCU 发起一个中断请求信号(电信号),中断控制器(NVIC)获取中断源对应的中断向量号。MCU 每执行一条指令结束时,会检测系统中是否有中断请求信号。如果有中断请求信号,MCU 将暂停执行任务,转而处理中断(中断响应);如果没有中断请求信号,MCU 继续执行任务。
中断响应过程中,MCU 会检查该中断源是否被允许。如果该中断源被允许,中断被忽略。中断响应过程需要 MCU 把当前的上下文保存到堆栈中,通过中断向量号找到对应的中断服务程序 ISR,转而执行该程序(ISR)。执行完成之后,就回到之前的上下文,继续执行主任务。
- 中断源:中断的源头,有外部和内部之分。
- 中断服务程序:处理中断源的函数。
- 中断向量号:识别中断源的编号。
- 中断号:对中断服务程序进行区分,区别内核和非内核。
- 中断向量表:一个连续的存储表,存储中断服务程序的首地址。
实验检测理论
实验准备
开发板:STM32L431RCT6(小熊派)
引脚配置:PB2(按键)、PB3(按键)、PC13(LED)
NVIC 模块中开启 EXTI2 和 EXTI3 的中断。找到 SYS 模块,打开 Serial Wire,方便调试。
其余的配置请看02#嵌入式系统基础:GPIO 和轮询控制 LED 的状态 - CubeMX 配置。
编写代码
在 main.c 中编写中断回调函数:
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == S4_KEY_Pin) {
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
} else if (GPIO_Pin == S3_KEY_Pin) {
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
}
}
/* USER CODE END 0 */
效果演示
总结
到目前为止,嵌入式的学习都非常简单,基本上全是点灯,只不过点灯方式有不同。轮询点灯就是一直无限循环判断按键的电平状态,是否有向 MCU 输入电平,判断引脚是哪一个,进而做出相应的处理;中断是 NVIC 管理中断,MCU 对中断请求进行响应,从中断回调函数中处理相应的处理。数模/模数模块会更加有趣,以及之后的知识点。