I am not an expert in Arduino, although I have not used the plate for a long time. And the times I have done it has been as a tool, copying and pasting code already created but without much interest to really learn how it works but simply with the intention of making it work and find it useful. This Christmas I tuned the Nativity scene a bit with some LEDs and an HC-SR04 ultrasonic sensor. And I stopped to observe what had to be done.

I just wanted to do different things with two LEDs from the same signal. Oops I quickly stumbled upon what I think will be one of the first limitations you encounter when you start to mess with Arduino. And it is not necessary to complicate it much. I speak only of some LEDs, you realize that you cannot do what you want correctly.

Let’s make it clear from the beginning in Arduino multitasking does not exist, you cannot process two tasks in parallel. But there are techniques to make calls so fast that they seem to work at the same time.

I tell you the case in more detail. At Christmas I rode a Nativity scene and I wanted certain birth lights to come on when my daughters approached. Nothing complicated I just wanted two branches of LED lights to work differently depending on the values of a proximity sensor.

I wanted that when someone approached less than 10 cm:

The branch of lights that goes to the stars stays on for 10 seconds

The other one that goes inside the houses stays on 10 seconds from the moment they move away from the Nativity.

Does it seems simple no? Well, this can cause big problems. Because Arduino is not able to work multitasking, he executes one order after another.

I have made an assembly with the ultrasonic sensor HC-SR04 and 2 leds, each one would be equivalent to a branch of Nativity. The first part is not important now, since it is to configure the setup and operation of the ultrasonic sensor in the LOOP, but this can be found in thousands of sites. Perhaps another day if I inquire more I make a special, so far here you have ( I’m sorry I don’t put credits, but I don’t remember where I took it from)

HC-SR04 Code in Arduino

