Está en la página 1de 13

Leccin 17: Funciones de tiempo

En la leccin anterior (Leccin 16) descubrimos los problemas que resultaban de utilizar la
funcin delay(). Cuando tenemos un cdigo de varias lneas que contiene una instruccin
delay(1000) para esperar a que pase un segundo, nos encontramos que nuestro Arduino est
inoperativo la mayor parte del tiempo. Ejecutar el resto del cdigo le puede llevar apenas unos
milisegundos y tiene que estar esperando el resto del tiempo sin capacidad de responder a
ninguno de los eventos que suceden a su alrededor. Por esa razn, nuestros pulsadores para
cambiar la hora, minuto y segundo no respondian de forma satisfactoria.
Adems, en la leccin 2 tuvimos ocasin de ver cmo se usaba tambin una instruccin delay()
para lograr intermitencias de leds. Seguro que el lector ha visto ejemplos similiares en muchos
otros cursos de Arduino. Sin embargo esta tcnica tiene un segundo problema aadido al
mencionado. Supongamos que queremos generar intermitencias en varios leds con frecuencias
diferentes (uno parpadea cada un segundo y otro cada dos y medio, por ejemplo).
Evidentemente utilizando la tcnica de la funcin delay() es imposible.

Por eso, en esta leccin vamos a abordar la construccin de funciones de tiempo con una
filosofa diferente que solucione los dos problemas anteriores. Empezaremos, como es habitual
en este curso, con un mnimo de teora. El primer concepto importante para entender las
funciones de tiempo es el de "timer". En general, todos los microprocesadores tienen disponibles
varios temporizadores (timer). En concreto el Arduino Uno tiene tres: timer0, timer1, timer2. Un
timer no es ms que un contador cuya entrada est conectada al reloj del sistema y que nos
permite "contar" los tics (ciclos de reloj) que han transcurrido.
Nota aclaratoria: Por defecto la seal que van a contabilizar los timers corresponde a la
frecuencia del oscilador dividida por cuatro. Por lo tanto, en realidad cuentan ciclos mquina, no
ciclos de reloj. Con un reloj de 20 Mhz tendramos una frecuencia de ciclos mquina de 20/4 = 5
MHz, por lo que un ciclo mquina corresponde a 0.2 usec. En principio, el contador del timer de

un micro que funcione a 20Mhz se incrementar cada 0.2 microsegundos o 5 veces en 1 usec.
De todas formas, el lector podr comprobar que con el mtodo propuesto en esta leccin puede
olvidarse de estas consideraciones.

El segundo concepto que necesitamos conocer para construir nuestras funciones de tiempo, es
el de interrupcin de timer. Bsicamente, todos los microprocesadores nos permiten generar
interrupciones asociadas a los timer. Eso significa que podemos configurar nuestro Arduino para
que se genere una "interrupcin" cada vez que un timer ha contado un nmero concreto de tics.
Como sabemos la frecuencia con la que se produce cada tic, evidentemente, podemos decir que
se genere una interrupcin cada vez que hayan transcurrido una serie de "unidades de tiempo"
determinadas. Estas "unidades de tiempo" pueden ser microsegundos, milisegundos,
centsimas, dcimas o segundos. La gran ventaja de utilizar interrupciones, es que todo el
cdigo que se est ejecutando se detiene cada vez que se produce una interrupcin y se ejecuta
el cdigo que hayamos escrito para "atender" a la interrupcin. Por ello la precisin obtenida es
muy grande.

Por lo tanto, con los timer y las interrupciones podemos lograr construir un reloj (con la precisin
que necesitemos acorde a nuestras necesidades) independiente del cdigo de nuestro programa
y no sujeto a que el micro est con ms o menos carga de trabajo. La tcnica propuesta consiste
en mantener un "reloj maestro" que sepa exactamente el tiempo transcurrido en cada momento
y utilizar tantos "relojes secundarios" como sea necesario para cada una de las tareas
temporizadas que queramos llevar a cabo de forma independiente.

