Skip to content

Arduino - Character Functions

Arduino - Processing Characters and Commands

Section titled “Arduino - Processing Characters and Commands”

Your Arduino often needs to process text-based data, whether it’s a command from the Serial Monitor, a configuration file from an SD card, or a parameter in a web request. The standard C++ library <cctype>, included by default, provides a set of highly efficient functions for classifying and converting individual characters (char).

While the Arduino String object offers more powerful string manipulation, these low-level functions are extremely fast and memory-efficient, making them perfect for resource-constrained microcontrollers.

These functions take a character (as an int) and return true (a non-zero value) or false (zero).

  • isDigit(c): Is it a digit (‘0’-‘9’)?
  • isAlpha(c): Is it an alphabetic letter (‘a’-‘z’, ‘A’-‘Z’)?
  • isAlphaNumeric(c): Is it a digit or a letter?
  • isSpace(c): Is it a whitespace character (space, tab \t, newline \n, etc.)?
  • isPunct(c): Is it a punctuation character?
  • isUpperCase(c): Is it an uppercase letter?
  • isLowerCase(c): Is it a lowercase letter?
  • toUpperCase(c): Converts a character to its uppercase equivalent.
  • toLowerCase(c): Converts a character to its lowercase equivalent.

Practical Example: A Simple Serial Command Parser

Section titled “Practical Example: A Simple Serial Command Parser”

Let’s build a robust command parser. Our Arduino will listen for commands via the Serial Monitor. This is a common pattern for debugging, configuration, and control.

Our commands will be:

  • L1: Turn LED ON
  • L0: Turn LED OFF
  • B<value>: Set blink delay to <value> milliseconds (e.g., B500)
constexpr int LED_PIN = 13;
int blinkDelay = 500; // Default blink delay
void setup() {
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
printInstructions();
}
void loop() {
// Check if any data has been received
if (Serial.available() > 0) {
// Read the first character (the command)
char command = Serial.read();
command = toUpperCase(command); // Make command case-insensitive
if (command == 'L') {
parseLedCommand();
} else if (command == 'B') {
parseBlinkCommand();
} else {
// Clear any remaining junk from the buffer
while(Serial.available() > 0) Serial.read();
Serial.println("Error: Unknown command.");
printInstructions();
}
}
}
void parseLedCommand() {
// Wait a tiny moment for the next character to arrive
delay(5);
if (Serial.available() > 0) {
char value = Serial.read();
if (value == '1') {
digitalWrite(LED_PIN, HIGH);
Serial.println("OK: LED is ON");
} else if (value == '0') {
digitalWrite(LED_PIN, LOW);
Serial.println("OK: LED is OFF");
} else {
Serial.println("Error: Invalid value for L. Use L1 or L0.");
}
}
}
void parseBlinkCommand() {
delay(5);
// Use parseInt() for simplicity, which internally checks for digits.
// This is a common Arduino helper function.
long value = Serial.parseInt();
if (value > 0) {
blinkDelay = value;
Serial.print("OK: Blink delay set to ");
Serial.print(blinkDelay);
Serial.println(" ms.");
// Example of a manual parse using isDigit()
// String numberStr = "";
// while(Serial.available() > 0) {
// char c = Serial.peek(); // peek() looks without removing
// if (isDigit(c)) {
// numberStr += Serial.read();
// } else {
// break; // Stop if it's not a digit
// }
// }
// if (numberStr.length() > 0) {
// blinkDelay = numberStr.toInt();
// ...
// }
} else {
Serial.println("Error: Invalid or zero value for Blink.");
}
}
void printInstructions() {
Serial.println("\n--- Command Menu ---");
Serial.println("L1 : Turn LED ON");
Serial.println("L0 : Turn LED OFF");
Serial.println("B<ms> : Set blink delay (e.g., B250)");
Serial.println("--------------------\n");
}
  • Blocking vs. Non-Blocking: Serial.read() is non-blocking; it returns immediately. Serial.parseInt() is blocking; it waits for a timeout. Be aware of this difference when designing your code.
  • Buffer Handling: The serial buffer is small (64 bytes on most Arduinos). Always read data you receive, even if it’s invalid, to prevent the buffer from overflowing.
  • End-of-Command: In more complex protocols, you need a way to know when a command is finished. A common technique is to read until you receive a newline character ('\n'), which is sent when you press Enter in the Serial Monitor.