Skip to content

Arduino - 变量与常量

变量是程序可以操作的命名存储位置。在Arduino(和C++)中,每个变量都有一个特定的类型,它决定了变量内存的大小和布局、可以存储的值的范围以及可以对其应用的操作集。

选择正确的数据类型对于编写高效无误的代码至关重要。使用过小的数据类型会导致错误,而使用过大的则会浪费宝贵的内存。

类型大小 (在Uno/AVR上)范围典型用途
bool1 bytetrue or false存储状态(例如,按钮是否按下,LED是否亮起)
byte1 byte0 to 255处理原始字节数据,PWM值
int2 bytes-32,768 to 32,767通用整数运算,循环计数器
unsigned int2 bytes0 to 65,535不需要负数时使用
long4 bytes-2,147,483,648 to 2,147,483,647大整数值
unsigned long4 bytes0 to 4,294,967,295存储millis()的返回值
float4 bytes-3.4028235E+38 to 3.4028235E+38带小数点的数字(6-7位精度)
char1 byte-128 to 127存储单个字符(例如,‘A’)

注意: int和long的大小在不同的Arduino开发板上可能有所不同。在ESP32或Arduino Due等32位开发板上,int通常是4字节。请务必查阅您特定开发板的文档。

变量的作用域定义了它在程序中可以被访问的范围。理解作用域是组织代码和避免bug的关键。

局部变量在函数(如setup()或loop())或代码块(如for循环)内部声明。它们只能在该函数或代码块内访问。当函数被调用时它们被创建,当函数退出时它们被销毁。这是大多数变量的首选作用域。

全局变量在任何函数外部声明,通常位于草图(sketch)的顶部。它们可以在程序的任何函数中被访问和修改。尽管有用,但应谨慎使用,因为它们会使代码更难调试(一个函数中的bug可能会意外地改变另一个函数使用的全局变量)。

static变量是一种特殊的局部变量。它只在其函数内部可访问,但其值在函数调用之间是保留的。这是在不使用全局变量的情况下在函数内部维护状态的好方法。

// --- 全局变量 ---
// 在此文件的任何地方都可访问。
int globalCounter = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
// --- 局部变量 ---
// 'loopMessage' 在每次运行 loop() 时被创建和销毁。
String loopMessage = "Inside loop().";
Serial.println(loopMessage);
// 我们可以在这里访问和修改全局变量。
globalCounter++;
Serial.print("Global counter is now: ");
Serial.println(globalCounter);
// 调用我们的自定义函数
myFunction();
delay(1000);
Serial.println("----------");
}
void myFunction() {
// 此函数无法访问 loop() 中的 'loopMessage'。
// 尝试这样做会导致编译错误。
// Serial.println(loopMessage); // <-- 这将无法编译
// --- 静态局部变量 ---
// 'staticCounter' 只在第一次运行此函数时初始化一次。
// 它的值在对 myFunction() 的多次调用之间被记住。
static int staticCounter = 0;
staticCounter++;
Serial.print("myFunction() has been called ");
Serial.print(staticCounter);
Serial.println(" times.");
}

常量是定义后其值不能更改的变量。将常量用于引脚编号、传感器阈值或配置设置会使您的代码更具可读性且更易于维护。

使用 ‘const’ 关键字(最佳实践)

Section titled “使用 ‘const’ 关键字(最佳实践)”

创建常量的现代首选方式是使用const关键字。它告诉编译器该变量是只读的,并允许编译器执行优化。

const int ledPin = 13;
const float pi = 3.14159;
const long baudRate = 9600;
void setup() {
// 现在使用常量而不是“魔术数字”
pinMode(ledPin, OUTPUT);
Serial.begin(baudRate);
}
void loop() {
// ledPin = 12; // 这将导致编译错误,这是件好事!
}

使用 ‘#define’ 预处理指令(传统方式)

Section titled “使用 ‘#define’ 预处理指令(传统方式)”

您可能会看到一些旧代码使用#define来创建常量。这是一个预处理指令,在代码编译之前执行简单的文本替换。虽然它有效,但const通常更安全,因为它具有类型感知能力并遵守作用域规则。

// 传统方法
#define LED_PIN 13