Arduino y las interrupciones: primera aproximación

Cuando un programa tiene que esperar a que ocurra un evento (p.ej. que se pulse un interruptor), tiene dos formas de hacerlo:

  • polling: comprobar el estado del interruptor. Si se activa, hacer lo que sea, y mientras no se active, volver a comprobar. Es fácil de implementar, pero presenta el inconveniente de que, hasta que no se active el interruptor, el código se quedará estancado haciendo siempre lo mismo y sin poder hacer otra cosa.
  • interrupciones: ir a hacer otra cosa (mismamente a dormir, para ahorrar energía), y cuando ocurra el evento que le avisen. El aviso se hace mediante una interrupción: el micro recibe una señal en una patilla y acto seguido ejecuta una función que previamente se la ha indicado.

El uso de interrupciones a veces es conveniente, a veces no, a veces es imprescindible y a veces puede ser horrible, ya que se puede recibir una interrupción en casi cualquier momento (p.ej. mientras estamos procesando otra interrupción).

Un ejemplo con Arduino. El software.

Hay formas de evitarse estos problemas, pero de momento, voy a presentar el uso básico de las interrupciones, y además lo haré desde la perspectiva del IDE de Arduino: con las directrices de Wiring, y no manipulando los registros del AVR.

En este ejemplo, primero configuramos el microcontrolador para hacer algo cuando se reciba una interrupción determinada:

const unsigned short pinInt0=2;
void setup()
{
pinMode(pinInt0, INPUT);
Serial.begin(9600);
attachInterrupt(0,INT0_vector,RISING);
}

Lo más interesante es esto:

interrupción puede ser 0 o 1 para, respectivamente, INT0 o INT1 en Arduino Duemilanove. Arduino Mega dispone de otras cuatro interrupciones más (INT2..5). INT0 se corresponde con el pin digital 2, e INT1 con el 3.

función es la función que se ejecutará cuando se active tal interrupción. A veces se llama rutina de servicio de interrupción (Interruption Service Routine, ISR)

modo es qué se entiende por activación de la interrupción: cuando pasa a estar alta (RISING), cuando cambia de valor (CHANGE), cuando está baja (LOW) o cuando pasa a estar baja (FALLING).

Una vez ejecutemos esa función, cada vez que la patilla digital 2 (INT0) suba de nivel se ejecutará la función INT0_vector:

void INT0_vector()
{
moehren++;
}

que lo que hace es incrementar una variable global:

volatile unsigned short moehren=0;

Está declarada como volatile, para evitar que el compilador la mantenga en los registros del micro. Cada vez que se vaya a utilizar se leerá su valor de memoria, y cada vez que se escriba, se escribirá su valor en memoria.

Y mientras se reciben interrupciones, pues vigilamos a ver si cambia el valor:

void loop()
{
static unsigned short oldMoehren=999;
if(oldMoehren!=moehren) {
Serial.print(“Ich hab neue Moehren gekriegt!! Sie sind schon “);
Serial.println(moehren);
oldMoehren=moehren;
}
delay(600);
}

Si el valor anterior (oldMoehren) es distinto al actual, se manda un mensaje y se actualiza su valor. En cualquier caso, a continuación se espera durante 600ms.

Acabando el ejemplo: el circuito.

Una resistencia (la mía es de 5,6K porque la tenía a mano, pero una de 10K, 1K o valores similares también son válidas) conectada a 5V por un lado y a un interruptor al otro.
El otro extremo del interruptor va conectado a GND. Así, cuando se cierre el interruptor, circulará corriente por la resistencia y por el interruptor.
La resistencia causa una caída de tensión de los 5V. de diferencia que hay, por lo que, cuando el interruptor está abierto, ambos extremos de la resistencia están a 5V. ya que no circula corriente.
Cuando el interruptor se cierra, circula corriente y los 5V. caen en la resistencia, por lo que en el extremo de la resistencia que va conectado al interruptor el voltaje es 0V.
Si finalmente conectamos un cable desde ese punto al pin 2 (correspondiente a INT0), el resultado es que cada vez que el interruptor se abra, el voltaje en ese punto vuelve a subir de 0V. a 5V., pasando la línea INT0 de bajo a alto y lanzando la función INT0_vector().

Y finalmente, la prueba

Su ejecución con el circuito:

