You are on page 1of 13

Arduino Programar multitareas,

controlar una intermitencia y


simultneamente vigilar la pulsacin de
un botn

Por Flix Maocho


27/2/2013
..

Objetivo de este post:


Ensear a utilizar ejecutar varias tareas simultaneamente , simulando una caopacuidad
multitarea que no tyrae de origen el equipo. Adicionalmente se explica la forma segura
de saber diferenciar una pulsacin en continuada de dos pulsaciones contiguas.
_________________
Los detractores del presidente Johnson, decan que no poda hacer dos cosas a la vez,
por ejemplo, andar y mascar chicle. Esta indudable maldad poltica, es un buen ejemplo
para explicar lo que supone hacer multitareas. Hasta la invencin de los ordenadores
con varios cores, o ncleos de procesador, los ordenadores slo tenan un procesador,
y este, como el Presidente Jonson, solo podan hacer una sola cosa a la vez, fuera andar
o mascar chicle, pero no podan hacer ambas cosas simultneamente. No obstante,
todos hemos visto hacer a los ordenadores varias cosas dispares a un tiempo, por
ejemplo, en la pantalla aparecen las letras que escribes en el teclado, mientras la
impresora imprime una fotografa que habas terminado de retocar antes y por los
baffles del PC, suena, (con ruido de lata), tu msica favorita. Es decir se estn
ejecutando tres tareas, capturar texto, imprimir, y emitir msica totalmente

indeopendientes, pese a que con mucha probabilidad solo tiene un nucleo de CPU capaz
de hacer en un instante solo una de esas tres tareas.
Se dice por ello, que los PC son multitarea, sin embargo no es cierto, lo que hacen es
repartir el tiempo del controlador, o tiempo de CPU, de su nico procesador, en
pequeas porciones y dedicar cada una de ellas, a hacer avanzar concwcutivamente
cada una de las diferentes tareas que tiene encomendadas, un ratito atiendo a la
pantalla para mostrar el carcter que han pulsado, el siguiente momento escribi media
linea en la impresora , y el siguiente a lo dedido a emitir una nota musical y as
sucesivamente, de tal forma, que si el procesador es suficientemente rpido, sobre todo
mucho ms rpido que los dispositivos perifricos, teclado, impresora y altavoz, y el
tiempo de parada de cada tarea es lo suficientemente pequeas para que no se note
que se para y parece que hacen varias cosas a la vez, aunque la realidad es que en un
instante cualquiera, solo hacen una de ellas.
Si alguno utiliza el ordenador desde hace tiempo, recordar que antes, la velocidad de
escritura de la impresora variaba en funcin de lo que estabas haciendo, pues una
buena gestora de multitareas, en vez de repartir por igual el tiempo de CPU, lo hace
primando los trabajos cara al pblico en detrimento de los trabajos sin intervencin
humana. Si adems estos no son crticos para el sistema aun pierden mas prioridad y
imprimir, era de los trabajos que no tenan necesidad de intervencin humana, y no
eran crticos para el sistema, por lo que las impresoras antes, impriman un poco a
trompicones. A medida que los relojes de los procesadores fueron cada vez ms rpidos,
todos los trabajos ganaban en rapidez. por lo que los momento de parada disminuyen,
de modo que antes que lo notes, toca avanzar nuevamente al trabajo un poco. Toda
esta introduccin histrica viene a cuento porque el procesador de Arduino, debe tener
hoy ms o menos la capacidad que tena un viejo PC y su reloj, no es muy rpido, por lo
que no esta previsto que hagas dos cosas a la vez y cuando quieres que las hagas, has
de ser t quien te tienes que ingeniar para gestionar a pelo el multiproceso.
Pongamos un ejemplo sencillo, tenemos una linterna que funciona como muchas que
hay en el mercado, la primera vez que aprietas el botn se enciende la luz, al volver a
apretar el botn, pasa a ser intermitentemente, de modo que que por ejemplo esta un 3
segundos apagado y 3 encendida y solo apretando nuevamente el botn, apagamos
definitivamente la linterna.

