Está en la página 1de 13

Arduino – Programar multitareas, controlar una

intermitencia y simultáneamente vigilar la


pulsación de un botón

Por Félix Maocho


27/2/2013
..

Objetivo de este post:


Enseñar 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

pulsación en continuada de dos pulsaciones contiguas. _________________

Los detractores del presidente Johnson, decían que no podía hacer dos cosas a la vez, por ejemplo,

andar y mascar chicle. Esta indudable maldad política, es un buen ejemplo para explicar lo que supone

hacer multitareas. Hasta la invención de los ordenadores con varios “cores“, o núcleos de procesador,

los ordenadores sólo tenían un procesador, y este, como el Presidente Jonson, solo podían hacer una

sola cosa a la vez, fuera andar o mascar chicle, pero no podían hacer ambas cosas simultáneamente. 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 fotografía

que habías terminado de retocar antes y por los baffles del PC, suena, (con ruido de lata), tu música

favorita. Es decir se están ejecutando tres tareas, capturar texto, imprimir, y emitir música 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 pequeñas 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 carácter 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 rápido, sobre todo mucho mñás rápido que los

dispositivos periféricos, teclado, impresora y altavoz, y el tiempo de parada de cada tarea es lo

suficientemente pequeñas 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 función 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 público” en detrimento

de los trabajos sin intervención humana. Si además estos no son críticos para el sistema aun pierden

mas prioridad y imprimir, era de los trabajos que no tenían necesidad de intervención humana, y no

eran críticos para el sistema, por lo que las impresoras antes, imprimían un poco a trompicones. A

medida que los relojes de los procesadores fueron cada vez más rápidos, 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 introducción histórica viene a cuento porque el procesador de

Arduino, debe tener hoy más o menos la capacidad que tenía un viejo PC y su reloj, no es muy rápido,

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 botón se enciende la luz, al volver a apretar el botón, pasa a ser
intermitentemente, de modo que que por ejemplo esta un 3 segundos apagado y 3 encendida y solo

apretando nuevamente el botón, apagamos definitivamente la linterna.

Hardware
Bien, pasemos a programar nuestro experimento. Comenzamos por fabricar el hardware en este

caso una linterna que no es más que unLED controlado por un PIN como ya hemos visto en post

anteriores,y un botón que recoge las pulsaciones que ejecutamos, algo que ya hemos efectuado en

capítulos anteriores, El esquema es el que abre el post, y su descripción 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 botón lo vamos a hacer del tipo PULL DOWN o sea que si no se pulsa el botón la tensión
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 pequeño cable rojo conecta el bus rojocon la pata izquierda del botón 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 pequeño 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 más larga (la positiva o cátodo) mientras que

unimos a la pata negativa una resistencia de 220 Ω suficiente para rebajar la tensión en la línea

a 3,5 volts más o menos que es a la tensión 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 botón.

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

Félix 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 público

https://felixmaocho.wordpress.com/?s=arduino

*/

// Arrea de definición 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

// Declaración del Hardware PINs utilizados

