I wrote this code to control my christmas tree. It takes up the majority of the memory on my Arduino Uno:
Sketch uses 31822 bytes (98%) of program storage space. Maximum is 32256 bytes.
Global variables use 1882 bytes (91%) of dynamic memory, leaving 166 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.
Does anyone know how I can reduce the memory usage?
Code:
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>
#define TREEONE 3
#define TREETWO 4
#define TREETHREE 5
#define TREEFOUR 10
SdFat sd;
SFEMP3Shield MP3player;
const uint8_t volume = 10; // MP3 Player volume 0=max, 255=lowest (off)
//10 for basement 50 for testing
const uint16_t monoMode = 1;
int song = 3;
int num = 0;
int count = 0;
//put arrays here
byte arrayTree[] = {17,16,9,8,3,2,5,4,17,16,9,8,3, ...etc };
void setup() {
initSD();
initMP3Player();
pinMode(TREEONE, OUTPUT);
pinMode(TREETWO, OUTPUT);
pinMode(TREETHREE, OUTPUT);
pinMode(TREEFOUR, OUTPUT);
digitalWrite(TREEONE, HIGH);
digitalWrite(TREETWO, HIGH);
digitalWrite(TREETHREE, HIGH);
digitalWrite(TREEFOUR, HIGH);
}
void loop() {
if(!MP3player.isPlaying()){
MP3player.playTrack(song);
MetallicaChristmas();
}
}
void initSD() {
if(!sd.begin(SD_SEL, SPI_HALF_SPEED))
sd.initErrorHalt();
if(!sd.chdir("/"))
sd.errorHalt("sd.chdir");
}
void initMP3Player() {
uint8_t result = MP3player.begin();
MP3player.setVolume(volume, volume);
MP3player.setMonoMode(monoMode);
}
void treeFunc() {
//delay(arrayTimes[i]);
num = arrayTree[count];
//TREEONE
if(num>15){
if((num%2)==0){
digitalWrite(TREEONE,HIGH);
}else{
digitalWrite(TREEONE,LOW);
}
}
//TREETWO
if((num%16)>7){
if((num%2)==0){
digitalWrite(TREETWO,HIGH);
}else{
digitalWrite(TREETWO,LOW);
}
}
//TREETHREE
if((num%8)>3){
if((num%2)==0){
digitalWrite(TREETHREE,HIGH);
}else{
digitalWrite(TREETHREE,LOW);
}
}
//TREEFOUR
if((num%4)>1){
if((num%2)==0){
digitalWrite(TREEFOUR,HIGH);
}else{
digitalWrite(TREEFOUR,LOW);
}
}
count = count + 1;
}
void MetallicaChristmas()
{
//event 1
delay(670);
treeFunc();
delay(248);
treeFunc();
//event 2
delay(116);
treeFunc();
delay(248);
treeFunc();
//event 3
delay(100);
treeFunc();
delay(248);
treeFunc();
//event 4
delay(132);
treeFunc();
delay(248);
treeFunc();
//event 5
delay(125);
treeFunc();
delay(248);
treeFunc();
//event 6
...etc.
1 Answer 1
As well as PROGMEM
(as described in the comments), there are a couple of other efficiencies that you can make:
A function call is expensive (takes a lot of code space), and you are performing a LOT of them!
The repetitious calls to
delay()
followed bytreeFunc()
are wasteful. Your commented-out line//delay(arrayTimes[i]);
looks like you were going to do the right thing, so I’d restore that (use
count
instead ofi
) and put thedelay()
numbers in a newint arrayTimes[]
array.PROGMEM
this array too, of course!Once you’ve done this, you can remove all the calls to
delay()
. You’ll be left with nothing but repeated calls totreefunc()
, which you can replace with a single loop:for (count=0;count<sizeof(arrayTree);++count) { treeFunc(); } // for
Don’t forget to get rid of the
count = count + 1;
line fromtreeFunc()
- it’s now in thefor
loop.
Also expensive is calling the same function twice except with different parameters in both sides of the
if
intreeFunc()
. Instead of:if (<condition>) { Function(1); } // if else { Function(0); } // else
you can instead do:
Function(<condition>);
For this to work, you need to know that
HIGH
has the value1
andLOW
has the value0
- and that atrue
condition has the value1
and afalse
condition has the value0
.So, you need to change the
if ()
slightly:digitalWrite(THREEONE, (num%2)>0);
Finally, the mod
%
operator itself is very expensive, since it is effectively a division, and the Arduino chip doesn’t know how to divide - so the code to do so is large. But the code you’ve written is using binary arithmetic, which the Arduino can do instantly - you just have to write it as such.- Instead of
(num%2)>0
usenum & B0001
. - Instead of
(num%4)>1
usenum & B0010
. - Instead of
(num%8)>3
usenum & B0100
. - Instead of
(num%16)>7
usenum & B1000
.
- Instead of
You’ve probably copied the guts of this code from somewhere else, and while it works it isn’t very efficient. Writing the code as above will greatly reduce your code size, exchanging repeated calls for much smaller PROGMEM
arrays.
arrayTree
. And use PROGMEM on both arrays your code will become smaller and use less dynamic memory. And also make it easier to read/maintain.