Hardware
Bien, pasemos a programar nuestro experimento. Comenzamos por fabricar
el hardware en este caso una linterna que no es ms que unLED controlado por
un PIN como ya hemos visto en post anteriores,y un botn que recoge las pulsaciones

que ejecutamos, algo que ya hemos efectuado en captulos anteriores, El esquema


es el que abre el post, y su descripcin es el siguiente siguiente:
Un cable rojo conecta el PIN 5V (5 voltios) y lo conecta con el bus rojo de la parte
inferior de la tarjeta protoboard mientras que el cable azul conecta el PIN
GND (tierra) con el bus azul , El montaje del botn lo vamos a hacer del tipo PULL
DOWN o sea que si no se pulsa el botn la tensin del cable amarillo es 0 Volts y si
se pulsa pasa a ser 5 Voltios, (si no recuerda bien este montaje lo tiene explicado con
detalle en el post Como funciona y se utiliza un pulsador ), para ello,
un pequeo cable rojo conecta el bus rojocon la pata izquierda del
botn mientras la pata superior izquierda conecta con el PIN 7 que abriremos como
de INPUT para leer el voltaje del cable amarillo. Adicionalmente y para que no
queden un circuito flotante unimos el la rpata derecha del pulsado al bus de
tierra con un pequeo cable azul intercalando una resistencia de 1000 .
Por su parte el LED se alimenta con un cable verde que parte del PIN 8 que lo
definiremos como de OUPUT y que acaba en donde de conecta su pata ms larga (la
positiva o ctodo) mientras que unimos a la pata negativa una resistencia de 220
suficiente para rebajar la tensin en la lnea a 3,5 volts ms o menos que es a la
tensin de trabajo de estos LED. Cuando mandemos salir voltaje (HIGH) por el PIN 8,
el LED brillar mientras si mandamos al PIN 8 voltaje 0, (LOW), el LED
permanecer apagado.

Software
Programaremos primero Ardunio sin tener en cuenta el necesario multiproceso, para
que podamos observar que el circuito puede fallar cuando la luz parpadea
porque no advierte que hemos pulsado botn.
El squetch ser como sigue :
Sketch Linterna_erronea
/*
Linterna_erroneo
Al oprimir el pulsado;
La 1 vez se enciende el LED
La 2 vez parpadea en intervalos de 10
La 3 vez de apaga
El Circuito:
LED controlado por el PIN 8 de abierto como salida

Resistencia de 220 Ohms en el mismo circuito del LED


Pulsador entre el PIN 7 y el PIN 5V
Resistencia de 10K entre el PIN 7 y el PIN de tierra
Flix Maocho
Este ejemplo hecho para demostrar que no funciona bien pues si
se pulsa cuando la luz parpadea es posible que no se detecte.
Hay otro sketch llamado Linterna_correcto que corrige el error
Es de dominio pblico
https://felixmaocho.wordpress.com/?s=arduino
*/
// Arrea de definicin de constantes y variables
const int buttonPin = 7; // el PIN 7 controla el pulsador
const int ledPin = 8; // el PIN 8 controla el LED
int buttonState = 0; // variable para leer el estado del pulsador
int evento = 0; // evento a ejecutar
// 0 = no hacer nada 1= encender, 2 = parpadeo 3 = terminar
// Declaracin del Hardware PINs utilizados
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT);
}
// Loop donde se ejecuta el proceso
void loop(){
// leer el botn y si guardar el valor obtenido
buttonState = digitalRead(buttonPin);
// chequear si se ha pulsado el pulsador si se pulso cambiar de evento y ejecutarlo
// Cambiar de evento
if (buttonState == HIGH) {
// Si han apretado el botn y estamos en el primer ciclo elegimos el evento a ejecutar
// que ser el siguiente al ltimo ejecutado
// evento = 0 encender LED
if (evento == 0) {
digitalWrite(ledPin, HIGH);
delay (500); // Pongo un delay para dar tiempo a retirar el dedo del botn
evento = 1;

}
else {
// evento = 1 poner el LED intermitente
// en el bucle primera vez hacemos la primer intermitencia
if (evento == 1) {
digitalWrite(ledPin, LOW); //apagar LED
delay(2500); //esperar 10 segundos
digitalWrite(ledPin, HIGH); //encender LED
delay(2500); //esperar 10 segundos
evento = 2;
}
else
// evento = 2 apagar definitivamente y dejar todo como al principio
if (evento == 2) {
digitalWrite(ledPin, LOW);
evento = 0;
delay (500); // Pongo un delay para dar tiempo a retirar el dedo del botn
}
}
}
else{
// en el caso de que estemos en el evento 2 intermitencia y no se haya apretado el
botn
// habr que repetir la secuencia
if (evento == 2) {
digitalWrite(ledPin, LOW); //apagar LED
delay(2500); //esperar 10 segundos
digitalWrite(ledPin, HIGH); //encender LED
delay(2500); //esperar 10 segundos
}
}
}

