Arduino - 字符函数
Arduino - 字符与命令处理
Section titled “Arduino - 字符与命令处理”您的 Arduino 经常需要处理基于文本的数据,无论是来自串口监视器的命令、SD 卡中的配置文件,还是网络请求中的参数。标准 C++ 库 <cctype>(默认已包含)提供了一组高效的函数,用于分类和转换单个字符(char)。
尽管 Arduino 的 String 对象提供了更强大的字符串操作功能,但这些底层函数速度极快且内存效率高,非常适合资源受限的微控制器。
关键字符函数
Section titled “关键字符函数”这些函数接受一个字符(作为 int 类型)并返回 true(非零值)或 false(零)。
字符类型检查
Section titled “字符类型检查”isDigit(c):它是一个数字字符(‘0’-‘9’)吗?isAlpha(c):它是一个字母字符(‘a’-‘z’, ‘A’-‘Z’)吗?isAlphaNumeric(c):它是一个数字或字母吗?isSpace(c):它是一个空白字符(空格、制表符\t、换行符\n等)吗?isPunct(c):它是一个标点符号吗?isUpperCase(c):它是一个大写字母吗?isLowerCase(c):它是一个小写字母吗?
字符大小写转换
Section titled “字符大小写转换”toUpperCase(c):将字符转换为其大写形式。toLowerCase(c):将字符转换为其小写形式。
实践示例:一个简单的串口命令解析器
Section titled “实践示例:一个简单的串口命令解析器”让我们构建一个健壮的命令解析器。我们的 Arduino 将通过串口监视器监听命令。这是一种常见的调试、配置和控制模式。
我们的命令将是:
L1:打开 LEDL0:关闭 LEDB<值>:设置闪烁延迟为<值>毫秒(例如B500)
constexpr int LED_PIN = 13;int blinkDelay = 500; // 默认闪烁延迟
void setup() { pinMode(LED_PIN, OUTPUT); Serial.begin(9600); printInstructions();}
void loop() { // 检查是否收到任何数据 if (Serial.available() > 0) { // 读取第一个字符(命令) char command = Serial.read(); command = toUpperCase(command); // 使命令不区分大小写
if (command == 'L') { parseLedCommand(); } else if (command == 'B') { parseBlinkCommand(); } else { // 清除缓冲区中所有剩余的垃圾数据 while(Serial.available() > 0) Serial.read(); Serial.println("错误:未知命令。"); printInstructions(); } }}
void parseLedCommand() { // 稍等片刻,等待下一个字符到来 delay(5); if (Serial.available() > 0) { char value = Serial.read(); if (value == '1') { digitalWrite(LED_PIN, HIGH); Serial.println("OK: LED 已开启"); } else if (value == '0') { digitalWrite(LED_PIN, LOW); Serial.println("OK: LED 已关闭"); } else { Serial.println("错误:L 的值无效。请使用 L1 或 L0。"); } }}
void parseBlinkCommand() { delay(5); // 为简单起见,使用 parseInt(),它内部会检查数字。 // 这是一个常见的 Arduino 辅助函数。 long value = Serial.parseInt();
if (value > 0) { blinkDelay = value; Serial.print("OK: 闪烁延迟设置为 "); Serial.print(blinkDelay); Serial.println(" 毫秒。"); // 使用 isDigit() 手动解析的示例 // String numberStr = ""; // while(Serial.available() > 0) { // char c = Serial.peek(); // peek() 只是查看而不移除 // if (isDigit(c)) { // numberStr += Serial.read(); // } else { // break; // 如果不是数字则停止 // } // } // if (numberStr.length() > 0) { // blinkDelay = numberStr.toInt(); // ... // } } else { Serial.println("错误:闪烁延迟值无效或为零。"); }}
void printInstructions() { Serial.println("\n--- 命令菜单 ---"); Serial.println("L1 : 打开 LED"); Serial.println("L0 : 关闭 LED"); Serial.println("B<ms> : 设置闪烁延迟(例如 B250)"); Serial.println("--------------------\n");}常见陷阱与最佳实践
Section titled “常见陷阱与最佳实践”- 阻塞与非阻塞:
Serial.read()是非阻塞的,它会立即返回。Serial.parseInt()是阻塞的,它会等待超时。在设计代码时请注意这种区别。 - 缓冲区处理:串口缓冲区很小(大多数 Arduino 上为 64 字节)。即使接收到的数据无效,也要始终读取,以防止缓冲区溢出。
- 命令结束符:在更复杂的协议中,您需要一种方法来判断命令何时结束。一种常见技术是读取直到接收到换行符(
'\n'),这在您在串口监视器中按下 Enter 键时发送。