Memory space is limited on an Arduino board, it may be important to improve your Arduino program in order to avoid certain problems. The more we advance in programming, the more we come to write long and complex programs. It is important, as soon as possible, to take the right reflexes. Good habits can be taken to facilitate sharing and reading your work; as well as to improve its execution and the space taken in memory.
We will see in this article some methods to improve your Arduino program.
Example of application: it is a shame to buy a Mega card for a few buttons and LEDs because we have put a hundred display on the serial monitor and there is not enough memory.
Prerequisite : Programming with Arduino
Variable and function names
Use clear function and variable names:
explicit names rather than letters (Ex: ” sensorValue ” rather than ” a “)
Loop and function creation
When a piece of code is repeated several times in a program create a function or a loop.
Use loops on vectors (array). We are going to read all the analog inputs of the Arduino.
int a,b,c,d,e,f; void setup() { Serial.begin(9600); } void loop() { a=analogRead(A0); b=analogRead(A1); c=analogRead(A2); d=analogRead(A3); e=analogRead(A4); f=analogRead(A5); Serial.print(a); Serial.print(b); Serial.print(c); Serial.print(d); Serial.print(e); Serial.print(f); }
Result:
Le croquis utilise 1952 octets (6%) de l'espace de stockage de programmes. Le maximum est de 32256 octets. Les variables globales utilisent 196 octets (9%) de mémoire dynamique, ce qui laisse 1852 octets pour les variables locales. Le maximum est de 2048 octets.
Introduction of a for loop and an array
int a[6]; void setup() { Serial.begin(9600); } void loop() { for(int i=0;i<6;i++){ a[i]=analogRead(14+i); Serial.print(a[i]); } }
We can see, that in addition to being more readable, the memory space taken by the code is reduced after this operation
Le croquis utilise 1746 octets (5%) de l'espace de stockage de programmes. Le maximum est de 32256 octets. Les variables globales utilisent 184 octets (8%) de mémoire dynamique, ce qui laisse 1864 octets pour les variables locales. Le maximum est de 2048 octets.
Type of variables
Use the right types of variable. Variable types take up memory spaces of different sizes on the microcontroller.
Here is a summary table of variable sizes
Type | Size | Range |
boolean | 1 byte | 0 to 1 |
char | 1 byte | -128 to 127 |
unsigned char | 1 byte | 0 to 255 |
int | 2 bytes | -32,768 to 32,767 |
unsigned int | 2 bytes | 0 to 65,535 |
word | 2 bytes | 0 to 65,535 |
long | 4 bytes | -2,147,483,648 to 2,147483,647 |
unsigned long | 4 bytes | 0 to 4,294,967,295 |
float | 4 bytes | 3.4028235E-38 to 3.4028235E+38 |
double | 4 bytes | 3.4028235E-38 to 3.4028235E+38 |
string | 1 byte + # of chars | N/A |
array | 1 byte + (sizeOfType * # of elements) | N/A |
enum | N/A | N/A |
struct | N/A | N/A |
pointer | N/A | N/A |
void | N/A | N/A |
To properly choose the type of variable, it is good to know its extreme values and to know what types of operation will be performed on this variable. You must choose the smallest type to describe the variable and the operation.
Example: write float a = analogRead (A0); does not make sense because the analogRead () function returns a value between 0 and 1023. So the variable should be of type unsigned int
Defined as a float
float a; void setup() { Serial.begin(9600); } void loop() { a=analogRead(A0); Serial.print(a); }
Le croquis utilise 2968 octets (9%) de l'espace de stockage de programmes. Le maximum est de 32256 octets. Les variables globales utilisent 196 octets (9%) de mémoire dynamique, ce qui laisse 1852 octets pour les variables locales. Le maximum est de 2048 octets.
Defined as an int
int a; void setup() { Serial.begin(9600); } void loop() { a=analogRead(A0); Serial.print(a); }
Le croquis utilise 1736 octets (5%) de l'espace de stockage de programmes. Le maximum est de 32256 octets. Les variables globales utilisent 184 octets (8%) de mémoire dynamique, ce qui laisse 1864 octets pour les variables locales. Le maximum est de 2048 octets.
Constant variable type
When the variable will not move while the program is running, use “const” or #define to define the variable.
Global or local variable
When the variable is used in different functions, it can be interesting to define it as global. If it is a variable that only exists to display an intermediate result, it is better to define it locally.
Function F () for display on the serial monitor
Putting the Strings in the F () function, this saves a lot of space when a lot of information is sent to the serial monitor.
Example: I found a code on the internet with a phenomenal amount of print () (I even wrote a Python script to modify the code to include the function F ()). Here is the result of the compilation:
Le croquis utilise 36966 octets (14%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent 6500 octets (79%) de mémoire dynamique, ce qui laisse 1692 octets pour les variables locales. Le maximum est de 8192 octets.
La mémoire disponible faible, des problèmes de stabilité pourraient survenir.
After modifying all Serial.print () and Serial.println () in the .INO script, here is the result of the compilation:
Le croquis utilise 36770 octets (14%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent 4830 octets (58%) de mémoire dynamique, ce qui laisse 3362 octets pour les variables locales. Le maximum est de 8192 octets.
A reduction from 79 to 58% and more stability problem. Rather practical.
Use the millis () function
In principle, you should ban the use of functions that block code execution like delay (). For simple codes, this is fine, but when you have to try to run multiple tasks in parallel you can no longer afford it.
Several solutions exist to do without delay (): millis (), Timer.h, Timer2.h, interupt. I show you in this article, the millis () solution which is sufficient in most cases but do not hesitate to inquire about the others.
Here is an example of a code that reads analog input A0 every 500ms
int a; void setup() { Serial.begin(9600); } void loop() { a=analogRead(A0); Serial.print(a); delay(500); }
When we modify the code to integrate the millis () function, we get the same result with, in addition, the ability to do something else during these 500ms
int a; unsigned long previousTime=0; void setup() { Serial.begin(9600); } void loop() { if(millis()-previousTime)>500{ previousTime=millis(); a=analogRead(A0); Serial.print(a); } }
If you know of other methods or best practices for writing and improving your Arduino program, don’t hesitate to leave a comment.
Sources
- https://robotresearchlab.com/2016/11/14/variable-data-types/