Descripcion del Sketch Linterna_erronea


Para quien no entienda muy bien el programa se lo explico con detalle
En la zona de inicio defino las constantes y variables que vamos a utilizar. Las
constantes buttonPin con valor 7 para controla el pulsador y ledPin con valor 8 para
controlar el LED y dos variables, buttonState para guardar el status del botn que

pueden ser solo HIGH con voltaje alto y LOW con voltaje y la variable evento que
inicialmente toma el valor 0 que equivale a decir que esta apagada la bombilla
esperando que aprieten el botn.
A continuacin definimos como vamos a atizar el Hardware, en este caso el PIN
buttonPin, o sea el 7 se va a utilizar para controlar el botn y lo definimos como de
entrada para que pueda leer el voltaje del cable amarillo y el PIN ledPin o sea el 8, se
va a utilizar para apagar y encender el LED por lo que le declaramos de salida.
Comenzamos a programar el bucle que se recorrer una y otra vez.
Lo primero que hacemos es leer el voltaje del cable amarillo en el PIN 7 (buttonPin)
puede que el cable no tenga tensin (LOW) seal que no se puls el pulsador o que la
tenga (HIGH) y guardar el valor en buttonState.
Si se ha apretado el botn (buttonState iguala HIGH) y:
Estbamos en el evento 0 (inicio, todo apagado), nos toca encender la luz,
(digitalWrite HIGH). Como eso es casi inmediato aado un tiempo (delay) de 500
milisegundos (medio segundo) para que de tiempo a retirar el dedo del botn antes de
iniciar el siguiente ciclo. Cuando acabo este evento pongo el indicador evento a 1
para avisar que este evento ha acabado.
Sui ni han aoretado el botn
Si evento =1 Estbamos en el evento 1 (encendido el LED) nos toca poner el LED
intermitente, iniciamos apagando el LED , (digitalWrite LOW), esperamos 2500
milisegundos (delay) volvemos a encender (digitalWrite HIGH) y esperamos 2500
milisegundos (delay). En total 5 segundos de parpadeo. Tiempo en que LA MAQUINA NO
PUEDE CONSULTAR SI SE PULSA EL BOTON por lo que si lo hacemos en ese momento la
MAQUINA NO SE ENTERA. Cuando acaba este parpadeo pongo el indicador evento a 2
para avisar que este evento se ha iniciado.
Ejecutar los eventos
Si evento =2 Estbamos en el evento 2 (LED intermitente) nos toca apagar el
LED, (digitalWrite LOW). Como eso es casi inmediato aado un tiempo delay) de 500
milisegundos (medio segundo) para que de tiempo a retirar el dedo del botn y pongo
el indicador evento a 0 para avisar que comienza la espera de un nuevo ciclo de
eventos.
Aun queda ver que hacemos en el caso de que no se haya pulsado el botn. Entonces si
el evento que se esta realizando es el 0, (esperar a que se pulse), 1 (encendido el LED),

