- 什么是函数? (核心概念)
- C 语言标准函数结构 (语法详解)
- Arduino 中的函数 (结合硬件实例)
- 函数进阶:
setup()和loop()(Arduino 的特殊函数) - 最佳实践与总结
什么是函数?
你可以把函数想象成一个“工具箱”里的小工具,你有一个“拧螺丝”的工具(函数),每次你需要拧螺丝时,你不需要重新造一个,只需要直接拿起这个工具,用它去拧就行了。

(图片来源网络,侵删)
在编程中,函数就是一段可以重复使用的代码块,它接收一些输入(称为参数),执行特定的任务,然后可以返回一个结果(称为返回值)。
使用函数的好处:
- 代码复用:避免重复编写相同的代码。
- 模块化:将一个大程序分解成许多小而独立的模块,使代码结构更清晰。
- 易于维护:如果需要修改功能,只需修改函数内部的代码,所有调用它的地方都会自动更新。
- 隐藏细节:调用者不需要知道函数内部是如何工作的,只需要知道如何使用它即可。
C 语言标准函数结构
一个标准的 C 语言函数由以下几个部分组成:
返回类型 函数名(参数列表) {
// 函数体 (具体的代码逻辑)
return 返回值; // 如果返回类型不是 void,则需要 return
}
让我们来分解一下:

(图片来源网络,侵删)
a. 返回类型
- 指定了函数执行完毕后返回给调用者的数据的类型。
- 可以是
int,float,char,double等基本数据类型。 - 如果函数不需要返回任何值,则使用
void关键字。 - 如果函数不需要参数,参数列表可以写成
void或者直接留空(在 C99 标准及以后,直接留空更常见)。
b. 函数名
- 给函数起一个有意义的名字,方便调用,遵循 C 语言的命名规则(通常使用小写字母,多个单词用下划线
_分隔)。
c. 参数列表
- 指定了函数在执行时需要接收的输入数据。
- 参数由
数据类型 参数名的形式组成,多个参数之间用逗号 分隔。 int a, float b。
d. 函数体
- 用花括号 括起来的部分,是函数真正执行的代码。
e. return 语句
- 用于从函数中返回一个值,并立即终止函数的执行。
return后面跟着的值类型必须与函数的返回类型匹配。- 如果返回类型是
void,可以写return;来提前结束函数,或者省略return。
Arduino 中的函数
Arduino 的编程语言本质上是 C++,但它完全兼容 C 语言的函数,在 Arduino 中,你既可以使用自己定义的函数,也可以大量使用 Arduino 提供的库函数(如 pinMode(), digitalWrite() 等)。
下面我们通过几个 Arduino 的例子来理解函数。
示例 1:无参数、无返回值的函数
这是最简单的函数,通常用于执行一系列固定的操作。
任务:让一个连接在引脚 13 的 LED 闪烁 5 次。

