HOWTO · Arduino
Arduino 等待输入
可以使用 Serial.available()函数和 digitalRead()函数将 Arduino 设置为等待输入。
本页内容
请根据信号类型选择输入方式:电脑或其他设备发送的字节使用串口输入;按钮等只有开、关两种状态的引脚使用 digitalRead();需要将传感器读数与阈值比较时使用 analogRead()。下方的 Arduino 草图使用标准 Arduino API。配套的可移植 C++ 测试程序以确定性的模拟值代替板载硬件,因此无需 Arduino 板也能编译并了解输入处理逻辑;它们不会测试电气行为。
选择输入来源:串口、数字输入或模拟输入
主机通过 USB 或 UART 连接发送字符或命令时,使用串口。信号只有两种状态时,使用数字引脚。传感器输出变化的电压,且你需要对其采样并进行比较时,使用模拟输入。请根据开发板和传感器选择输入引脚及电气连接方式;示例中按钮接在引脚 2,模拟传感器接在 A0。
使用 Serial.available() 等待串口数据
Serial.available() 会报告接收缓冲区中有多少字节正在等待。调用 Serial.read() 前先检查这个值,避免草图在没有可读字节时读取数据。此示例每次读取并回显一个字节,适用于简单的字符命令。它不会组装完整的一行;若要处理按行发送的命令,请收集字节直到遇到换行符,并明确处理行结束符。
运行这个可移植测试程序,可以了解逐字节处理的模式。在 Arduino 草图中,保留 setup() 和 loop(),并用开发板的 Serial 对象替换此处的小型模拟对象。
#include <iostream>
class SerialPort {
public:
void begin(int) {}
int available() const { return next_ < 1; }
int read() { ++next_; return 65; }
void print(const char* text) { std::cout << text; }
void println(int value) { std::cout << value << '\n'; }
private:
int next_ = 0;
};
SerialPort Serial;
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
int incomingByte = Serial.read();
Serial.print("Received byte: ");
Serial.println(incomingByte);
}
}
int main() {
setup();
loop();
}
Received byte: 65
将串口监视器或发送设备设为相同的波特率。由于 Serial.read() 返回的是整数形式的字节值,此示例会打印一份带标签的数值字节报告:标签 Received byte: 后跟该字节的数值;如果要打印字符本身,请将其转换为 char。
使用 digitalRead() 等待数字输入
数字输入从引脚读取,而不是从串口读取。若按钮连接在引脚 2 和地之间,请配置 INPUT_PULLUP:按钮未按下时读数为 HIGH,按下时读数为 LOW。下方的循环会先等待按钮按下,再等待按钮释放。等待任一状态时,这种轮询都会暂停 loop() 中的其他工作。
这个可移植测试程序会向相同的等待逻辑提供一系列引脚状态。在 Arduino 草图中,请将模拟函数替换为开发板的 pinMode() 和 digitalRead() API。
#include <iostream>
const int INPUT_PULLUP = 2;
const int HIGH = 1;
const int LOW = 0;
const int buttonPin = 2;
int pinStates[] = {HIGH, LOW, LOW, HIGH};
int stateIndex = 0;
void pinMode(int, int) {}
int digitalRead(int) { return pinStates[stateIndex++]; }
class SerialPort {
public:
void begin(int) {}
void println(const char* text) { std::cout << text << '\n'; }
};
SerialPort Serial;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
while (digitalRead(buttonPin) == HIGH) {
}
Serial.println("Button pressed");
while (digitalRead(buttonPin) == LOW) {
}
}
int main() {
setup();
loop();
}
Button pressed
按钮断开时,内部上拉电阻会让输入保持在确定的电平。如果你的电路将按钮接到正电源,并使用外部下拉电阻,则应使用 INPUT,并在按下时检查 HIGH。代码中的有效电平必须与电路一致,才能避免输入悬空或响应极性相反。
使用 analogRead() 等待模拟阈值
analogRead() 会对模拟引脚上的电压采样,并返回一个数值读数。请根据传感器和开发板选择阈值,再将读数与之比较。如果第一次执行时读数已经高于阈值,此草图会立即报告;此后每次报告后,都会等待后续读数降至阈值或以下,才可能再次报告。
这个可移植测试程序会提供两个读数:第一个高于阈值,第二个等于或低于阈值。在开发板上,Arduino 核心库提供 A0 和 analogRead();可用引脚及读数范围取决于开发板。
#include <iostream>
const int A0 = 0;
const int sensorPin = A0;
const int threshold = 500;
int readings[] = {600, 450};
int readingIndex = 0;
int analogRead(int) { return readings[readingIndex++]; }
class SerialPort {
public:
void begin(int) {}
void println(const char* text) { std::cout << text << '\n'; }
};
SerialPort Serial;
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(sensorPin);
if (sensorValue > threshold) {
Serial.println("Threshold exceeded");
while (analogRead(sensorPin) > threshold) {
}
}
}
int main() {
setup();
loop();
}
Threshold exceeded
analogRead() 对应的数值范围和电压取决于开发板。请查阅开发板文档,并根据传感器读数校准 threshold。这里进行的是反复采样和比较,而不是等待串口字节。
避免阻塞草图的其他工作
紧密轮询的 while 循环会持续检查输入,但在条件改变前,loop() 中其余代码都不会运行。如果草图此时就该停下来,这种做法很有用;但它也会延迟更新显示内容或检查其他输入等任务。若草图需要继续处理其他工作,请改为每轮检查一次输入并记录状态,而不是在循环中等待。例如,使用 if (Serial.available() > 0) 处理当前可用的字节,然后继续执行 loop() 的其余部分。
如果草图看起来没有响应,请检查所选引脚是否与接线一致、数字输入是否有确定的电平、串口发送端是否使用了相同的波特率,以及模拟阈值是否符合开发板的读数范围。阻塞式等待也只有在被检查的状态发生变化后才会结束。