week 05: Embedded programming

Summary

This week we got to know the Arduino Uno and wrote our first little program, which included serial communication, reading a button as input device and writing a LED as output device.

Theory

The board is equipped with rows of digital pins, where cables can be connected and the pinstatus can be set or read with digitalWrite() or digitalRead(). The ones marked with PWM can use the analogWrite(). On the opposite side there’s a row of analog input pins, that can read analog signals. There’s one LED that is hardwired to pin 13. And additionally one that indicates whether the board is powered and two that are showing whether data is transmitted over serial. The USB port is used to connect the Arduino to the computer and upload programs and communicate via serial.

PinModes can be set to INPUT, OUTPUT or INPUT/_PULLUP, which kind of reverses the INPUT mode. The parameters for digital or analog are digitalWrite(pinnumber, HIGH|LOW) and analogWrite(pinnumber, value), whereas value is between 0 and 255 and simulates an analog signal.

The Memory is rather small: 32KB flash memory and 2KB RAM. So if the program would get a bit bigger and more complex, the space should be used efficiently.

The basic structure of an Arduino program always contains a setup() and a loop() function. The first one gets called when the Arduino is powered and the second one gets looped through afterwards over and over again. The known control structures (if/else, for, (do) while, switch case) can be used and further functions can be declared.

The Arduino also comes with a small IDE, equipped with the tools that are needed to upload code to the Arduino and to communicate via serial monitor. (but there’s also a nice VS Code extension to use with the Arduino :D) The code can be verified and uploaded via the top left icons or under sketch > Verify/Compile and skecth > Upload or The serial monitor can be accessed via the icon in the top right corner or under tools > Serial Monitor.

Arduino IDE
Arduino IDE

The Programming

I wanted to make a small game where the LED blinks a random amount of times and the player has to repeat it.
I will explain the codesnippets in the order I wrote them and in the end there will be the whole code to copy.

but first the setup
But first the setup

but first the setup
Pinnumbers

First the pin numbers the LED and the button connects to, has to be defined and set to the pinMode they should run on. Since the button is connected to ground it has to use a INPUT/_PULLUP. The setup function also has to contain the initializing of serial communication with a baud rate of 9600. To receive or send data via the serial monitor of the IDE, those baud rates have to match up.

const byte ledPin = 13; // hardwired LED on pin 13
const byte btnPin = 7;  // button on pin 7
boolean btnstatus;

void setup() {
  Serial.begin(9600); //set baud rate for serial data transmission
  pinMode(btnPin, INPUT_PULLUP); 
  pinMode(ledPin, OUTPUT);
}

At the beginning of the loop there’s only some text displayed to indicate the beginning of the game turn. After that the function quest() gets called..

void loop() {  
  // just feedback on the Serial Monitor
  Serial.println("Watch the LED!");
  delay(1500);
  Serial.println("ready!");
  delay(250);
  Serial.println("steady!");
  delay(250);
  Serial.println("go!");  

  int blinks = quest(); // quest() gets called, to flash the LED random times and get this number for later use

… where a random amount (1 to 5 times) of blinking is defined and the LED falshes accordingly. Blinks gets returned for later use.

int quest() {
  int blinks = random(1, 6);  // a random number between 1 and 5 gets created
  for(int i = 1; i <= blinks; i++) {  // the LED flashes for the earlier chosen random number
    digitalWrite(ledPin, HIGH);
    delay(150);
    digitalWrite(ledPin, LOW);
    delay(500);
  }
  return blinks; // the random number gets returned
}

Next up in the loop, is a small indicator on the serial monitor, that the player has to get in action and a call to turn() is made. That yields a true or false, depending on whether the player repeated the right amount of button pushes. The game repeats every 5 seconds.

  delay(200);
  Serial.println("now it's your turn!");

  if(turn(blinks)) {  // turn() gets called and returns wether the player succeeded or not
    Serial.println("you won!");
  } else {
    Serial.println("oww, you lost.. but try again!");
  }

  delay(5000); // after 5 seconds the game restarts

}