Ich hab neue Moehren gekriegt!! Sie sind schon 0
Ich hab neue Moehren gekriegt!! Sie sind schon 1
Ich hab neue Moehren gekriegt!! Sie sind schon 2
Ich hab neue Moehren gekriegt!! Sie sind schon 3
Ich hab neue Moehren gekriegt!! Sie sind schon 6
Ich hab neue Moehren gekriegt!! Sie sind schon 7
Ich hab neue Moehren gekriegt!! Sie sind schon 9
Ich hab neue Moehren gekriegt!! Sie sind schon 10
Ich hab neue Moehren gekriegt!! Sie sind schon 11
Ich hab neue Moehren gekriegt!! Sie sind schon 13
Ich hab neue Moehren gekriegt!! Sie sind schon 15
Ich hab neue Moehren gekriegt!! Sie sind schon 16

Cada vez que se suelta el interruptor, la patilla 2 vuelve a valor alto y se ejecuta la función, incrementando la variable moehren. Posteriormente en la siguiente ejecución de loop() se detectará el cambio de valor y se notificará por el puerto serie.

¿Qué ocurre si hay dos subidas de nivel antes de que se ejecute loop() de nuevo? Pues que el valor que se notifica se habrá incrementado en dos unidades, una por cada subida.

Arduino

Comments (0)

Permalink

Arduino + microSD: más funciones de la librería

Entre las funciones que aún no hemos visto están:
  • SD.usedBytes(<fichero>), que devuelve un long con los bytes empleados en el fichero. Es decir, los bytes desde el primero hasta el EOF, que para esta librería es el código ASCII 3.
  • SD.del(<fichero>), fija el primer byte del fichero a 0×03, es decir a EOF. Con esto la longitud del fichero pasa a ser 0, por lo que, a ojos de la librería, estará vacío y disponible para escribir. No borra el fichero, sólo su contenido. Y en realidad, tampoco borra todo su contenido: si después del del() y antes de escribir examinamos el fichero, veremos que se mantienen todos los contenidos, excepto el primer byte.
  • SD.startSector(<fichero>), retorna un long con el primer sector del fichero.
Y además, una serie de funciones interactivas que hablan (y escuchan) por el puerto serie, por lo que requieren que esté iniciado:
  • SD.ls(<fichero>), muestra en la terminal cuántos bytes y sectores tiene asignado el fichero, y cuántos bytes está utilizando.
  • SD.cat(<fichero>), vuelca por el puerto serie el contenido de fichero
  • SD.write(<fichero>), escucha por el puerto serie bytes hasta recibir un . (el punto normal y corriente). Guarda todo lo recibido en el fichero. No se hace eco de lo recibido.
  • SD.printEvent(<fichero>), manda un mensaje por el puerto serie informando de qué operación va a hacer o a hecho.
  • SD.append(<fichero>), añade al final del fichero lo recibido por el puerto serie hasta encontrar un punto. Se imprime lo recibido.
Lo mejor para hacerse una idea de cómo funcionan es jugar con el programa que suministran de ejemplo.

Arduino

Comments (0)

Permalink

Arduino + microSD: programación de la librería

Una vez que tenemos instalada la librería, que tenemos una tarjeta que funciona con la librería y que hemos probado que Arduino es realmente capaz de leer/escribir en ella, vamos a hacer nuestros propios programas.

En primer lugar, incluímos la interfaz de la librería:

#include “SDuFAT.h”

Esto nos proporciona un objeto llamado SD para acceder a la tarjeta.

Probablemente usemos el pin digital 8 para alimentar el shield, así que definimos una constante:

const unsigned short pinSDPower=8;

Y en la inicialización nos preocuparemos de alimentar el shield, poniendo a alto el pin 8:

pinMode(pinSDPower, OUTPUT);
digitalWrite(pinSDPower, HIGH);

Y, optativamente, silenciar los mensajes de la librería:

SD.verbose(OFF);

Por defecto, la librería arranca en modo parlanchín, por lo que cada vez que haya un error o haga algo, nos lo comentará mediante el puerto serie (que deberemos haber inicializado). Para activarlo o desactivarlo está el método SD.verbose(estado), siendo estado ON u OFF (constantes definidas en SDuFAT.h)
No he leído en ningún sitio que haya que dejarle tiempo para arrancar y no sé si hay que hacerlo.

Podemos usar el método SD.println(fichero, cadena) para añadir cadena al final de fichero, seguida de un salto de línea:

SD.println(“hola.txt”, “tengo hambre”);