(图片来源网络,侵删)
// 定义一个名为 blinkLED 的函数
// void 表示没有返回值
// () 表示没有参数
void blinkLED() {
int ledPin = 13; // 定义 LED 引脚
for (int i = 0; i < 5; i++) { // 循环 5 次
digitalWrite(ledPin, HIGH); // 点亮 LED
delay(500); // 延时 500ms
digitalWrite(ledPin, LOW); // 熄灭 LED
delay(500); // 延时 500ms
}
}
void setup() {
pinMode(13, OUTPUT); // 将引脚 13 设置为输出模式
}
void loop() {
blinkLED(); // 调用 blinkLED 函数
delay(2000); // 主循环暂停 2 秒
}
代码解析:
void blinkLED() { ... }:我们定义了一个名为blinkLED的函数,它不接收任何输入,也不返回任何值。void setup() { ... }:Arduino 上电或复位后,setup()函数会自动运行一次,我们在这里配置引脚模式。void loop() { ... }:loop()函数会不断地、循环地执行,每次循环,我们调用blinkLED()函数,让 LED 闪烁 5 次,然后暂停 2 秒。
示例 2:带参数、无返回值的函数
让函数更灵活,可以接收不同的输入来执行相似的任务。
任务:创建一个函数,可以控制任意引脚上的 LED 闪烁指定的次数。
// 定义一个带参数的函数
// void 表示没有返回值
// (int pin, int times) 表示接收两个整数参数:引脚号和闪烁次数
void blinkNTimes(int pin, int times) {
for (int i = 0; i < times; i++) {
digitalWrite(pin, HIGH);
delay(250);
digitalWrite(pin, LOW);
delay(250);
}
}
void setup() {
// 可以配置多个引脚
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop() {
// 调用函数,控制引脚 13 的 LED 闪烁 3 次
blinkNTimes(13, 3);
delay(1000);
// 调用函数,控制引脚 12 的 LED 闪烁 5 次
blinkNTimes(12, 5);
delay(1000);
}
代码解析:
void blinkNTimes(int pin, int times) { ... }:这个函数非常灵活。int pin:接收一个整数,代表要操作的引脚。int times:接收一个整数,代表闪烁的次数。
blinkNTimes(13, 3):我们调用这个函数,传入参数13和3,函数内部就会操作引脚 13 闪烁 3 次。blinkNTimes(12, 5):再次调用,传入不同的参数12和5,实现了代码的复用。
示例 3:带参数、有返回值的函数
函数不仅执行操作,还可以像一个计算器一样,返回一个计算结果。
任务:创建一个函数,读取一个模拟传感器的值,并将其转换成 0-100 的百分比。
// 定义一个有返回值的函数
// int 表示函数将返回一个整数
// (int sensorPin, int maxVal) 接收传感器引脚和最大可能值作为参数
int getSensorPercentage(int sensorPin, int maxVal) {
// 1. 读取模拟引脚的值 (0-1023)
int sensorValue = analogRead(sensorPin);
// 2. 将原始值映射到 0-100 的范围
// map(value, fromLow, fromHigh, toLow, toHigh)
int percentage = map(sensorValue, 0, maxVal, 0, 100);
// 3. 返回计算后的百分比
return percentage;
}
void setup() {
Serial.begin(9600); // 初始化串口通信,波特率为 9600
}
void loop() {
// 假设我们连接了一个电位器到 A0 引脚
int potPin = A0;
int maxAnalogValue = 1023; // Arduino 模拟输入的最大值
// 调用函数,获取传感器百分比
int sensorPercent = getSensorPercentage(potPin, maxAnalogValue);
// 通过串口监视器打印结果
Serial.print("Sensor Value: ");
Serial.print(sensorPercent);
Serial.println("%");
delay(500); // 每半秒更新一次
}
代码解析:
int getSensorPercentage(...) { ... }:这个函数的返回类型是int。int sensorValue = analogRead(sensorPin);:读取传感器原始值。int percentage = map(...);:使用 Arduino 的map()函数进行数值转换。return percentage;:这是关键!函数将计算好的percentage值返回给调用者。int sensorPercent = getSensorPercentage(...);:在loop()中,我们调用这个函数,并用一个int类型的变量sensorPercent来接收它返回的值。
函数进阶:setup() 和 loop()
setup() 和 loop() 是 Arduino 程序中两个最特殊的函数,它们由 Arduino 的核心框架自动调用。
-
void setup(): 初始化函数。- 在程序开始时只运行一次。
- 通常用来配置引脚模式(
pinMode)、启动串口(Serial.begin)、初始化传感器等。 - 它没有返回值,也没有参数。
-
void loop(): 主循环函数。- 在
setup()执行完毕后,它会无休止地、反复地运行。 - 你的主要逻辑代码都写在这里。
- 它也没有返回值和参数。
- 在
你可以把整个 Arduino 程序想象成一个永动机:
- 上电 -> 执行一次
setup()(准备工作) - -> 开始执行
loop()(干活) - ->
loop()执行到结尾 -> 立刻回到开头,再次执行loop()(继续干活) - -> ... 永远循环下去。
最佳实践与总结
- 函数命名要清晰:函数名应该清楚地表达它的功能,
calculateDistance()比func1()好得多。 - 一个函数只做一件事:遵循“单一职责原则”,让函数尽量短小精悍,易于理解和测试。
- 善用注释:在函数上方添加注释,说明函数的功能、参数的含义和返回值的类型。
- 先声明,后定义:对于复杂的项目,通常会在文件开头(
.h文件或.ino文件顶部)声明函数(即函数原型),然后再在后面定义它,这可以解决函数调用顺序的问题。
函数声明示例:
// 函数声明(函数原型)
void blinkNTimes(int pin, int times);
int getSensorPercentage(int sensorPin, int maxVal);
void setup() {
// ...
}
// 函数定义
void blinkNTimes(int pin, int times) {
// ... (函数体)
}
int getSensorPercentage(int sensorPin, int maxVal) {
// ... (函数体)
return ...;
}
void loop() {
// 即使函数定义在 loop() 之后,因为已经声明,这里也可以正常调用
blinkNTimes(13, 5);
}
掌握了函数,你就掌握了编程中“模块化”和“代码复用”的精髓,这是从一个新手走向专业开发者的关键一步,在 Arduino 中,合理地使用函数能让你的项目结构更清晰,代码更健壮。
