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

如何将旧版Arduino的C++中断代码移植到ESP8266和ESP32并修复编译报错

报错根源与修复方案

错误原因

原代码是为AVR架构Arduino开发板编写的,大量使用了AVR专属的底层特性,而ESP8266/ESP32为XTensa架构,完全不兼容这些特性,才会触发语法报错:

  • ISR()是AVR专用的中断服务函数定义宏,ESP核心无此定义
  • PCINT1_vect、PCMSK1、PCIFR、PCICR、PINC都是AVR专属的中断向量、端口寄存器
  • cli()、sei()是AVR的中断开关指令
  • Streaming.h是AVR平台常用的串口输出库,多数ESP核心未内置该库

具体修复步骤

1. 依赖替换

  • 移除Streaming.h引用,将Serial <<格式的输出改为标准Serial.print()/Serial.println()写法
  • 移除所有AVR寄存器操作代码,改用ESP Arduino核心兼容的API
  • 中断开关替换为通用的noInterrupts()/interrupts()函数,ESP核心已做架构兼容

2. 中断逻辑适配

ESP系列支持单个GPIO独立绑定中断,不需要统一处理端口电平变化,直接为每个RC输入引脚绑定边沿中断即可,适配后逻辑更简洁。

适配后可用的示例代码(兼容ESP8266/ESP32)

/*  rcTiming_ESP.ino 适配ESP8266/ESP32
 *  可自行修改RC_INPUTS数组为你实际使用的GPIO引脚
 */

// 定义4个RC输入引脚,可根据硬件修改
const uint8_t RC_INPUTS[] = {14, 12, 13, 15};
const uint8_t RC_CH_NUM = sizeof(RC_INPUTS)/sizeof(RC_INPUTS[0]);

volatile unsigned long rcRises[RC_CH_NUM]; // 上升沿时间
volatile unsigned long rcTimes[RC_CH_NUM]; // 脉冲长度
volatile unsigned int rcChange = 0; // 变化计数器

// 中断回调函数
void IRAM_ATTR rcInterruptHandler(void* arg) {
  uint8_t channel = (uint32_t)arg;
  unsigned long now = micros();
  if (digitalRead(RC_INPUTS[channel]) == HIGH) {
    // 上升沿,记录时间
    rcRises[channel] = now;
  } else {
    // 下降沿,计算脉冲宽度
    rcTimes[channel] = now - rcRises[channel];
    rcChange++;
  }
}

void setup_rcTiming() {
  for (uint8_t i = 0; i < RC_CH_NUM; i++) {
    pinMode(RC_INPUTS[i], INPUT);
    // 绑定边沿中断,传入通道号作为参数
    attachInterruptArg(digitalPinToInterrupt(RC_INPUTS[i]), rcInterruptHandler, (void*)i, CHANGE);
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("Starting RC Timing Test");
  setup_rcTiming();
}

void loop() {
  unsigned long rcT[RC_CH_NUM];
  unsigned int rcN;
  if (rcChange) {
    noInterrupts();
    rcN = rcChange;
    rcChange = 0;
    memcpy(rcT, (void*)rcTimes, sizeof(rcT));
    interrupts();

    Serial.print("t=");
    Serial.print(millis());
    Serial.print(" ");
    for (uint8_t i = 0; i < RC_CH_NUM; i++) {
      Serial.print(rcT[i]);
      Serial.print(" ");
    }
    Serial.println(rcN);
  }
}

代码说明

  • IRAM_ATTR是ESP专属的属性标记,保证中断函数运行在RAM中,避免Flash读取延迟导致的中断异常
  • 使用attachInterruptArg绑定中断,支持传入通道参数,不需要为每个通道单独写中断函数
  • 引脚定义可根据自己的硬件连接自由修改,只要是支持中断的GPIO即可

内容的提问来源于stack exchange,提问作者Luca Spuntoni

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 23:48:02