o el tres (apagado el LED no hay que hacer nada) pero si el evento que se est
ejecutando es el 2 (intermitencia del LED) tendremos que efectuar otro parpadeo que
ser igual al explicado anteriormente y que nuevamente durara 5 segundos. Tiempo en
que LA MAQUINA NO PUEDE CONSULTAR SI SE PULSA EL BOTON por lo que si lo
hacemos en ese momento laMAQUINA NO SE ENTERA.
En el video que pongo a continuacin veremos que responde perfectamente a encender
el LED, y a ponerlo intermitente, pero que cuando la luz esta intermitente es difcil
apagarla porque tienes que apretar exactamente gasta que se apaga la intermitencia y
sale en ese momento del ciclo pues si no llegas NO SE ENTERA QUE HAS APRETADO y si
TE PASA y dejas el dedo una vez encendido ms del medio segundo programado, la
maquina despus de volver a encender LED, entiende que nuevamente has pulsado dos
veces y pasa nuevamente a dejar la luz intermitente.
Se ve claramente que tenemos que trabajar simultneamente encendiendo y apagando
la luz y a la vez estudiando si apretamos el pulsador, o sea en multiproceso. Para ello
dedicaremos los ciclos impares a la tarea de ver si han apretado el botn y los pares a
la tarea de ir adelantando el evento que corresponda ejecutar. los el evento 0 (esperar a
que toquen el botn), el 1( encenderle LED ) y el 3 (apagar el LED y dejarlo todo como a
la entrada, son muy rpidos de ejecutar hasta el punto que en el programa pusimos un
tiempo de espera (delay) para dar tiempo a retirar el dedo. En este programa
perfeccionaremos el sistema y no haremos nada en tanto el dedo pulse el botn sea el
tiempo que sea , as que el de disparador de iniciar un nuevo evento ser primero
detectar que se ha pisado el botn y segundo que se ha soltado.
Mejora para el control de l lsado de el botn
As pues, pondremos un bucle corto que compruebe si el botn estaba sin pisar,
que se ha pisado y si esta pisado, que se ha soltado y hasta que eso no ocurra no
cambiaremos el evento que se esta realizando con ello nos libramos de las chapuzas
que hacamos para prolongar la duracin de los eventos rpidos y habr menos
interpretaciones errneas.
Por otra parte para aumentar la velocidad de ejecucin de los parpadeos cambiaremos
de encender a apagar el LED y viceversa cuando un contador que aumenta cada vez
que pasa por las rutinas llegue a una cantidad de mosopare un milisegundo hasta que
haya pasado el tiempo deseado que dure el parpadeo. Como en cada bucle solo va a
aumentar el contador el tiempo y hacer una parada de un milisegundo, la ejecucin del
bucle mientras ejecuta este evento, ser similar al de los otros eventos, es decir ser
muy rpido

El programa queda as con se indica.


Sketch Linterna_correcto
/*
Linterna_correcto
Al oprimir el pulsado;
La 1 vez se enciende el LED
La 2 vez parpadea en intervalos de 10
La 3 vez de apaga
El Circuito:
LED controlado por el PIN 8 de abierto como salida
Resistencia de 220 Ohms en el mismo circuito del LED
Pulsador entre el PIN 7 y el PIN 5V
Resistencia de 10K entre el PIN 7 y el PIN de tierra
Flix Maocho
Este ejemplo explica como se simula un multiproceso
y corrige el error existente en el proceso anterior llamado
Linterna_erroneo
Es de dominio pblico
https://felixmaocho.wordpress.com/?s=arduino
*/
// Arrea de definicin de constantes y variables
const int buttonPin = 7; // el PIN 7 controla el pulsador
const int ledPin = 8; // el PIN 8 controla el LED
int buttonState = 0; // variable para leer el estado del pulsador
int evento = 0; // evento a ejecutar
// 0 = no hacer nada 1= encender, 2 = parpadeo 3 = terminar
int vuelta = 1; // 1 = mira si pulsaron el botn 2 = avanza un ciclo el evento
int pulsado = 0; // 0 = botn no pulsado 1 = botn pulsado
int encendido = 0; // 0 = LED apagado 1 = LED encendido
int contador = 0; // 0 = contador de tiempo de intermitencia
int finfase = 2500; // finfase = Tiempo de intermitencia aproximadamente 1250 pasos
del contador
int finparpadeo = 5000; // finparpadeofase = timpo de encendido apagado
aproximadamente 5000 pasos del contador

// Declaracin del Hardware PINs utilizados


void setup() {
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT);
}
// Loop donde se ejecuta el proceso
void loop(){
if (vuelta == 1) { // vuelta impar chequear botn
vuelta = 2; // la prxima vuelta par
buttonState = digitalRead(buttonPin); // leer y guardar el valor obtenido en
buttonState
if (buttonState == HIGH) { // si pulsado 0 y buttonState es HIGH, nueva pulsacin
if (pulsado == 0) {
pulsado = 1; // poner pulsado a 1
}
}
else { // si han dejad de pulsar pero haban pulsado previamente
if (pulsado == 1) {
evento = evento +1; // cambiar de evento
pulsado = 0; // poner pulsado a 0 para la prxima vez
}
}
}
else { // vuelta par. Avanzar el evento que corresponda
vuelta = 1; // la prxima vuelta impar
// evento = 0 apaga el LED si est encendido
if (evento == 0) {
if (encendido == 1) {
digitalWrite(ledPin, LOW);
encendido = 0;
}
}
// evento = 1 encender LED est apagado
if (evento == 1) {
if (encendido == 0) {
digitalWrite(ledPin, HIGH);
encendido = 1;
}

}
else {
// evento = 2 LED intermitente
if (evento == 2) {
contador = contador + 1; // contador de tiempo de intermitencia
if (contador == 1) {
digitalWrite(ledPin, LOW); // apagamos el LED
}
if (contador < finfase) {
delay(1); // apagamos el LED
}
if (contador == finfase ) { // contador = x encendemos el LED
digitalWrite(ledPin, HIGH);
}
if (contador < finparpadeo) {
delay(1); // apagamos el LED
}
if (contador == finparpadeo ) { // fin del parpadeo
contador = 0 ;
}
}
else {
// evento = 3 apagar LED y dejar contadores inicializados
if (evento == 3) {
digitalWrite(ledPin, LOW);
evento = 0;
encendido = 0;
pulsado = 0;
}
}
}
}
}

