Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / IoT / Arduino

HashMaps - Associative Arrays with the Arduino Programming Language

3.33/5 (7 votes)
31 Jan 2016CPOL4 min read 59.5K   913  
Simplifies your programs through the use of HashMaps and other data structures with the Arduino programming language

Introduction

When it comes to computer programming (or microcontrollers), the choice of the data structure can turn a complicated problem in a simple solution or VICE VERSA!

The Arduino platform provides in its API a set of composite data types that can be used by the programmer like, for example: Arrays, Strings, Structs, etc. However, sometimes these structures are not enough to solve certain types of problems, then we need seek solutions in external libraries.

In this tip, we demonstrate the use of a well-known data structure between PHP programmers: The Associative arrays, also known as HashMaps or dictionaries. We will see how they can make our lives easier.

Before that, let us remember some basic types of structured data from the Arduino platform ...

Arrays

Arrays or Vectors are data structures that represent a set of variables with the same name, individually identified by an numerical index.

In the Arduino programming language, the arrays have the following characteristics:

  • All elements must have the same type.
  • The number of elements is immutable.
  • The index is a sequential number that starts at 0 (zero) and goes to (N-1), where N is the number of array elements.

Therefore, to declare an array, we need to inform 3 things:

  1. The array name
  2. The maximum number of elements it will contain
  3. The data type of the elements

For example, in the following statement, we're creating an array with three integer elements:

C++
mypin int [] = {2, 4, 8};

Where mypin [0] = 2, mypin [1] = 4, mypin [2] = 8.

Strings

A String in the Arduino language is a class that represents a set of characters and provides various methods for manipulating texts.
Each character of the String can be accessed by a numeric index that starts at 0 (zero) and goes to (N-1), where N is the size of String.

Example: The following command creates a String of seven characters with the value "Arduino":

C++
Board String = "Arduino";

Where:

C++
board.length() = 7 → The size of String
board.indexOf(0) = "A" → First Letter String
board.indexOf ("i") = 4 → Position of the letter "i" in the String
board.toUpperCase () = "ARDUINO" → Turns the letters to upper case

Associative Arrays

It is a type of array where the elements are formed by a key and a value (key-value pairs) in which each key has an associated value. This key can take on any value, including Strings. The keys are user-defined and stored in the structure. The relationship between the keys and their values is called mapping. Therefore, to find a value, the key is used like search index.

The main advantage in using associative arrays is the ease of performing searches for values, which is more intuitive.

There are some HashMaps implementations that can be used with the Arduino. We highlight the following frameworks:

  • Wiring - An open-source programming framework for microcontrollers
  • STL - The Standard Template Library

In this tip, we'll give examples in the Wiring platform that includes an implementation of HashMaps developed by Alexander Brevig. You'll need to "import" the countable.h and hashmap.h files for the libraries folder of Arduino.

Here's an example where we create an associative array with three integer elements with keys of type String and associated values of integer type:

C++
CreateHashMap (mypin, char *, int, 3);
mypin ["Sensor"] = 2;
mypin ["Led"] = 4;
Mypin ["Buzzer"] = 8;

Notice that, in this example, the associating of the key "Sensor" to the value 2. The advantage of this implementation is that we can identify the first element by your key "Sensor" or by its index which is 0 (zero).

To better understand these concepts, we'll develop a simple project and solve it in three different ways:

  1. No Data Structures
  2. Using Arrays and Strings
  3. Using Associative Arrays

Case Study

Our project consists of 3 colored LEDs connected to pins 5, 7, 9 and 11 of Arduino, as shown below:

Arduino 4 leds

The application will read a String through the Arduino serial port in an infinite loop. For each value read, the following action is taken:

  • If reading = "red" → Red LED Lighting
  • If reading = "yellow" → Yellow LED Lighting
  • If reading = "green" → Green LED Lighting
  • If reading = "blue" → Blue LED Lighting

Sketches

Solution One: No Data Structures

C++
/* Arduino & 4 leds
 * Solution 1: Without Data Structures
 * 2016, by José Cintra
 * http://www.josecintra.com/blog
 */

String reading = "";
int redPin = 5;
int greenPin = 7;
int bluePin = 9;
int yellowPin = 11;

void setup() {
  Serial.begin(9600);
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
}

