RPi Pico配置UART0_RX引脚IRQ中断后触发即冻结问题求助
问题根源
你的代码触发冻结主要有两个核心错误:
- ISR(中断服务函数)上下文禁止使用阻塞API:
sleep_ms()是阻塞延时函数,依赖系统滴答定时器的调度逻辑,在中断上下文中调用会直接导致系统调度异常,出现卡死。同时ISR要求执行时间尽可能短,长耗时、阻塞类操作都不允许放在ISR中执行。 - 未清除UART中断标志:你配置了UART RX有数据时触发中断,进入ISR后如果没有读取UART接收缓冲区的数据,RX中断标志会一直处于置起状态,退出ISR后会立刻再次触发中断,CPU会被持续占用无法执行主循环代码,看起来就像直接冻结。
如果是GPIO中断出现相同问题,原因大概率是进入ISR后没有调用gpio_acknowledge_irq()清除对应的GPIO中断标志,也会出现中断反复触发导致的卡死。
修复方案
核心原则是:ISR内只做最低限度的紧急操作,所有业务逻辑、阻塞操作全部放到主循环执行,修复后的代码示例如下:
#include <stdio.h> #include "pico/stdlib.h" #include "hardware/irq.h" #include "hardware/uart.h" // 共享变量必须加volatile修饰,防止编译器优化 volatile bool data_received = false; volatile uint8_t rx_buffer; void onDataReceived() { // 读取UART FIFO中所有可读取的数据,读操作会自动清除RX中断标志 while (uart_is_readable(uart0)) { rx_buffer = uart_getc(uart0); } // 仅打标记,不执行业务逻辑 data_received = true; gpio_put(16, 1); } int main() { // 原有初始化逻辑不变 stdio_init_all(); gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_init(16); gpio_set_dir(16, GPIO_OUT); uart_init(uart0, 115200); gpio_set_function(1, GPIO_FUNC_UART); gpio_set_function(0, GPIO_FUNC_UART); irq_set_exclusive_handler(UART0_IRQ, onDataReceived); irq_set_enabled(UART0_IRQ, true); uart_set_irq_enables(uart0, true, false); while (1) { // 在主循环中处理中断触发的业务逻辑 if (data_received) { data_received = false; sleep_ms(500); gpio_put(16, 0); sleep_ms(500); } // 原有默认LED闪烁逻辑 gpio_put(PICO_DEFAULT_LED_PIN, 1); sleep_ms(200); gpio_put(PICO_DEFAULT_LED_PIN, 0); sleep_ms(200); } return 0; }
注意事项
- 所有在ISR和主循环之间共享的变量必须加
volatile修饰,避免编译器优化导致两个上下文中读取的变量值不同步 - 要是使用GPIO中断,进入ISR后必须首先调用
gpio_acknowledge_irq(引脚号, 中断边沿类型)清除中断标志,否则也会出现反复触发中断导致的卡死问题
内容的提问来源于stack exchange,提问作者The Origin
相关产品推荐
相关产品推荐