Descripcion del Sketch Linterna_correcto


Nuevamente voy a explicar detalladamente este segundo sketch pero algo mas
ligeramente pues poco a poco hemos de acostumbrarnos a entender directamente el
cdigo,

Lo primero que tengo que resaltar es que no hemos tocado nuestro hardware lo que
funcionaba mal pasa a funcionar bien, simplemente porque hemos mejorado las
instrucciones que manejan el HARD, esa es una ventaja de los controlado digitalmente
que se puede mejorar su funcionamiento son tocar nada fsico. Algo que estamos
acostumbrados, nuestro ordenador funciona mejor y ms seguro a medida que
actualizamos el sistema operativo y las versiones de los programas sin que haya falta
tocar un tornillo sol instalando un nuevo programa. Igual pasa en esta linterna que
hemos fabricado
Para simular el multiproceso hemos dividido los bucles dedicando los bucles pares a una
tarea y los impares a otras, a veces no se hace a partes iguales sino por ejemplo un
bucle a una tarea y tres seguidos a otra, segn la importancia que demos a las tareas o
lo crtico de su funcionamiento. Por el ejemplo, el vdeo y la msica suelen estar
primadas ante la imagen fija y el texto, pues en estos procesos se nota menos la
lentitud que en los anteriores.
En el Arrea de definicin de constantes y variables hemos definido mas valores que
necesitaremos en el proceso vuelta para distinguir las vueltas pares de las impares,
encendido para encender el LED solo si esta apagado y contador para llevar las
vueltas que da en la rutina de intermitencia y apagar el LED durante x, encenderle y
tenerle encendido otras y vueltas y volver a comenzar y pulsado que nos valdr
para controlar los ciclos que transcurran sin que se levante el dedo del pulsador.
Si la vuelta es 1 se chequea botn y se de a vuelta el valor 2 para prepararla para el
siguiente ciclo. Se le el buttonPin y se guarda la lectura en buttonState.
Si antes no se haba pulsado , pulsado = 0, y ahora la lectura de HIGH se ha pulsado
el botn, ponemos pulsado a 1 y esperamos a que lo dejen de pulsar para cambiar de
evento, mientras tengan el dedo en el pulsador seguiremos con el mismo evento. Si se
ha pulsado y la nueva lectura de LOW quiere decir que han liberado el botn y
cambiamos de evento a ejecutar, ponemos pulsado cero para prepararlo para la
siguiente pulsacin.
Si vuelta no es uno avanzamos los eventos
Si estamos en el evento 1 (encender el LED) y esta apagado lo encendemos y ponemos
encendido a 1 para no volverlo a intentar mientras est encendido
Si estamos en el evento 2 ( LED intermitente), cuando contador vale 1 e apagamos el
LED, cundo valga finciclo volvemos encenderlo, y cuando valga 2fin parpadeo
hemos acabado el parpadeo y ponemos nuevamente el contador a cero. En los
intermedios entre apagado y encendido y encendido y vuelta a apagar, solo hacemos