O bien, sin salto de línea usamos la función print():

char pez[]=”quiero bananas”;
char glu[2];
for(int i=0; i glu[0]=pez[i]
glu[1]=0;
SD.print(“hola.txt”, glu);
}
SD.print(“hola.txt”, “\n”);

Los métodos print y println reciben siempre dos punteros a cadena de caracteres: uno para el nombre de fichero y otro para la cadena a imprimir. No se puede imprimir un caracter directamente, ni un entero ni un real. Con la implementación actual sólo se puede una cadena de caracteres.

En imprimir la frase letra por letra (15 bytes, 15 accesos de escritura), Arduino emplea 10 segundos. La velocidad de escritura es muy lenta porque la librería (creo yo, no he mirado la implementación en tanto detalle) debe recorrer todas las estructuras de datos de la FAT almacenadas en la microSD. Por lo que es mejor guardar lo que queramos imprimir en una cadena, y luego imprimir la cadena en el fichero. Además, mantener el número de escrituras al mínimo aumenta la vida de la tarjeta y podría, en mi opinión, ayudar a disminuir el consumo de corriente.

Arduino

Comments (0)

Permalink

Arduino + microSD: instalación de la librería

La gente de Libelium desarrollaron una librería para trabajar con este shield en el año 2008. Al parecer ahora David Cuartielles e Ino Schlaucher han adoptado el proyecto, aunque la realidad es que no hay mucho desarrollo en torno a él.

Una vez descargada, debe descomprimirse sobre el subdirectorio libraries/ de la instalación de arduino, y la próxima vez que iniciemos el IDE podremos utilizar con un simple #include “SDuFAT.h”.

Para probarla desarrollaron un pequeño programa que podemos compilar y subir al arduino. El programa está disponible en el propio ZIP de la librería, bajo el directorio examples/ (/libraries/examples). Lo tengo por aquí un poco modificado, porque había algún mensaje para el usuario que no estaba claro.

Antes de probarla, deberemos formatear la tarjeta microSD en formato FAT, si no lo estaba ya, y copiarle el fichero hola.txt que viene empaquetado con la librería (/libraries/hola.txt). La librería es limitada, por lo que no podemos crear un fichero nuevo, sino que escogemos uno ya creado, que podremos vaciar, añadirle nuevo contenido o leer. El tamaño de este fichero no es modificable por la librería, así que si se intenta escribir más allá del final del fichero, obtendremos un error.

Este programa, una vez quemado en al Arduino y ejecutándose, esperará órdenes del usuario vía el puerto serie. Mismamente con el Monitor de puerto serie del IDE de Arduino (Menú Tools/Serial Monitor, configurado a 9600, aunque en el ejemplo original se usan 19200 baudios) podemos enviar una ‘L’ para que nos muestre el tamaño del fichero hola.txt, y cuánto de él estamos utilizando. Otros comandos nos permiten ver el contenido del fichero, vaciarlo, añadirle contenido a voluntad, etc. La ‘H’ ofrece una breve ayuda.

Arduino

Comments (0)

Permalink

Arduino + microSD: el shield

Estos últimos días he estado jugando con el módulo microSD que venden en Libelium. Es un shield que permite añadir almacenamiento persistente a un Arduino mediante su bus ICSP.

En esencia, el módulo es una interfaz entre las patillas del bus y la tarjeta microSD. El resto de componentes son SMCs que juegan con la corriente, sin que haya ningún procesamiento intermedio de los mensajes, ni ninguna traducción entre el bus y la tarjeta.

El bus ICSP usa 6 patillas, aunque hay una variante de 10 patillas (y pareceser que para el ICSP esas cuatro patillas no aportan nada). Esas patillas son reloj (SCK), reset (SS), comunicación desde el AVR (MISO), comunicación hacia el AVR (MOSI) y las dos de alimentación.

El shield va conectado al Arduino con los pines digitales 9 (CD, Card Detection, no es ICSP, pero sí es de la tarjeta), 10 (SS, el reset), 11 (MOSI), 12 (MISO), 13 (SCK), el siguiente (14) que es GND, y el 8, si se pone alto, se puede usar para alimentar el shield (VCC).

No sólo se pueden usar esos pines, sino que en Arduino Duemilanove hay 6 pines junto al micro, al borde, a los que también se les puede conectar el shield, y que, de hecho, están puenteados con los de la fila lateral.

Arduino

Comments (0)

Permalink