Por defecto, Arduino utiliza el timer0 para las funciones de tiempo incorporadas por el software
bse: delay(), millis() y micros(). El timer1 lo utiliza la librera servo. Y el timer2 lo utiliza la
funcin tone(). Por lo tanto, el usuario que no profundice ms puede llegar a pensar que su
utilizacin para los fines que pretendemos est comprometida a menos que sacrifiquemos
alguna de las funcionalidades mencionadas. Para evitarlo, la solucin ser aprovechar la funcin
millis() para implementar nuestro reloj maestro en el que se basan las funciones de tiempo.
Bsicamente, la funcin millis() nos devuelve el tiempo en milisegundos transcurridos desde que
se arranco la placa Arduino con el programa actual. Por lo tanto Arduino ya nos facilita el reloj
maestro. La funcin millis() nos devuelve un unsigned long, es decir un nmero de 32 bits. As
que todos nuestros relojes secundarios deben utilizar variables de este mismo tipo. Puesto que la
funcin millis() cuenta milisegundos, la precisin de nuestros relojes secundarios ser,
precisamente de un milisegundo (ms que suficiente para la mayora de los proyectos
habituales).

La primera funcin que vamos a escribir se llamar iniTemp() y se encarga de arrancar un


cronmetro (reloj secundario) indicando el tiempo que deseamos que se cuente. La segunda
funcin ser chkTemp() y nos dir los milisegundos que restan para que el cronmeto alcance el
tiempo deseado.
El cdigo de ambas funciones es el siguiente:

Antes de utilizar estas dos funciones y ver con detalle cmo estn escritas, vamos a construir
una tercera, a la que llamaremos parpadeo() y que utiliza las dos anteriores para generar una
intermitencia de una frecuencia determinada. Su cdigo es el siguiente:

Ahora veamos un ejemplo de su uso. En primer lugar, el esquema electrnico que vamos a
utilizar en nuestra leccin es muy sencillo. Nuestro Arduino y dos leds para hacer las pruebas.

Y el cdigo de nuestro programa:

Cada vez que utilicemos la funcin intermitencia() necesitamos pasarle cuatro parmetros. El
primero es una seal que indica cuando debe ejecutarse la funcin (in) y llevar a cabo la
intermitencia. En nuestro ejemplo, como deseamos que la intermitencia se est generando sobre
el led todo el tiempo, escribimos directamente un 1. Si quisiramos que la intermitencia se
produjera slo cuando se cumpliera una determinada condicin, utilizaramos este primer
parmetro para llevar a cabo esta tarea slo cuando se cumpla la condicin deseada.
El segundo parmetro es el tiempo en milisegundos que permanecer alto (y, por lo tanto,
tambin bajo) nuestra cadena de pulsos intermitentes. En nuestro caso para el led situado en el
pin IO2 hemos fijado como tiempo 1000 mseg y para el led situado en el pin IO3 hemos fijado
como tiempo 2500mseg.
El tercer parmetro es una variable auxiliar de trabajo que utilizaremos para almacenar nuestro
cronmetro. Debe ser del tipo unsigned long como explicamos antes. Hemos creado las variables

temporizador1 y temporizador2 para este fin. La primera la utilizamos para un led y la segunda
para el otro.
El cuarto y ltimo parmetro es una variable auxiliar que utilizamos para indicar el estado de
nuestra salida de la intermitencia. Es la variable que usamos para indicar si el led se iluminar o
apagar, segn el momento de la intermitencia en que nos encontremos. Hemos utilizado las
variables intermitencia1 e intermitencia2 para este fin. La primera la utilizamos para un led y la
segunda para el otro.
El cdigo de nuestro bucle principal, loop(), no puede ser ms sencillo. Dos llamadas a la nueva
funcin intermitencia() y dos sentencias para escribir el resultado que nos devuelven para
activar o desactivar las salidas donde se conectan nuestros leds. Ejecutamos la compilacin y
simulamos nuestro programa. Podemos comprobar que hay dos intermitencias a frecuencias de
1 y 2,5 segundos que no se interfieren una con la otra.

Conviene aqu que dediquemos un momento a estudiar el cdigo de la funcin parpadeo() y


algunas tcnicas de programacin utlizadas en l.

En primer lugar, utilizamos AND y NOT en lugar de && y !. La razn es que en la zona superior
del cdigo hemos utilizado tres sentencias #define para fijar las definiciones de AND, NOT y OR y
utilizar estos nombres ms intuitivos que &&, || o !.

