《STM32 HAL库开发实战(五)—— 中断》

发布时间:2026/9/4 8:35:24
《STM32 HAL库开发实战(五)—— 中断》 一、什么是中断我们总是先做总要且紧急的事其实处理中断也是一样中断的紧急程度也是分等级的我们把中断的紧急程度叫做中断的优先级在常规程序执行的过程中如果发生了中断单片机会帮我们调用中断响应函数而如果在中断响应函数执行的过程中又遇到第二个中断此时是否执行中断二的中断响应函数取决于中断二的中断优先级。二、中断优先级关于中断优先级从以下四个方面介绍1、中断优先级分组对于我们使用的STM32F103C8T6来说它使用四位二进制数表示中断优先级从bit0到bit3所以它的范围就是0000b~1111b转化为十进制也就是0~15因此总共分为16个优先等级且数字越小表示优先级的程度越高。蓝线以左又叫做抢占优先级蓝线以右又叫子优先级。根据这个规则我们就产生5种不同的分组方式将四个比特位都分给右边的子优先级抢占优先级占0个比特位1级子优先级占4个比特位16级以此类推把这5种方案叫做中断优先级分组。2、中断排队是指抢占优先级别相同的情况下按照响应优先级依次按顺序执行后发生的中断不能打断正在执行的同级中断如果多个中断同时发生响应优先级高的先执行。3、中断嵌套抢占优先级高的可以打断抢占优先级低的从而产生中断嵌套。即只和抢占优先级有关发生中断嵌套的条件新中断的抢占优先级更高。4、举例比如我们使用两位抢占优先级和两位子优先级的分组方式这个时候抢占优先级和子优先级的取值范围都是0~3假设中断1的抢占优先级是2x在中断响应函数的执行过程中又发生了新的中断我们假设中断2的抢占优先级是0/1x那么这个时候就会发生中断嵌套程序会转而去运行抢占优先级更高的中断响应函数。如果中断2的抢占优先级不比中断1高此时就不会发生中断嵌套根据先后顺序依次执行中断函数三、NVIC模块CubeMX设置全称Nested Vectored Interrupt Controller嵌套向量中断控制器负责管理单片机的中断在CubeMX中点击all interrupts即可显示出当前使用的单片机的所有中断这里则是中断优先级分组可以看到一共有五个选项如果不需要中断嵌套则选择第一种如果既需要中断嵌套又需要终端排队则选择下面三种例如我们选择22在右边就可以选择抢占优先级和子优先级的级别。四、串口中断接收实验我们在前面说过如何让LED闪烁起来也说过如何通过串口从电脑接收数据现在我们把这两个实验结合起来通过串口来控制LED的闪烁速度发送1是慢闪发送2是正常发送3是快闪。1、硬件连接单片机上的PC13接的是板载LED采用的是开漏接法然后将USB转TTL模块的TXD接到PA10引脚RXD接到PA9引脚现在先不考虑用串口接收数据的问题先实现板载LED的不同速度的闪烁。在之前我们如果像控制LED的闪灯速度就是在点亮和熄灭LED时加上一个延时通过改变延时的时间来实现不同速度的闪烁所以我们选择直接声明一个变量blinkInterval用来控制闪灯的间隔把它作为延迟函数的参数传进去。2、CubeMX配置在CubeMX新建工程还是先设置调试接口然后调整一下PC13参数并改为输出模式随后生成代码然后打开main.c文件先找到42行这里的注释是私有变量我们一般将全局变量的声明写在下方/* USER CODE BEGIN PV *//* USER CODE END PV */之间。再接着编写闪灯代码往下找到main函数讲闪灯代码写在while循环内随后打开调试模式左上角的全速运行再打开view菜单选择watch1就打开了监视窗口我们在监视窗口中输入我们要监视的变量blinkInterval我们希望他是十进制右键blinkInterval将Hexdecimal Display勾选去掉即可变成十进制这个时候程序在全速运行时我们就可以更改blinkInterval的值例如100030050可以看到LED闪烁的频率是不一样的。接下来用用串口接收命令打开CubeMX将usart1改为异步模式下面的参数例如波特率数据为长度校验位等保持默认再点击NVIC settings有一个USART1 global interrupt即串口1全局中断勾选以使能此中断或者在NVIC选项卡中也能使能该中断因为这里只使用了一个中断中断优先级并不重要这里也是默认就行随后生成代码。3、代码实现完整的代码如下/* USER CODE BEGIN PV */ static uint32_t blinkInterval 1000; static uint32_t dateRcvd; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huarthuart1) { if (dateRcvd 1) { blinkInterval 1000; } else if (dateRcvd 2) { blinkInterval 300; } else if (dateRcvd 3) { blinkInterval 50; } HAL_UART_Receive_IT(huart1, (uint8_t*)dateRcvd, 1); } } /* USER CODE END 0 */ /** * brief The application entry point. * retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ HAL_UART_Receive_IT(huart1, (uint8_t*)dateRcvd, 1); while (1) { /* USER CODE END WHILE */ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); HAL_Delay(blinkInterval); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); HAL_Delay(blinkInterval); /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }五、总结整个过程可以总结为主循环负责让 LED 闪烁串口中断负责接收控制字符回调函数根据字符修改 LED 的闪烁速度。串口收到字符 ↓ 硬件产生中断请求 ↓ NVIC 通知 CPU ↓ CPU 进入 USART1 中断处理函数 ↓ HAL 库检查串口发生了什么 ↓ 发现“一个字节接收完成” ↓ HAL 调用 HAL_UART_RxCpltCallback() ↓ 执行用户编写的处理代码