Arduino/ESP32 项目重构:从单文件到多文件架构及多版本管理

在开发 Arduino 项目(尤其是 ESP32)时,随着功能增加,单文件 .ino 会变得臃肿且难以维护。将代码拆分为多个 .h 和 .cpp 文件,不仅可以提高代码可读性,还能实现模块复用,便于多版本管理。本文以一个 100us 定时翻转 LED 的简单示例,详细讲解如何将单文件项目重构为标准的多文件架构,并介绍在 Arduino IDE 2.x 中高效管理多版本项目的方法。


一、原始单文件代码分析

假设我们有以下单文件 main.ino,实现了一个 100 微秒的定时任务,每 10000 次(即 1 秒)翻转一次 LED(引脚 17):

bool task100usFlag = false;
unsigned long prevUsCnt = 0;
const unsigned long interval = 100;  // 100us

const int ledPin = 17;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  unsigned long now = micros();
  if (now - prevUsCnt >= interval) {
    prevUsCnt = now;
    task100usFlag = true;
  }

  if (task100usFlag) {
    task100usFlag = false;
    myFastTask();  // 100us 任务
  }
}

void myFastTask() {
  static uint16_t us100TimeCnt = 0;
  us100TimeCnt++;
  if (us100TimeCnt > 10000) {
    us100TimeCnt = 0;
    digitalWrite(ledPin, !digitalRead(ledPin));
  }
}

这段代码将所有变量和函数都堆在同一个文件中,虽然简单,但若后续添加更多任务(如传感器读取、通信处理),文件将迅速膨胀,且难以复用其中的定时任务模块。


二、多文件拆分步骤

2.1 分析模块边界

识别出可独立的功能模块。本例中,myFastTask 是一个独立的定时任务,它使用了 ledPin 和 us100TimeCnt。我们可以将这部分封装为一个模块,命名为 fast_task。

2.2 创建头文件(.h)

头文件用于声明模块的公共接口(函数、变量、常量),并添加头文件保护。

新建文件:fast_task.h

#ifndef FAST_TASK_H
#define FAST_TASK_H

#include <Arduino.h>  // 包含 Arduino 核心定义

void initFastTask();   // 初始化函数
void myFastTask();     // 任务函数

#endif

2.3 创建实现文件(.cpp)

实现文件包含模块的具体代码,并将内部变量声明为 static(文件作用域),避免与其它模块冲突。

新建文件:fast_task.cpp

#include "fast_task.h"

// 模块内部变量(静态,仅在当前文件可见)
static uint16_t us100TimeCnt = 0;
static const int ledPin = 17;

void initFastTask() {
  pinMode(ledPin, OUTPUT);
}

void myFastTask() {
  us100TimeCnt++;
  if (us100TimeCnt > 10000) {
    us100TimeCnt = 0;
    digitalWrite(ledPin, !digitalRead(ledPin));
  }
}

2.4 修改主文件(.ino)

主文件只保留调度逻辑,包含模块头文件并调用其函数。

main.ino

#include "fast_task.h"

bool task100usFlag = false;
unsigned long prevUsCnt = 0;
const unsigned long interval = 100;  // 100us

void setup() {
  initFastTask();  // 初始化模块
}

void loop() {
  unsigned long now = micros();
  if (now - prevUsCnt >= interval) {
    prevUsCnt = now;
    task100usFlag = true;
  }

  if (task100usFlag) {
    task100usFlag = false;
    myFastTask();  // 执行模块任务
  }

  // 其他非实时任务...
}

2.5 编译与验证

将三个文件放在同一项目文件夹中(例如 MyProject/),在 Arduino IDE 中打开 .ino 文件,点击编译。若一切正常,程序功能应与原单文件一致。

文章在这个系列:ESP32_今天长脑子了吗的博客-CSDN博客

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