Editado 10.01.2019
Cada tanto aparecen preguntas sobre estos tópicos en foro. En algunos casos son preguntas validas sobre procesos en paralelo, pero en la mayoría de las ocasiones se trata de un mal diseño de funciones.
Generalmente es un intento de integrar dos o mas códigos que funcionan bien por separados, pero juntos tienen comportamientos inesperados.
Por ese motivo me decidí a escribir un modesto tutorial sobre el tema, utilizando dos funciones de lo mas sencillas.
Las funciones están basadas en los ejemplos blink y blinkWithoutDelay
Pero antes un break culinario. Prepararemos una exquisita receta: un huevo duro
Receta de principiante
1 tomar un huevo
2 ponerlo en un recipiente, con agua, sobre el fuego.
3 esperar 10 minutos, sin hacer nada.
4 sacar el huevo.
Receta de masterchef para preparar un huevo duro
1 ¿Estamos preparando un huevo duro en este momento?
2 si la respuesta es no
2.1 tomar un huevo
2,2 ponerlo en un recipiente con agua sobre el fuego.
3 si la respuesta a la pregunta 1 es si
3.1 ¿ya pasaron 10 minutos?
3.2 si la respuesta de la pregunta 3.1 es no: hacer otra cosa
3.2 si la respuesta de la pregunta 3.1 es si: sacar el huevo.
sin duda la segunda receta parece mas complicada, sobre todo porque al final tenemos un huevo duro, pero es lo que hacemos en la realidad, cuando cocinamos no nos quedamos diez minutos viendo como hierve el huevo, nos ponemos a hacer otra cosa en esos diez minutos. Por eso para un observador externo parece que un cocinero esta haciendo varias recetas al mismo tiempo. Sin embargo, si intentamos unir varias recetas del primer tipo , a comida se alarga en el tiempo y parecerá que el cocinero se la pasa esperando.
Ahora un ejemplo de Arduino
El objetivo del programa es encender dos leds, uno rojo y otro verde, a diferentes frecuencias.
Led rojo con delays parpadeando cada 500 ms
int ledRojo = 14;
void setup() {
pinMode(ledRojo, OUTPUT);
}
void loop() {
LedRojo;
}
void LedRojo()
{
digitalWrite(ledRojo, HIGH);
delay(500);
digitalWrite(ledRojo, LOW);
delay(500);
}
El mismo caso, pero sin delay
const int ledPinRojo = 14; // the number of the LED pin
int ledStateRojo = LOW; // ledState used to set the LED
long previousMillisRojo = 0; // will store last time LED was updated
long intervalRojo = 500; // interval at which to blink (milliseconds)
void setup() {
pinMode(ledPinRojo, OUTPUT);
}
void loop()
{
LedRojo ;
}
void LedRojo()
{
unsigned long currentMillis = millis();
if(currentMillis - previousMillisRojo > intervalRojo) {
previousMillisRojo = currentMillis;
if (ledStateRojo == LOW)
ledStateRojo = HIGH;
else
ledStateRojo = LOW;
digitalWrite(ledPinRojo, ledStateRojo);
}
}
En ambos casos se comportan igual
Las funciones para un led Verde son equivalentes (parpadeando a un segundo)
int ledVerde = 15;
void setup() {
pinMode(ledVerde, OUTPUT);
}
void loop() {
LedVerde;
}
void LedVerde()
{
digitalWrite(ledVerde, HIGH);
delay(1000);
digitalWrite(ledVerde, LOW);
delay(1000);
}
Y su equivalente sin delay
const int ledPinVerde = 15; // the number of the LED pin
int ledStateVerde = LOW; // ledState used to set the LED
long previousMillisVerde = 0; // will store last time LED was updated
long intervalVerde = 1000; // interval at which to blink (milliseconds)
void setup() {
pinMode(ledPinVerde, OUTPUT);
}
void loop()
{
LedVerde ;
}
void LedVerde()
{
unsigned long currentMillis = millis();
if(currentMillis - previousMillisVerde > intervalVerde) {
previousMillisVerde = currentMillis;
if (ledStateVerde == LOW)
ledStateVerde = HIGH;
else
ledStateVerde = LOW;
digitalWrite(ledPinVerde, ledStateVerde);
}
}
En ambos casos el comportamiento final es el mismo.
Hasta aquí parece una complicación sin sentido no utilizar delays , pero cuando se integra el codigo
con delays el programa tiene un comportamiento inesperado.
int ledRojo = 14;
int ledVerde = 15;
void setup() {
pinMode(ledRojo, OUTPUT);
pinMode(ledVerde, OUTPUT);
}
void loop() {
LedRojo;
LedVerde;
}
void LedRojo()
{
digitalWrite(ledRojo, HIGH);
delay(500);
digitalWrite(ledRojo, LOW);
delay(500);
}
void LedVerde()
{
digitalWrite(ledVerde, HIGH);
delay(1000);
digitalWrite(ledVerde, LOW);
delay(1000);
}
El problema reside en las funciones, se completan antes de devolver el control a la función void loop, por lo tanto se ejecutan en serie, es decir una detrás de la otra.
Es en este momento cuando aparecen los post de mulhilo y procesos en paralelo.
Sin embargo el código integrado sin utilizar delays funciona correctamente
const int ledPinRojo = 14; // the number of the LED pin
int ledStateRojo = LOW; // ledState used to set the LED
long previousMillisRojo = 0; // will store last time LED was updated
long intervalRojo = 500; // interval at which to blink (milliseconds)
const int ledPinVerde = 15; // the number of the LED pin
int ledStateVerde = LOW; // ledState used to set the LED
long previousMillisVerde = 0; // will store last time LED was updated
long intervalVerde = 1000; // interval at which to blink (milliseconds)
void setup() {
pinMode(ledPinRojo, OUTPUT);
pinMode(ledPinVerde, OUTPUT);
}
void loop()
{
LedRojo ;
LedVerde ;
}
void LedRojo()
{
unsigned long currentMillis = millis();
if(currentMillis - previousMillisRojo > intervalRojo) {
previousMillisRojo = currentMillis;
if (ledStateRojo == LOW)
ledStateRojo = HIGH;
else
ledStateRojo = LOW;
digitalWrite(ledPinRojo, ledStateRojo);
}
}
void LedVerde()
{
unsigned long currentMillis = millis();
if(currentMillis - previousMillisVerde > intervalVerde) {
previousMillisVerde = currentMillis;
if (ledStateVerde == LOW)
ledStateVerde = HIGH;
else
ledStateVerde = LOW;
digitalWrite(ledPinVerde, ledStateVerde);
}
}
Como conclusión podemos decir que en la mayoría de los casos no son necesarios procesos en paralelos y se debe evitar a toda costa utilizar delays y otras estructuras que detengan el programa en algún punto.
Saludos