En segundo lugar las variables auxiliares crono y out las hemos utilizado precedidas de un
asterisco. Esto signfica que estamos utilizando punteros a las variables en lugar de las propias
variables. El puntero indica la direccin que ocupa una variable. As, el cdigo de la misma
funcin puede ser utilizada diversas veces con temporizadores diferentes sin que entren en
conflicto unos con otros. Por eso cuando utilizamos la funcin parpadeo la llamamos utilizando
como parmetros las variables precedidas del smbolo &.

El cdigo de la funcin realiza lo siguiente. Si el parmetro IN es verdad (lanzador de la funcin)


y el cronomtro ya ha cumplido su tiempo (la primera vez que se utiliza la funcin es siempre es
as por el reloj maestro siempre es mayor que 0 que es el valor del cronmetro en ese momento)
arrancamos nuestro cronmetro con el tiempo establecido en el parmetro TIEMPO y ponemos
alto el parmetro utilizado para indicar el estado de la intermitencia -OUT-. Si no es verdad
ponemos bajo el parmetro OUT para indicar el estado de la intermitencia.
Para arrancar y comprobar el estado de nuestro cronmetro hemos utilizado las otras dos
funciones auxiliares que hemos creado initTemp() y chkTemp(). La primera asigna a la variable
que utilizamos como cronmetro el valor actual devuelto por la funcin millis() -nuestro reloj
maestro- ms el tiempo que deseamos controlar y que le pasamos a la funcin como parmetro.

La segunda comprueba si el valor almacenado en nuestro cronmetro es mayor que el reloj


maestro -la funcin millis()- y devuelve un cero si ya ha transcurrido el tiempo o el valor en
milisegundos que falta, en caso contrario.

El cdigo de una nueva funcin retraso() que sustituya a la estndar delay() pero que no paraliza
a nuestro Arduino mientras se ejecuta, se muestra a continuacin como otro ejemplo de las
funciones temporales que podemos escribir. Tambin se apoya en el uso de las funciones iniTemp
y chkTemp, que siempre son la base de todas las dems.

Dejamos como problema para el usuario, corregir el programa de la leccin anterior para que los
botones de nuestro reloj ya estn activos todo el tiempo. Esperamos que vuestras soluciones las
compartis en nuestro facebook (https://www.facebook.com/pages/HuborProteus/294446180592964?ref=hl).
A continuacin, vamos a mostrar, como ejemplo final, el cdigo de una nueva funcin llamada
pulso() que permite generar un pulso de una duracin determinada siempre que se cumpla una
determinada condicin. De esta manera tenemos otro ejemplo de funciones de tiempo que
podemos construir con ayuda de nuestra tcnica de cronmetro maestro y cronmetros
derivados. De la misma forma no nos resultar difcil construir otras que se adapten a nuestras
necesidades concretas de cada proyecto.

No queremos terminar sin hacer dos consideraciones importantes. La funcin millis() utiliza,
como ya mencionamos, nmeros de 32 bits. Como cada unidad es un milisegundo, eso significa
que nuestro cronmetro puede contar hasta 4.294.967.296 mseg = 4.294.967 seg = 71.582 min
= 1.193 horas = 49 das.
Es decir que cada 49 das nuestro reloj maestro se reiniciar a cero. En la prctica, suele ser
suficiente y no tendremos problemas. Pero es posible que en ciertos proyectos tengamos que
tener esta circunstancia en cuenta porque un retraso, un pulso o un parpadeo que se produzca
justo en el momento en que se reinicia el reloj maestro podra no funcionar correctamente. Si en
nuestro proyecto se diera este caso, podemos solucionar el problema utilizando dos variables
unsigned long combinadas.
La segunda consideracin es que la precisin de nuestro cronmetro es de un milisegundo. Si
necesitramos precisiones mayores (de hasta un microsegundo) podemos utilizar la funcin
micros() que devuelve microsengundos transcurridos en lugar de milisegundos como hace la
funcin millis(). En este caso la limitacin mxima temoral es de unos 70 minutos.
Esperamos que esta leccin le haya resultado til e interesante.

También podría gustarte