int ledPin1=8; int ledPin2=7; long distancia; long tiempo; long currenttime; long timepast; void setup() { // initialize digital pin LED_BUILTIN as an output. pinMode(ledPin1, OUTPUT); pinMode(ledPin2, OUTPUT); Serial.begin(9600); pinMode(3, OUTPUT); /*Activating pin 9 as output: for ultrasonic pulse*/ pinMode(2, INPUT); /*Activating pin 8 as input: ultrasound rebound time*/ } // the loop function runs over and over again forever void loop() { digitalWrite(3,LOW); /* sensor stabilization*/ delayMicroseconds(5); digitalWrite(3, HIGH); /* send ultrasonic pulse*/ delayMicroseconds(10); tiempo=pulseIn(2, HIGH); /* Function to measure the length of the incoming pulse. Measure the time elapsed between the shipment of the ultrasonic pulse and when the sensor receives the bounce, that is: since pin 12 begins to receive the bounce, HIGH, until stop doing it, LOW, the length of the incoming pulse*/ distancia= int(0.017*tiempo); /*formula to calculate the distance obtaining an integer value*/ /*Centimeter monitoring by serial monitor*/ Serial.println("Distancia "); Serial.println(distancia); Serial.println(" cm"); delay(1000); 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 29 30 31 32 int ledPin1 = 8 ; int ledPin2 = 7 ; long distancia ; long tiempo ; long currenttime ; long timepast ; void setup ( ) { // initialize digital pin LED_BUILTIN as an output. pinMode ( ledPin1 , OUTPUT ) ; pinMode ( ledPin2 , OUTPUT ) ; Serial . begin ( 9600 ) ; pinMode ( 3 , OUTPUT ) ; /*Activating pin 9 as output: for ultrasonic pulse*/ pinMode ( 2 , INPUT ) ; /*Activating pin 8 as input: ultrasound rebound time*/ } // the loop function runs over and over again forever void loop ( ) { digitalWrite ( 3 , LOW ) ; /* sensor stabilization*/ delayMicroseconds ( 5 ) ; digitalWrite ( 3 , HIGH ) ; /* send ultrasonic pulse*/ delayMicroseconds ( 10 ) ; tiempo = pulseIn ( 2 , HIGH ) ; /* Function to measure the length of the incoming pulse. Measure the time elapsed between the shipment of the ultrasonic pulse and when the sensor receives the bounce, that is: since pin 12 begins to receive the bounce, HIGH, until stop doing it, LOW, the length of the incoming pulse*/ distancia = int ( 0.017 * tiempo ) ; /*formula to calculate the distance obtaining an integer value*/ /*Centimeter monitoring by serial monitor*/ Serial . println ( "Distancia " ) ; Serial . println ( distancia ) ; Serial . println ( " cm" ) ; delay ( 1000 ) ;

This checks and stores the distance measured by the ultrasound sensor

LEDS operating solution

The first thing that comes to mind is to start putting delays. I do not know why but all beginners think of delay () and that greatly limits the options because while using delay () the board does not work and therefore you can not do anything else in that time of suspension. The solution is the use of millis ()

Here I found a solution, simple based on if and counters. As one teacher of mine said, anything can be programmed with many if in a row. But of course the truth is not very elegant.

//if distance is less than 10, switch on the 2 LEDS and begin to count time with milis() if (distancia < 10){ digitalWrite(ledPin1, HIGH); digitalWrite(ledPin2, HIGH); currenttime=millis(); } //if distance is bigger than 10 check time from the switch on, and is is bigger than switch off LED1 if (distancia > 10){ timepast=millis()-currenttime; digitalWrite(ledPin1, LOW); //if distance is bigger 10000 switch off LED2 if(timepast>10000){ digitalWrite(ledPin2,LOW); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 //if distance is less than 10, switch on the 2 LEDS and begin to count time with milis() if ( distancia & lt ; 10 ) { digitalWrite ( ledPin1 , HIGH ) ; digitalWrite ( ledPin2 , HIGH ) ; currenttime = millis ( ) ; } //if distance is bigger than 10 check time from the switch on, and is is bigger than switch off LED1 if ( distancia & gt ; 10 ) { timepast = millis ( ) - currenttime ; digitalWrite ( ledPin1 , LOW ) ; //if distance is bigger 10000 switch off LED2 if ( timepast & gt ; 10000 ) { digitalWrite ( ledPin2 , LOW ) ; } } }

What this code intends is that Arduino is constantly executing those three if so that he will go through them so fast that he seems to be doing several things at the same time. But as we know, it continues executing sentences one by one.

Once the distance was measured and stored in the distance variable, the if would be evaluated:

The first checks if the distance is less than the desired 10 centimeters. If so, we turn on the two LEDS and start counting the time with milis ()

and we would go to the second if for the distance greater than 10 cm. If it complies, we calculate the time that has passed and deactivate the LED 1 that only depended on the distance.

We would go to the third if we checked if it has been more than 10 seconds since the counter was activated, and if so, turn off pin 2

And so the loop continues. And again.

In the end and although the solution worked it was clear that this problem was sure that many people had had it and that there had to be a more orthodox solution. I started looking and I found a good one (surely not the only one) from Adafruit’s boys and object-oriented programming. It consists of creating objects with defined classes to make quick calls and not have to repeat the code hundreds of times in our program.

That in the end is “the same” as my solution with if + counters but much more elegant and that provides a much more readable and much more efficient code.

Multitasking management inevitably leads to time management in Arduino. At first this did not fit in the article but I think it is very interesting.

Arduino time functions

As I said, I think there is a great dependence with delay (), possibly because people who start see this function in all the examples that are usually put from the blink to any traffic light or any manipulation of LEDS on and off.

Delay has a very big problem and that is when we make a call to delay () for an amount of time everything stops. The board does not read any sensor, nor does it continue executing sentences, nor does it do anything at all, just wait until the time we have told you passes and of course if we want to use the board for more than one thing at the same time this is not feasible.

We will have to take a look at millis () even delayMicroseconds () And we also have micros () that returns the number of microseconds since the program has started running

Blink without delay

A cool example to see how it works is to run the mythical Blink but without the delay. The main difference is to forget about the delay () function using milis () to be able to count the time between operations.