A few random tips for Arduino programmers. We cover saving RAM by storing text in program memory, making your programs easier to read, a technique to avoid being held up in delays, the C++ ternary operator and the watchdog timer.
Putting text strings in program memory saves ram
Write Serial.println(F(“Hello World!”)); instead of Serial.println(“Hello World”);
When you write:
Serial.println(“Hello World!”);
the text ‘Hello World!’ is stored in two places:
- Program memory
- Random access memory (RAM)
The contents of RAM are lost every time the Arduino is reset, or the power is lost. Program memory is retained through reset and power loss, so at the start of each program, normal strings are copied from program memory into RAM so they can be used by your program.
Many Arduino boards don’t have much RAM though: there’s only 2 kb on the 328 chip used in the Uno, for example. So it is easy to run out of RAM if your program uses many strings or other variables.
When you write:
Serial.println(F(“Hello World!”));
the println function gets the text from program memory directly, using a temporary buffer that doesn’t eat up lots of precious RAM.
Delays are boring
The delay function stops your program dead. The classic blink program spends most of its time doing absolutely nothing:
C++
1
2
3
4
5
6
7
|
void loop()
{
digitalWrite(LedPin, HIGH);
delay(1000); // yawn. Nothing is happening here.
digitalWrite(LedPin, LOW);
delay(1000); // zzz. Or here!
}
|
Think of all the great things you could do in that dead time: reading sensors, making noise, driving motors. Delays can be useful, but often they are just a waste of time.
There’s an easy way around it, but we’ll need a few variables:
C++
1
2
3
4
5
6
7
8
9
10
11
|
// Time stamp when the LED was last turned on or off.
long LastLEDToggleTime = 0;
// Current state of the LED; true => on; false => off.
bool IsLEDOn = false;
// Time between turning the LED on or off
const int LEDTogglePeriod = 1000; // [milliseconds]
// The pin the LED is connected to
const int LEDPin = 13;
|
And the loop becomes:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
void loop()
{
// This will toggle the LED on and off every second, with no waseful delays
if ((millis() – LastLEDToggleTime) > LEDTogglePeriod)
{
LastLEDToggleTime = millis();
if (IsLEDOn)
{
IsLEDOn = false;
digitalWrite(LEDPin, LOW);
}
else
{
IsLEDOn = true;
digitalWrite(LEDPin, HIGH);
}
}
// Do something else here.
}
|
Ternary Tricks
C++, the language the Arduino platform uses, includes a handy expression for selecting between two values:
(expression) ? (true-value) : (false-value).
This is called a ternary operator…because it has 3 arguments:
- (expression), a test which is true or false
- (true-value), the result if (expression) is true
- (false-value), the result if (expression) is false
It lets you write things like:
C++
1
2
|
IsLEDOn = !IsLEDOn; // toggle value of IsLEDOn
digitalWrite(LEDPin, IsLEDOn ? HIGH : LOW)
|
Instead of:
C++
1
2
3
4
5
6
7
8
9
10
|
if (IsLEDOn)
{
IsLEDOn = false;
digitalWrite(LEDPin, LOW);
}
else
{
IsLEDOn = true;
digitalWrite(LEDPin, HIGH);
}
|
It is easy to create code that is hard to follow using this tip. Use it wisely!
Taming runaway programs with the watch-dog timer
The Arduino’s microprocessor includes a watch-dog timer. The watch-dog timer is a sort of dead-man’s switch: if your program doesn’t keep telling the timer all is well, it will blow up the Arduino.
Actually, it just resets the micro: what you do on reset is your own responsibility.
To use the watch-dog timer, you’ll need to:
- include a library
- enable the watch-dog
- tell the watch-dog that all is well
This example should work on any Arduino that uses a microcontroller from Atmel, including the Uno, Mini and Mega. Note, older Mega’s had a problem in their bootloader. If you set the watch-dog timeout too low, you won’t be able to reprogram the Arduino using the serial bootloader. Update to the latest Mega bootloader to fix that.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
// Include the watch-dog library functions
#include
unsigned CountDown = 10;
void setup()
{
Serial.begin(9600);
// enable the watchdog timer and set a timeout.
// if we don’t call wdt_reset() before the time is up, the program will reset automatically.
wdt_enable(WDTO_1S); // WDTO_1S => 1 second timeout.
}
void loop()
{
// the program is alive…for now.
wdt_reset();
while (CountDown >= 0)
{
Serial.println(CountDown);
CountDown = CountDown – 1;
delay(30);
}
Serial.println(F(“Kaboom!”));
}
|
This program contains a bug which means the countdown will never finish. Can you spot it?
The program will get stuck in the while loop. Because that means wdt_reset() is only called the first time into loop, the watch-dog timer will eventually timeout and the program will get reset.