una parada de un nanosegundo en cada ciclo y el estamos en el evento 3 (Apagamos el


LED y dejamos todo como lo encontramos al principio
Quiero hacer hincapi en los siguientes aspectos
El secreto de los multiprocesos, consiste repartir los diferentes ciclos del programa entre
todos los procesos a realizar, (en este caso dos procesos, vigilar el botn y controlar las
luces), y que por ninguna bifurcacin del programa puede existir un trabajo en que dure
tanto que impida el correcto funcionamiento de los dems procesos.
Cuando eso ocurra, deberemos dividir ese trabajo en muchos paso consecutivos. de
forma que cada paso se realice en un ciclo diferente, permitiendo de esta forma,
entrelazar la ejecucin de todos los procesos de una forma suave para el
funcionamiento de todos ellos. En este sketch hemos sustituidos los delay de diez
segundos de espera, que eran incompatibles con dejar sin vigilancia el botn ese
tiempo, por el trabajo de sumar en cada ciclo uno a un contador, hasta llegar a los
5000, algo que espero sea, en una primera aproximacin, mas o menos 10 segundos,
aunque hasta que no haga una prueba real no podr decir si es poco o mucho y corregir
con ello el valor de x asta alcanzar el objetivo marcado de intermitencias de 10
segundos en pocos experimentos.
Tambin quiero resaltar la utilidad de parametrizar variables, cosa que no es necesario
cuando en todo el Squetch van a tener un valor invariable, Las funciones condicionales,
(if), que controlan el flujo del proceso, funcionan igual de bien poniendo si tiempo
igual 2500 que si ponemos por un lado finfase igual 2500 y por otro si tiempo =
finfase, pero utilizar un parmetro permite que si descubrimos que el valor que hemos
dado a x es inadecuado, ( y aqu por ejemplo dar con el valor adecuado nos puede
costar diez experimentos) y por ejemplo en una nueva prueba vamos a dar a x el
nuevo valor de 2000 en vez de 2500, basta cambiarlo en el rea donde se inicializan las
variables, sin tener que recorrer lnea por lnea todo el texto del programa cambiando
2000 por 2500.
Por este motivo un programa bien parametrizado es fcil de adaptar a cambios, por
ejemplo en este es muy fcil indicar que s en vez de los PIN 7 y 8 se utilizan el 2 y el 3 y
que los tiempos de intermitencia son un segundos encendido y tres apagados pues solo
tendramos que modificar cuatro parmetros para conseguirlo.
Nuevamente quiero resaltar, que un botn en programacin no funciona solo como un
interruptor de la luz es decir no interrumpe directamente la corriente , sino que solo es
un medio fsico que tenemos para indicar a la mquina que cambie el evento que est

ejecutando, por el siguiente evento previsto en el programa. En este caso programamos


cuatro eventos:
1 Luz apagada
2 Luz encendida fija
3 Luz intermitente
4 Repetir desde el principio
Esta sucesin de eventos, o algo similar como la eleccin de una opcin en un men de
ventana, siempre da lugar en programacin a una escalera de funciones condicionales
en la que en cada paso se pregunta si el evento seleccionado, es un elemento de un
tabla de opciones posibles, en cuyo caso de coincidir lo ejecuta, o en caso contrario,
baja un peldao preguntando nuevamente si es igual al siguiente elemento de la tabla y
as hasta que se agoten.

You might also like