Fun with Arduino 04 Readable and Maintainable Code with #define

video_4Let’s mount our LED and resistor from the previous Fun with Arduino video 3 on a breadboard. With Dupont wires we connect the + (long lead) of the LED to Arduino pin 8.  The resistor goes in series. The value tried and tested in video 3 was 330 ohm, but if you don’t have that one, any value between 150 and 2k will do. A second Dupont wire goes from the resistor to the Arduino GND. Connect a push button between pin 2 and GND. If you don’t have a push button, a wire on pin 2 which we can touch to GND can be used to simulate the push button.

We’re going to modify our code from video 2 to control the LED. Let’s set two goals:

  1. We want to make our code better readable and easier to maintain.
  2. Let’s imagine pin 8 is going to operate 20 street lights on a model railway layout. They switch on when we press the button and to simulate a night cycle on the layout we want them to stay on for 3 minutes and then automatically switch off again.

Read on below the video …

 

 

We can start with our previous code:

void setup() {
  pinMode(2,INPUT_PULLUP); // push button
  pinMode(13,OUTPUT); // on board LED
}
void loop() {
  if (digitalRead(2)==LOW) digitalWrite(13,HIGH); // turn the LED on
  else digitalWrite(13,LOW); // turn the LED off
}

In this code we have to change pin 13 to pin 8. Even with this short code this already needs 3 modifications. Suppose our code is over 100 lines long … we would have to carefully scan through the entire code to find every line we need to modify, hoping not to forget anything.

Is there maybe a nicer way? Yes … there is … the #define statement can be a great help. It substitutes a text with another text. Let’s re-write our code and use two #defines:

#define PUSH_BUTTON_PIN 2
#define STREET_LIGHTS_PIN 13

void setup() {
  pinMode(PUSH_BUTTON_PIN, INPUT_PULLUP);
  pinMode(STREET_LIGHTS_PIN, OUTPUT);
}

void loop() {
  if (digitalRead(PUSH_BUTTON_PIN) == LOW)
    digitalWrite(STREET_LIGHTS_PIN, HIGH);
  else
    digitalWrite(STREET_LIGHTS_PIN, LOW);
}

Note that there are no semicolons ( ; ) behind the #define statements.

Admittedly this code is longer, while the behavior when executed is identical. However, the advantages of writing the code like this are:

  1. The code becomes better readable and we need less comments to explain things. Adding comments is a very good habit, but there’s no need to repeat the obvious.
  2. If we need to change a parameter, like pin 13 to pin 8, we don’t need to scan through the whole code, we only have to change the #define statement at the top of our code … just once … and that’s it!

Why is STREET_LIGHTS_PIN written in all capitals? This is not mandatory, but it is a convention among C++ programmers around the world. The capitals distinguish #defines from variables, which are written in lower case. There are more of these coding conventions, like the use of the underscore ( _ ) and the use of 2 spaces indent with the code between { … } and with the if / else. All this helps to make code more readable. If you’re interested to read more about these style conventions, Google for ‘C++ style guide’ or ‘C++ code standards’. Unfortunately these standards often are no easy read … but this one is digestible.

OK … our first goal is accomplished. On to the second goal: how can we get the street lights to burn for 3 minutes after we pressed the button and then automatically switch off again? A ‘quick and dirty’ way is to use a ‘delay’ statement. Quick because it’s very easy: delay(1000) will give us a 1 second pause. Dirty because it halts the Arduino, nothing else is done in that time, it’s ‘tapping fingers’. Of course we add a #define so the ‘LED on time’ can easily be changed without having to dig into the code.

#define PUSH_BUTTON_PIN 2
#define STREET_LIGHTS_PIN 8
#define LED_ON_TIME 180000 // [ms] 180000 = 3 minutes

void setup() {
  pinMode(PUSH_BUTTON_PIN,INPUT_PULLUP);
  pinMode(STREET_LIGHTS_PIN,OUTPUT);
}

void loop() {
  if (digitalRead(PUSH_BUTTON_PIN) == LOW) {
    digitalWrite(STREET_LIGHTS_PIN, HIGH);
    delay(LED_ON_TIME); 
    digitalWrite(STREET_LIGHTS_PIN, LOW);
  }
}

This code meets our specifications. Let’s change the 180000 milliseconds into 3000 ( = 3 s ) for test purposes, upload and try it out. Yes … it works fine … we can pat ourselves on the shoulder again!

In the next video we are going to see how we can connect multiple LEDs to the Arduino without blowing it up due to too large a current.

— 0 —

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s