The turn() function that is entered sets some values at the start to later check whether the task is completed. The while runs as long as the turnTime, which is specified by the amount of LED flashes. The button status is read and depending on whether it’s pressed, another while gets accessed which is needed to notice the button release, on which the turncounter is increased. While pressing the button the LED lights up and stops when it’s released again. At the end a boolean is returned indicating whether the task was successful or not.

boolean turn(int quest) {
  int turncounter = 0;
  int turnTime = 1500 * quest; // turnTime gets set depending how many blinks the LED made
  unsigned long turnStart = millis();
  unsigned long turnCurrTime = turnStart;

  while((turnCurrTime - turnStart) < turnTime ) { // the time the task can be executed is limited
    turnCurrTime = millis(); // the current turn time is saved to be able to compare how much time has passed since the start
    btnstatus = digitalRead(btnPin); 

    while(!btnstatus){ // while the button is pushed
      digitalWrite(ledPin, HIGH); // LED gets switched on
      btnstatus = digitalRead(btnPin);  // the button status is read again to notice a change

      if(btnstatus){ // button isn't pushed, so is released again
        turncounter++; // button presses gets counted +1
        digitalWrite(ledPin, LOW); // the LED gets switched off again
        delay(50);
      }
    }
  }

  return turncounter == quest; // returns whether the player won or not
}

A problem I encountered was that the turncounter had to be increased only on button release, not just while the button was pressed.

Here’s everything in one block:

const byte ledPin = 13; // hardwired LED on pin 13
const byte btnPin = 7;  // button on pin 7
boolean btnstatus;


int quest() {
  int blinks = random(1, 6);  // a random number between 1 and 5 gets created
  for(int i = 1; i <= blinks; i++) {  // the LED blinks for the earlier chosen random number
    digitalWrite(ledPin, HIGH);
    delay(150);
    digitalWrite(ledPin, LOW);
    delay(500);
  }
  return blinks; // the random number gets returned
}

boolean turn(int quest) {
  int turncounter = 0;
  int turnTime = 1500 * quest; // turnTime gets set depending how many blinks the LED made
  unsigned long turnStart = millis();
  unsigned long turnCurrTime = turnStart;

  while((turnCurrTime - turnStart) < turnTime ) { // the time the task can be executed is limited
    turnCurrTime = millis(); // the current turn time is saved to be able to compare how much time has passed since the start
    btnstatus = digitalRead(btnPin); 

    while(!btnstatus){ // while the button is pushed
      digitalWrite(ledPin, HIGH); // LED gets switched on
      btnstatus = digitalRead(btnPin);  // the button status is read again to notice a change

      if(btnstatus){ // button isn't pushed, so is released again
        turncounter++; // button presses gets counted +1
        digitalWrite(ledPin, LOW); // the LED gets switched off again
        delay(50);
      }
    }
  }

  return turncounter == quest; // returns whether the player won or not
}

void setup() {
  Serial.begin(9600); //set baud rate for serial data transmission
  pinMode(btnPin, INPUT_PULLUP); 
  pinMode(ledPin, OUTPUT);
}

void loop() {  
  // just feedback on the Serial Monitor
  Serial.println("Watch the LED!");
  delay(1500);
  Serial.println("ready!");
  delay(250);
  Serial.println("steady!");
  delay(250);
  Serial.println("go!");  

  int blinks = quest(); // quest() gets called, to flash the LED random times and get this number for later use

  delay(200);
  Serial.println("now it's your turn!");

  if(turn(blinks)) {  // turn() gets called and returns wether the player suceeded or not
    Serial.println("you won!");
  } else {
    Serial.println("oww, you lost.. but try again!");
  }

  delay(5000); // after 5 seconds the game restarts
}

Here’s a small working example:
First round was won, second was lost by just doing nothing, so not enough button clicks and third one was lost by pressing too many times.

A nice side effect of this project was that I had to tidy my desk, so two birds with one stone :D

Downloads, Resources and Tools

Downloads

Buttongame download (.ino)
Buttongame download (.zip)

Resources

Arduino Language Reference

Tools

Arduino Uno
Arduino IDE
VS Code Extension