我在void setup()
和 void loop()
之外的其他示例经常见到很多编程有void controlLED()等,那么这些其他“void”如何使用呢
在 Arduino 编程中,除了 void setup()
和 void loop()
这两个核心函数外,你还可以自定义任意数量的 void
函数。这些自定义函数用于模块化代码,提高可读性和复用性。以下是详细规则和添加方法:
cpp
// 自定义函数声明(可选) void myFunction(); // 自定义函数定义 void myFunction() { // 你的代码 }
自定义函数可以放在 setup()
和 loop()
之后(推荐),也可以放在之前。
推荐结构:
cpp
void setup() { /* 初始化代码 */ } void loop() { /* 主循环代码 */ } // 自定义函数放在 setup/loop 之后 void myFunction1() { /* 代码 */ } void myFunction2() { /* 代码 */ }
如果自定义函数定义在 setup()/loop()
之后,需在文件顶部添加函数声明(避免编译错误):
cpp
// 函数声明(告诉编译器函数的存在) void myFunction(); // 结尾带分号 void setup() { myFunction(); // 正确:声明后可在定义前调用 } void loop() {} // 函数定义 void myFunction() { // 实际代码 }
在 setup()
、loop()
或其他函数内直接调用:
cpp
void setup() { myFunction(); // 初始化时调用 } void loop() { myFunction(); // 循环中重复调用 delay(1000); }
无返回值:void
函数不返回任何值,仅执行操作(如控制引脚、打印数据等)。
cpp
// 声明自定义函数 void blinkLED(int times, int duration); void setup() { pinMode(LED_BUILTIN, OUTPUT); blinkLED(3, 500); // 启动时闪烁3次 } void loop() { blinkLED(1, 1000); // 每秒闪烁1次 } // 定义自定义函数(放在setup/loop后) void blinkLED(int times, int duration) { for (int i = 0; i < times; i++) { digitalWrite(LED_BUILTIN, HIGH); delay(duration); digitalWrite(LED_BUILTIN, LOW); delay(duration); } }
规则项 | 说明 |
---|---|
自定义函数位置 | 可放在 setup()/loop() 之后(推荐)或之前 |
函数声明 | 若定义在调用之后,必须在顶部声明(如 void myFunc(); ) |
无返回值 | void 函数不返回数据 |
命名规则 | 不能与关键字冲突(如 setup , loop , digitalWrite ) |
作用域 | 函数内定义的变量是局部的(除非使用全局变量) |
通过自定义 void
函数,你可以将复杂逻辑拆分成模块,使代码更清晰。只需遵循声明/定义的位置规则,即可灵活扩展 Arduino 程序的功能。
loop()
里不行吗?可以把所有代码都写在 loop()
里,但这会导致严重的代码维护问题。以下是自定义函数的 核心价值 和直接写在 loop()
中的 弊端:
优势 | 说明 | 示例对比 |
---|---|---|
代码复用 | 避免重复代码,一处定义多处调用 | 需要闪烁LED时,只需 blink(3) 而不是重写整个闪烁逻辑 |
模块化 | 将复杂系统拆分成独立功能块 | 将「传感器读取」「数据处理」「电机控制」拆分成独立函数 |
可读性 | 函数名即注释,逻辑一目了然 | calculateTemperature() 比一堆数学公式更易理解 |
调试效率 | 可单独测试特定功能模块 | 只需调试 readSensor() 函数而非整个 loop() |
维护性 | 修改逻辑只需调整一个函数 | 修改LED引脚时只需改 blink() 函数,而非搜索替换整个代码 |
loop()
中的弊端cpp
// ❌ 糟糕实践:所有代码堆砌在loop中 void loop() { // 代码块1: 读取传感器 int raw = analogRead(A0); float temp = (raw * 0.488) - 50; Serial.print(temp); // 代码块2: 控制LED if (temp > 30) { for(int i=0; i<5; i++) { digitalWrite(13,HIGH); delay(200); digitalWrite(13,LOW); delay(200); } } // 代码块3: 电机控制(混杂在温度逻辑中) int speed = map(analogRead(A1), 0, 1023, 0, 255); analogWrite(5, speed); }
问题分析:
代码臃肿:300+行后难以定位关键逻辑
重复劳动:相同功能(如LED闪烁)需多次复制粘贴
牵一发而动全身:修改LED逻辑需搜索替换所有相关片段
调试地狱:无法单独测试传感器读取功能
可读性差:新人难以理解代码意图
cpp
// ✅ 清晰的主循环 void loop() { float temp = readTemperature(); // 调用传感器函数 controlLED(temp); // 调用LED控制函数 controlMotor(); // 调用电机函数 } // 模块1: 温度读取 float readTemperature() { int raw = analogRead(A0); return (raw * 0.488) - 50; } // 模块2: LED控制(复用blink函数) void controlLED(float temp) { if (temp > 30) blink(13, 5, 200); } // 模块3: 电机控制 void controlMotor() { analogWrite(5, map(analogRead(A1), 0, 1023, 0, 255)); } // ✅ 复用核心功能:闪烁函数 void blink(int pin, int times, int dur) { for(int i=0; i
关键决策参考表
场景 推荐方案 原因 简单一次性脚本 直接写 loop()
代码量<50行时可行 重复功能 >2次 必须用自定义函数 避免复制粘贴错误 多人协作项目 强烈推荐模块化 便于分工开发 长期维护项目 函数化+文档注释 降低维护成本70%+ 经验法则:当你的
loop()
超过屏幕一屏(约30行),或发现相同代码出现两次,就该使用自定义函数了。通过自定义函数,你实际上是在构建自己的「代码乐高」—— 每个函数都是可复用的标准件,最终组合成强大而优雅的系统。