You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Raspberry Pi Pico RP2040 UART发送时无限中断,如何应答?

Raspberry Pi Pico RP2040 UART发送无限中断问题修复

问题描述

在Raspberry Pi Pico RP2040开发板上,UART发送数据时会触发无限中断。修改官方示例"uart_advanced"复现该问题,无论是否启用FIFO,问题都会出现。为了在示波器上观测问题,在中断处理函数中切换GPIO电平:

  • 通道1:UART TX线路GPIO(引脚8)
  • 通道2:中断触发指示GPIO(引脚16)

问题代码如下:

#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/irq.h"
#include "hardware/gpio.h"


#define UART_ID         uart1
#define BAUD_RATE       115200
#define DATA_BITS       8
#define STOP_BITS       1
#define PARITY          UART_PARITY_NONE

#define UART_TX_PIN     8
#define UART_RX_PIN     9

#define D_GPIO_TEST     16


// interrupt handler
void on_uart_interrupt() {
    for( int i = 0; i < 8; ++i ) {
        gpio_put( D_GPIO_TEST, true ) ;
    }
    gpio_put( D_GPIO_TEST, false ) ;
}


int main() {
gpio_init( D_GPIO_TEST ) ;
gpio_set_dir( D_GPIO_TEST, GPIO_OUT ) ;
gpio_pull_up( D_GPIO_TEST ) ;
gpio_put( D_GPIO_TEST, false ) ;

   // Set up our UART with a basic baud rate.
    uart_init(UART_ID, 2400);

    // Set the TX and RX pins by using the function select on the GPIO
    // Set datasheet for more information on function select
    gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
    gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);

    // Actually, we want a different speed
    // The call will return the actual baud rate selected, which will be as close as
    // possible to that requested
    int __unused actual = uart_set_baudrate(UART_ID, BAUD_RATE);

    // Set UART flow control CTS/RTS, we don't want these, so turn them off
    uart_set_hw_flow(UART_ID, false, false);

    // Set our data format
    uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);

    // Turn on FIFO's 
    //uart_set_fifo_enabled(UART_ID, true);

    // Set up a interrupt
    // We need to set up the handler first
    // Select correct interrupt for the UART we are using
    int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ;

    // And set up and enable the interrupt handlers
    irq_set_exclusive_handler(UART_IRQ, on_uart_interrupt);
    irq_set_enabled(UART_IRQ, true);

    // Now enable the UART interrupts
    uart_set_irq_enables(UART_ID, false, true);

    sleep_ms( 10 ) ;

    uart_puts(UART_ID, "Hello uart\n");

    while (1)
        tight_loop_contents();
}

问题原因

你启用了UART的TX中断(uart_set_irq_enables(UART_ID, false, true)的第二个参数为true),但中断处理函数中没有清除对应的中断标志位。RP2040的UART中断触发后,必须手动清除中断状态,否则中断控制器会认为中断事件仍未处理,会持续触发中断,导致无限循环调用中断处理函数。

修复方案

在中断处理函数中,需要读取并清除UART的中断标志。可以直接清除所有已触发的UART中断,或者针对性清除TX相关的中断标志。

基础修复版本

// interrupt handler
void on_uart_interrupt() {
    // 清除当前UART的所有已触发中断标志
    uart_clear_interrupts(UART_ID);
    
    for( int i = 0; i < 8; ++i ) {
        gpio_put( D_GPIO_TEST, true ) ;
    }
    gpio_put( D_GPIO_TEST, false ) ;
}

精准处理版本(可选)

如果你只想清除TX相关的中断,可以先读取中断状态,再针对性清除:

// interrupt handler
void on_uart_interrupt() {
    uint32_t ints = uart_get_interrupt_status(UART_ID);
    
    // 检查是否是TX FIFO空中断触发
    if (ints & UART_IRQ_TX) {
        // 清除TX中断标志
        uart_clear_interrupt_status(UART_ID, UART_IRQ_TX);
    }
    
    for( int i = 0; i < 8; ++i ) {
        gpio_put( D_GPIO_TEST, true ) ;
    }
    gpio_put( D_GPIO_TEST, false ) ;
}

额外说明

如果你的需求是在TX发送完成后触发一次中断(而非TX FIFO空时触发),可以调整UART的中断触发条件,启用UART_TX_DONE_IRQ(发送完成中断),但需注意对应的配置和标志清除逻辑。

内容的提问来源于stack exchange,提问作者teach me

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 14:33:18