void loop() {
  reading = readSerial(); //Reads value from serial
  ledsOff(); // Turn off all leds
  if (reading == "red") {
    digitalWrite(redPin,HIGH);
  }
  else if (reading == "green") {
    digitalWrite(greenPin,HIGH);
  }
  else if (reading == "blue"){
    digitalWrite(bluePin,HIGH);
  }
  else if (reading == "yellow"){
    digitalWrite(yellowPin,HIGH);
  }
}

//Read String from Serial
String readSerial() {
  String retVal = "";
  char c;
  while(!Serial.available()){ //Wait for serial input
    delay(10);
  }
  while(Serial.available() > 0) { //Read the serial input
    c = Serial.read();
    if (c != '\n'){
      retVal.concat(c);
    }
    delay(10);
  }
  retVal.toLowerCase(); //Convert to lower case
  return retVal;
}  

//Turn off all leds
void ledsOff(){
  digitalWrite(redPin,LOW);
  digitalWrite(greenPin,LOW);
  digitalWrite(bluePin,LOW);
  digitalWrite(yellowPin,LOW);
}

Solution Two: With Arrays and Strings

C++
/* Arduino & 4 leds
 * Solution 2: With Arrays & Strings
 * 2016, by José Cintra
 * http://www.josecintra.com/blog
 */
String reading = "";
int pins[] = {5,7,9,11};
String commands = "red       green     blue      yellow    ";

void setup() {
  Serial.begin(9600);
  for(int i = 0; i < 4; i++){
    pinMode(pins[i], OUTPUT);
  }
}

void loop() {
  reading = readSerial(); //Read value from serial
  ledsOff(); // Turn off all leds
  int i = commands.indexOf(reading);
  if (i >= 0) {  
    digitalWrite(pins[(i / 10)],HIGH);
  }
}

//Read String from Serial
String readSerial() {
  String retVal = "";
  char c;
  while(!Serial.available()){ //Wait for serial input
    delay(10);
  }
  while(Serial.available() > 0) { //Read the serial input
    c = Serial.read();
    if (c != '\n'){
      retVal.concat(c);
    }
    delay(10);
  }
  retVal.toLowerCase(); //Convert to lower case
  return (retVal);
}  

//Turn off all leds
void ledsOff(){
  for(int i = 0; i < 4; i++){
    digitalWrite(pins[i],LOW);
  }
}

Solution Three: With Associative Arrays

C++
/* Arduino & 4 leds
 * Solution 3: With HashMaps
 * 2016, by José Cintra
 * http://www.josecintra.com/blog
 */
#include <HashMap.h>
String reading = "";
CreateHashMap(ledPins, String, int, 4);

void setup() {
  Serial.begin(9600);  
  ledPins["red"] = 5;
  ledPins["green"] = 7;
  ledPins["blue"] = 9;
  ledPins["yellow"] = 11;
  for (int i = 0; i < ledPins.size(); i++){
    pinMode(ledPins.valueAt(i), OUTPUT);
  }  
}

void loop() {
  reading = readSerial();
  ledsOff();
  if(ledPins.contains(reading)){
    digitalWrite(ledPins[reading],HIGH);
  }
}

//Read String from Serial
String readSerial() {
  String retVal = "";
  char c;
  while(!Serial.available()){ //Wait for serial input
    delay(10);
  }
  while(Serial.available() > 0) { //Read the serial input
    c = Serial.read();
    if (c != '\n'){
      retVal.concat(c);
    }
    delay(10);
  }
  retVal.toLowerCase(); //Convert to lower case
  return retVal;
}  

//Turn off all leds
void ledsOff(){
  for (int i = 0; i < ledPins.size(); i++){
    pinMode(ledPins.valueAt(i), LOW);
  }  
}

Points of Interest

  • The readSerial function will wait and read a String value through the serial port.
  • The ledsOFF function serves to turn off all the LEDs before lighting the LED requested by serial command.
  • Notice that, by comparing the loop function of the 3 solutions, the alternative using associative arrays is much more readable, compact and maintainable.
  • The Alternative 2 with arrays and Strings has the advantage of not needing to use any external libraries.

Resources

Conclusion

In this tip, we try to show that the choice of appropriate data structures can result in more intuitive and compact programs, facilitating the work of the programmer.

Thank you for reading. See you ...

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)