In this article I am going to write about some ideas that improved my arduino code to higher levels. Or, by other words, what I learned during making bigger projects and now I use it whenever I can.
Use TABsAdruino software (IDE) allows to use TABs. Use them! It makes the code very clear and quickly available. During compilation Arduino IDE takes the tab by tab like the code would be written on one sheet of the paper only.
I create the tab for every component that is connected to my Arduino. For example my project LED Cube 4x4x4 contains these tabs:
The main (and first) TAB has the name of the project I created. This contains usually variables used in all the project, setup(), loop() and an interruption function.
In setup() and loop() I call functions defined on other tabs of the project. If functions are on specific tabs it can help me to find them faster than to look for them among others on the main tab.
The TAB "Pin_scheme" contains commented overview of Arduino pins so I see clearly which pins are what for and I have a whole picture of used Arduino pins. For example:
/*
* PIN 0
* PIN 1
* PIN 2 - (INPUT) PushButton
* PIN 3
* PIN 4 - (OUTPUT PORT D4) Layer 0
* PIN 5 - (OUTPUT PORT D5) Layer 1
.
.
.
*/
The "Patterns" TAB in this project contains all the functions about patterns that displays on the led cube.
The "ShiftRegister" TAB contains a basic setting and functions for shift registers that are connected to Arduino. Variables used only for shift registers are defined on this tab too. The code looks like this:
#define latchPin 10 //PORT B2
#define clockPin 9 //PORT B1
#define dataPin 11 //PORT B3
#define resetPin 8 //PORT B0
void InitializeShiftReg() {
DDRB |= B1111; //pins D8-D11 as OUTPUTS
PORTB |= B0001; //resetPin to HIGH
}
void SetShiftReg(unsigned int value) {
bitClear(PORTB, 2); //digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, value >> 8); //shift out high byte, alternative: LSBFIRST / MSBFIRST
shiftOut(dataPin, clockPin, MSBFIRST, value); //shift out low byte, alternative: LSBFIRST / MSBFIRST
bitSet(PORTB, 2); //digitalWrite(latchPin, HIGH);
}
You can notice I create Initialize...() function for the component and then I call this function in the setup() on the main tab. So every component connected to Arduino has its own initalization function and code on the main tab is more clear.
SetShiftReg() is a function that servers for this component and is called from the loop() on the main tab.
Don't stop the LOOPArduino is a quite fast microcontroller. It can do a lot of opperations in microsecconds (1 microsec = 0, 000001 second). Its endless process is made thank to the loop() function. It can handle a lot of diffrent things almost at once if we don't stop it. We can set to do diffrent things in to loop() this way:
void loop() {
if (process1) {
....
}
if (process2) {
....
}
....
if (processN) {
}
}
... where process1... processN are booleans that we set to true or false during the program.
Delay() function stops all the procesess and waits defined milliseconds. So if we need from Arduino to care about more than 1 thing, then we cannot use delay(). Instead of this we create a boolen "processX" as following:
#define delayTime 1000
unsigned long startTime;
void setup() {
....
startTime = millis();
}
void loop() {
....
if (millis() - startTime > delayTime) {
....codeX.....
startTime = millis();
}
}
The millis() returns actual time in milliseconds. If we need microseconds we can use micros() instead of it. The codeX in our case will start every second, but waiting for this second will not stop other processes in the loop.
InterruptionsInterruptions is another great feature of Arduino. It can allow the code of Arduino react immediately to any impulse from outside. We use attachinterrupt() to set an interruption and our function that will be called if an interruption appeared. Arduino UNO and Nano has 2 pins (D2 and D3) we can use to interrupt things. Let's look at the example with the Push button:
#define buttonPin 2
bool buttonPushed = false;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(buttonPin), PushButton, FALLING);
}
void loop() {
....
if (buttonPushed) {
detachInterrupt(digitalPinToInterrupt(buttonPin));
buttonPushed = false;
....codeY....
attachInterrupt(digitalPinToInterrupt(buttonPin), PushButton, FALLING);
}
....
}
void PushButton() {
buttonPushed = true;
}
In this code we set our function PushButton() that will be called if the push button is pressed. Push button is connected to the Groung and pin 2 of Arduino. Very important thing is that the interruption function PushButton() must be as simple as possible. If you try to call other functions from it they do not have to work.
The bad feature of a push button is that when you press it, it does not go directly to the state ON or OFF, but it creates a lot of noise like ON, OFF, ON, OFF, ON, OFF at the moment we pressed it. This is why we use detachInterrupt() to detach it from the pin 2 and if we do our codeY we attach it again.
Use PORT RegistersFunctions digitalWrite() and digitalRead() are commonly used for setting or reading pins of Arduino. But Arduino allows to use PORT registers that set pins much more quicklier and we can use them to set more pins at once. These registers stores values of Arduino pins so we can read from them too.
For example if we want to set pin 10 to high, we can call digitalWrite(10, HIGH), or we can do the same by calling bitSet(PORTB, 2). PORTB maps to Arduino digital pins 8 to 13. Pin 10 is the third bit of the register PORTB (we count from 0). If we want to read the value of the pin 10, instead of digitalRead(10) we take the third value from the register PINB: (PINB & B100). If we understand the work of bits, we can change this code:
void setup() {
pinMode(8, INPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
digitalWrite(10, HIGH);
digitalWrite(11, HIGH);
digitalWrite(12, HIGH);
}
void loop() {
............
if (analogRead(8)) {
....
digitalWrite(10, LOW);
}
............
}
to this one:
void setup() {
DDRB = B111100; //sets INPUTS and OUTPUTS
PORTB |= B11100; //sets pins 10, 11 and 12 to HIGH
}
void loop() {
............
if (PINB & B1) { //takes directly the value of pin 8
....
bitClear(PORTB, 2); //sets directly the value of pin 10 to LOW
}
............
}
For more information look at: https://www.arduino.cc/en/Reference/PortManipulation
More memory required?Arduino does not have a lot of memory. You can find a lot of articles that deals how to write your code better to save some space of the memory. But if it is not enough a lot of people changes Arduino Nano to Arduino Mega2560 that has more memory. In my case Arduino Nano bought from ebay is much more cheaper than Arduino Mega so I like rather to combine 2 or more Arduino Nanos.
You can connect them through pins A4 and A5 and let them communicate through I2C protocol. It means that Arduino1 can do some part of the work, Arduino2 can do the rest and they can communicate with each other very quickly and very easily by using Wire.h library. This way you double the memory for your code and even pins for doing a lot of interesting things.
In some cases it is worth to think about using EEPROM. Your Arduino UNO or Nano has a built-in EEPROM with 1024 bytes. Sometimes it is a sin not to use it. If you have stable blocks of values, you can save them to this EEPROM and then they do not interfere in the memory.
More about EEPROM: https://www.arduino.cc/en/Reference/EEPROM
More pins required?If you need more digital pins for a project, the cheapest and easiest way is to use shift registers. The shift register 74HC595 gives you 8 digital outputs controlled by 3 pins of Arduino. But you can use the same 3 pins of Arduino to controll more shift registers at the same moment, so you can have so many outputs as you need.
If I started to use shift registers I noticed that my code is much more shorter and easier. To set 8 or more outputs of shift registers is often easier than to set 8 or more outputs of Arduino pins. Mainly in such projects where you want to set them at the same moment.
On another side there is the shift register 74HC165 that works the same, but gives you 8 digital inputs. Again, you can use the same 3 pins of Arduino to controll more such shift registers.
Closer look at https://www.arduino.cc/en/Tutorial/Foundations/ShiftOut
Comments
Please log in or sign up to comment.