void setup() {

pinMode(ledPin, OUTPUT);

pinMode(buttonPin, INPUT);

// Loop donde se ejecuta el proceso

void loop(){

// leer el botón 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 botón 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 botón

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 botón

else{

// en el caso de que estemos en el evento 2 intermitencia y no se haya apretado el botón

// 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 botón 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 botón.

A continuación definimos como vamos a atizar el Hardware, en este caso el PIN “buttonPin”, o sea el 7

se va a utilizar para controlar el botón 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 tensión (LOW) señal que no se pulsó el pulsador o que la tenga (HIGH) y guardar el

valor en “buttonState”.

Si se ha apretado el botón (buttonState iguala HIGH) y:

Estábamos en el “evento 0” (inicio, todo apagado), nos toca encender la luz, (digitalWrite HIGH). Como

eso es casi inmediato añado un tiempo (delay) de 500 milisegundos (medio segundo) para que de

tiempo a retirar el dedo del botón 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 botón

Si “evento =1” Estábamos 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” Estábamos en el “evento 2” (LED intermitente) nos toca apagar el LED, (digitalWrite

LOW). Como eso es casi inmediato añado un tiempo delay) de 500 milisegundos (medio segundo) para

que de tiempo a retirar el dedo del botón 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 botón. 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 continuación veremos que responde perfectamente a encender el LED, y a

ponerlo intermitente, pero que cuando la luz esta intermitente es difícil 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 más del

medio segundo programado, la maquina después 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 simultáneamente 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 botón y los pares a la tarea de ir adelantando el evento que corresponda

ejecutar. los el evento 0 (esperar a que toquen el botón), el 1( encenderle LED ) y el 3 (apagar el LED y

dejarlo todo como a la entrada, son muy rápidos 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 botón sea el tiempo que sea , así que el de

disparador de iniciar un nuevo evento será primero detectar que se ha pisado el botón y segundo que se

ha soltado.

Mejora para el control de l ùlsado de el botón

Así pues, pondremos un bucle corto que compruebe si el botón 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 hacíamos para prolongar la duración de los

eventos rápidos y habrá menos interpretaciones erróneas.

Por otra parte para aumentar la velocidad de ejecución 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 ejecución del bucle mientras ejecuta este evento, será similar al de los otros eventos, es

decir será muy rápido

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

Félix Maocho

Este ejemplo explica como se simula un multiproceso

y corrige el error existente en el proceso anterior llamado

Linterna_erroneo

Es de dominio público

https://felixmaocho.wordpress.com/?s=arduino

*/

// Arrea de definición 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 botón 2 = avanza un ciclo el evento

int pulsado = 0; // 0 = botón no pulsado 1 = botón 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

// Declaración 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 botón

vuelta = 2; // la próxima vuelta par

buttonState = digitalRead(buttonPin); // leer y guardar el valor obtenido en “buttonState”

if (buttonState == HIGH) { // si “pulsado” 0 y buttonState es HIGH, nueva pulsación

if (pulsado == 0) {

pulsado = 1; // poner pulsado a 1


}

else { // si han dejad de pulsar pero habían pulsado previamente

if (pulsado == 1) {

evento = evento +1; // cambiar de evento

pulsado = 0; // poner pulsado a 0 para la próxima vez

else { // vuelta par. Avanzar el evento que corresponda

vuelta = 1; // la próxima 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 código,

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 físico. Algo que estamos acostumbrados, nuestro ordenador funciona mejor y más 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, según la importancia que demos a las tareas o lo crítico de su funcionamiento. Por el

ejemplo, el vídeo y la música 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 definición 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 botón 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 había pulsado , “pulsado” = 0, y ahora la lectura de HIGH se ha pulsado el botón,

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 botón y cambiamos de evento a ejecutar, ponemos “pulsado” cero para

prepararlo para la siguiente pulsación.

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 2″fin 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 botón y controlar las luces), y que por ninguna

bifurcación del programa puede existir un trabajo en que dure tanto que impida el correcto

funcionamiento de los demás 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 ejecución 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 botón 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 aproximación, 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.

También 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 parámetro 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 línea

por línea todo el texto del programa cambiando 2000 por 2500.

Por este motivo un programa bien parametrizado es fácil de adaptar a cambios, por ejemplo en este es

muy fácil 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 tendríamos que modificar cuatro parámetros para

conseguirlo.

Nuevamente quiero resaltar, que un botón en programación no funciona solo como un interruptor de la

luz es decir no interrumpe directamente la corriente , sino que solo es un medio físico que tenemos para

indicar a la máquina 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 sucesión de eventos, o algo similar como la elección de una opción en un menú de ventana,

siempre da lugar en programación 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 peldaño preguntando nuevamente si es igual al

siguiente elemento de la tabla y así hasta que se agoten.

Un pequeño video muestra el funcionamiento correcto de este segundo programa

En él se ve como se suceden las tres fases e encendido fijo, luz intermitente, apagado y en espera, y

como tanto da que la pulsación sea rápida o continuada la máquina interpreta siempre una sola

pulsación.

También podría gustarte