h1

Un registro SIPO para el rey

2 junio 2009

Nuestro rey posee catorce puertos de entrada/salida digitales que pueden ser más que suficientes para muchas aplicaciones, pero ¿y si necesitamos más? Supongamos por ejemplo que tenemos las entradas analógicas ocupadas y deseamos controlar una matriz de leds de 8×8, para lo cual necesitamos 16 puertos, o que sólo tenemos dos puertos libres y necesitamos un contador binario de 8 bits. En ambos casos nos veríamos ante dos alternativas: adquirir el Ardiuno Mega, con 54 puertos digitales, o utilizar hardware adicional. En mi caso, como poseo el Duemilanove y poco presupuesto, voy a optar por la segunda de dichas alternativas para obtener el contador binario de 8 bits.

Una de las opciones es emplear un dispositivo que permita leer datos en serie y pueda mostrarlos en paralelo. Nos referimos a un registro Serial In – Parallel Out o SIPO. Uno de estos dispositivos es el circuito integrado 74164, un SIPO de 8 bits , cuyo símbolo puede observarse en la siguiente imagen. Las patillas 7 y 8, que no aparecen en el mismo, son las de alimentación, GND y Vcc, 0 V y 5 V, respectivamente.

74164NEl funcionamiento y sus características pueden consultarse en su hoja de datos. Seguidamente describimos las más importantes para entender su funcionamiento.

Qi (patillas 3, 4, etc.): las 8 salidas del dispositivo.

CLEAR (patilla 9): entrada de puesta a cero de todas las salidas. Al poner un nivel lógico bajo, todas las salidas Qi quedan a bajo.

S1 y S2 (patillas 1 y 2): entradas de datos. El dato que se almacena es el producto lógico, AND, de ambas.

CLOCK (patilla 8): entrada de sincronismo. A cada flanco de subida, paso del nivel bajo al alto, el producto lógico de S1 y S2 se almacena en Q0. El valor que había en Q0 se desplaza a Q1, el de éste a Q2, el de Q2 a Q3, etc., y el de Q7 se pierde.

Un resumen de todo ello se puede ver en la siguiente tabla.

tabla-74164

La siguiente imagen representa el esquema de conexión a la placa Arduino que utilizaremos.

arduinoSIPO

Observe como el pin 13 de Arduino será quien genere los impulsos de sincronismo y el 12 quien dé los datos que serán almacenados en el registro. De este modo estamos controlando con sólo dos puertos los 8 bits del registro SIPO.El funcionamiento se puede comprobar con el siguiente ejemplo.
int serialInput = 12; // a los pines 1 y 2 del SIPO
int clockInput = 13; // al pin 8 del SIPO
void setup() {
pinMode(serialInput, OUTPUT);
pinMode(clockInput, OUTPUT);
}
// ************PROGRAMA PRINCIPAL************
void loop() {
for (int k=1; k<9; k++){
digitalWrite(serialInput, HIGH);
digitalWrite(clockInput, LOW);
digitalWrite(clockInput, HIGH);
delay(150);
}
delay(500);
for (int k=1; k<9; k++){
digitalWrite(serialInput, LOW);
digitalWrite(clockInput, LOW);
digitalWrite(clockInput, HIGH);
delay(150);
}
delay(500);
}

Se trata de mandar mediante sendos bucles, ocho impulsos a intervalos de 150 ms para almacenar niveles altos y bajos. Entre ambos bucles se ha introducido un retardo de 500 ms. El resultado, como puede verse en el siguiente vídeo, proporciona un desplazamiento desde Q0, led más a la derecha, a Q7, led más a la izquierda, de niveles altos y bajos.

Para el contador binario no resulta profesional dar los impulsos de sincronismos poniendo primero a bajo y  acontinuación a alto el clockInput 8 veces cada vez que deseamos escribir un dato de 8 bits, esto es un octeto o byte. Para ello, Arduino tiene la función shiftOut() cuya sintaxis es la siguiente:

shiftOut(dataPin, clockPin, bitOrder, value)

donde:

  • dataPin: terminal que mandará los datos al registro. En nuestro caso el 12, al que hemos denominado serialInput.
  • clockPin: terminal por donde se enviarán los impulsos de sincronismo. En nuestro esquema el 13, denominado clockInput.
  • bitOrder: modo en el que se desplazarán los bits en el registro. Si primero se debe almacenar el bit más significativo, MSB, caso del 74164, hay que poner el valor MSBFIRTS. En el caso de que el primer bit que se almacena sea el menos significativo, LSB, se pondrá LSBFIRTS.
  • value: valor, de tipo byte, que se desea escribir.

El programa, sencillo, es el siguiente:

int serialInput = 12;
int clockInput = 13;
void setup() {
pinMode(serialInput, OUTPUT);
pinMode(clockInput, OUTPUT);
}
// ******************PROGRAMA PRINCIPAL******************
void loop() {
//Puesta a cero
shiftOut(serialInput, clockInput, MSBFIRST, 0x00);
delay(3000);
for (int k=0; k<256; k++){
shiftOut(serialInput, clockInput, MSBFIRST, k);
delay(150);
}
}

Y su resultado este:

Anuncios
h1

Audiencia al embajador de Processing

15 mayo 2009

Una de las posibilidades más atractivas que posee Arduino es poder comunicarse con otros programas, y si estos son libres, mejor que mejor. El IDE de Arduino está basado en el de Processing, un lenguaje y entorno de programación en código abierto basado a su vez en Java, utilizado por artistas y diseñadores gráficos.

Aprovechando el divisor de tensión, ddt, con LDR de la entrada anterior, queremos que al acercar o alejar la mano del circuito, un círculo cambie su tamaño y su color. En este vídeo podemos ver lo que queremos.

Para conseguir nuestro objetivo necesitaremos dos programas: uno para Arduino, que deberá leer los valores del ddt y escribirlos en el puerto USB o serie virtual, y otro para Processing que deberá leer dichos valores y operar en consecuencia.

El programa de Arduino es muy sencillo. Aquí tenemos su listado:


int ldrPin=3;
void setup(){
Serial.begin(9600);
}
void loop(){
int val=analogRead(ldrPin);
Serial.print(val,BYTE);
delay(75);
}

Veamos sus líneas principales, de las cuales, las dos primeras ya las hemos visto anteriormente:

  • Serial.begin(9600): configura la velocidad de transmisión del puerto; en este caso 9600 baudios.
  • analogRead(ldrPin): lee el valor del ddt conectado al pin 3. Dicho valor, comprendido entre 0 y 255, se almacena, en la variable val.
  • Serial.print(val. BYTE): envía el valor de la variable val al puerto en formato byte.

El programa para Processing es algo más complicado y lo vamos a analizar por partes. Aquí tenemos sus primeras líneas:


import processing.serial.*;
String portname = "/dev/ttyUSB0";
Serial port;
int valorUSB;
int valorMin=62;
int valorMax=240;

  • import processing.serial.*: carga la librería necesaria para la comunicación con el puerto serie.
  • String portname = “/dev/ttyUSB0”: se asigna a la variable portname el nombre del puerto al que está conectado nuestro Arduino. Este nombre lo podemos ver marcado desde la barra de menú Tools==>Serial port en el IDE de Arduino. En mi máquina ese nombre es ttyUSB0, muy familiar para quienes trabajamos libremente con GNU/Linux.
  • Serial port: crea un objeto denominado port de la clase Serial.
  • valorUSB, valorMin, valorMax: variables para almacenar los valores presente en el puerto, mínimo y máximo respectivamente. Los dos últimos dependerán de la luz ambiental que tengamos por lo que habrá que ajustarlos como se detalla más delante.

La función setup() se ejecuta al arrancar el programa y en ella se incluyen las características que se desean.


void setup() {
size(300, 300);
stroke(255);
smooth();
port = new Serial(this, portname, 9600);
}

  • size(300, 300): define la dimensión de la ventana, en nuestro caso de 300×300 píxeles.
  • stroke(255): proporciona el color del borde del círculo. El  valor 255 se corresponde con el blanco.
  • smooth(): suaviza el borde del círculo mejorando su aspecto visual.
  • port=new Serial(this, portname, 9600): se asigna a port un nuevo objeto denominado Serial. La opción this hace referencia al propio objeto. De este modo se abre el puerto al que está conectado la placa a una velocidad de 9600 bps.

La función draw() se ejecutará continuamente como un bucle infinito:


void draw() {
background(0);
int valorColor= 255*(valorUSB-valorMin)/(valorMax-valorMin);
fill(valorColor,255-valorColor,255);
int radio = height*(valorUSB -valorMin)/(valorMax-valorMin);
ellipse(width/2,height/2,radio,radio);
if (port.available() > 0) {
valorUSB = port.read();
}
println(valorUSB);
}

  • backgroun(0): define el color de fondo de la ventana. El valor 0 se corresponde con el negro.
  • valorColor: esta variable permitirá cambiar el color del círculo. La fórmula ajusta los valores desde 0 a 255.
  • fill(): establece el color de relleno del círculo. Dicho color viene definido por defecto en términos RGB. Al dejar el tercer parámetro fijo a 255, las variaciones se corresponden con distintos tonos desde el azul al rosa, como se aprecia en el vídeo. Se puede cambiar el orden de estos tres prámetros para obtener otros colores.
  • radio: valor del radio. La fórmula permite que varía desde 0 hasta el alto de la ventana.
  • ellipse(): dibuja una elipse en la ventana. En nuestro caso será un circulo puesto que los dos últimos parámetros son iguales al valor de radio. Los dos primeros, width/2 y height/2 proporcionan las coordenadas de su centro, que se correponden en esye caso con el centro de la ventana. Las constantes width y height se corresponden con los valores, en píxeles del ancho y alto de la ventana, respectivamente, en nuestro caso 300 y 300, definidos en size().
  • if(port.available()>0): si el dato está disponible…
  • valorUSB=port.read(): … lee su valor y lo almacena en la variable valorUSB.
  • println(valorUSB): muestra en el IDE el valor leído. Esto nos permitirá obtener las asignaciones a la variables valorMin y valorMax.

El programa funciona, descárguelo desde este enlace y compruébelo. Alguna vez se me ha bloqueado el puerto y he tenido que reiniciar el ordenador. También he observado que si ela prueba se hace en un ambiente donde la luz varía constantemente, sobre todo si esa luz proviene de fluorescentes, las variaciones de tamaño y color son demasiado bruscas.

h1

Su majestad ve mi mano

6 mayo 2009

En la anterior entrada vimos como crear sencillas melodías con las ocho notas musicales básicas. En este caso vamos a intentar que el rey Arduino de Ivrea “vea” nuestra mano y toque una nota diferente en función de lo cerca o alejada que se encuentre de su majestad.

Para ello vamos a utilizar un circuito muy sencillo y bien conocido por los estudiantes de electricidad o electrónica: el divisor de tensión, ddt. Se trata de dos o más resistencias conectadas en serie. En la figura de la izquierda se muestra este circuito en su versión más sencilla. Fácilmente se puede demostrar que la tensión en bornes de R2, Vout es:

Ecuación de salidaPara nuestro ejercicio conectaremos Vin a 5 V,  Vout a uno de los puertos analógicos de entrada, tomaremos una resistencia de 1 kΩ para R1 y sustituiremos R2 por un fotoresistor o ldr, un componente cuyo valor resistivo varía con la intensidad luminosa de modo que a mayor luz menor resistencia. De este modo al acercar o alejar nuestra mano, la sombra hará que varíe su resistencia y por lo tanto Vout.

Antes de realizar el programa principal necesitaremos conocer de qué orden es la variación mencionada, variación que dependerá, obviamente de la luz ambiental de donde nos encontremos. Para ello probaremos el siguiente programa.

int ldrPin = 3;
int valor = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
valor = analogRead(ldrPin);
Serial.println(valor);
delay(250);
}

Según se puede deducir, se tomará el pin 3 para conectar al punto Vout del ddt y se declara la variable “valor” para almacenar su lectura. Esto último se consigue con el comando analogRead(ldrPin), el cual proporciona valores en función de la tensión presente en el pin 3, valores que estarán comprendidos entre 0, para 0 V, y 1.023, para 5 V. Para poder visualizarlos, primero hay que configurar la transmisión serie con Serial.begin(9600), donde 9600 es el valor en baudios típico, y a continuación imprimirlos en el Serial Monitor con Serial.println(valor). Hay que recordar que una vez arrancado el programa, para ver los valores hay que hacer clic en el icono Serial Monitor para activarlo. En este video puede verse la captura de pantalla mostrando valores cada 0,25 s, tiempo regulado por el comando delay(250).

En mi caso observo al alejar y acercar la mano unos valores respectivos que van desde el 642 al 790. Estos valores puedo oírlos con el siguiente programa al que denomino LdrAudible.
int ldrPin = 3;
int zumbadorPin = 11;
int valor = 0;
void setup() {
pinMode(zumbadorPin, OUTPUT);
}
void loop() {
valor = analogRead(ldrPin);
digitalWrite(zumbadorPin, HIGH);
delayMicroseconds(valor);
digitalWrite(zumbadorPin, LOW);
delayMicroseconds(valor);
}

Para ello se conecta el zumbador en el pin 11 y se declara como salida. El programa principal consiste en leer los valores visualizados anteriormente y mandar niveles altos y bajos con retardos en microsegundos de los mismos.

El programa que pretendíamos lo llamo LdrNotas, en el que se declaran las siguientes constantes y variables

int ldrPin = 3;
int zumbadorPin = 11;
int valor = 0;
int tiempo=300;
int valormin=742;
int valormax=790;
int intervalo=(valormax - valormin)/8;

Observe que, como vamos a disponer de 8 notas, la constante “intervalo” nos servirá para proporcionar a cada una de ellas un rango similar de valores. Esto se consigue mediante la función if y los else if anidados como puede verse en el siguiente listado incompleto.

void loop() {
valor = analogRead(ldrPin);
if (valor <= valormin){
tocarNota('c', tiempo);
Serial.println("Do");
}else if (valor >=valormin && valor <= valormin + intervalo){
tocarNota('d', tiempo);
Serial.println("Re");
}else if (valor > valormin + intervalo && valor <=valormin + 2*intervalo){
tocarNota('e', tiempo);
Serial.println("Mi");
............................................................
delay(200);
}

De este modo conseguimos que cada 200 ms toque una nota que dependa de lo cerca o lejos que pongamos la mano de la fotoresistencia. Los comandos del tipo Serial.println(“nota”) permitirán mostrar por el monitor la nota que está sonado en cada momento. Se recuerda de nuevo que para poder verlas hay que hacer clic en el icono Serial Monitor para activarlo. El programa completo puede descargarse desde este enlace. En el mismo observará la función tocarNota(), que lleva asociada la función tocarTono(), que ya fueron explicadas anteriormente. Y no diremos más. Veamos finalmente como su majestad toca al ver mi mano.

h1

El rey puede cantar

7 abril 2009

Es muy probable que Arduino de Ivrea disfrutara con la música y entra dentro de lo posible que alguna vez cantara. De lo que no tenemos duda es que el sistema Arduino puede “cantar”, eso ya lo hemos comprobado quienes tenemos uno. Basta con cargar el programa Melody que viene como ejemplo dentro del directorio Digital y conectar un zumbador piezoeléctrico en el puerto apropiado.

¿Y qué sucede cuando queremos programar nuestras propias melodías y tenemos conocimientos limitados en programación y nuestro solfeo se limita a poner con dificultad la escala musical en un pentagrama? No hay problema, tenemos gran parte del conocimento humano disponible desde casa, sólo nos hace falta un poco de entusiasmo y ganas para dar con la solución. Pongámonos un desafío: tocar el “Himno de la alegría“. En un principio pensé en la “Marcha imperial“, pero aún faltan unos años para que pase al dominio público. Aprovecho para pedir a los compositores que en lugar del poco solidario y asfixiante copyright, licencien su música bajo Creative Commons. De todos modos, gente con menos escrúpulos que yo ante las licencias ya han realizado esta melodía. En este vídeo podemos escucharlo.

Siguiendo con nuestro objetivo, trataremos de tocar las primeras notas, justo las que acompañan a los siguientes versos (desde este enlace es posible oirlo):

Escucha, hermano, la canción de la alegría,
el canto alegre del que espera un nuevo día.

Tras analizar el código fuente de Melody observo que cada una de las notas musicales se representa con un símbolo y se corresponde con una determinada frecuencia. En la siguiente tabla tenemos la equivalencia.

Nota Símbolo Frecuencia (Hz) Período (μs) Anchura del pulso(μs)
do c 261 3830 1915
re d 294 3400 1700
mi e 329 3038 1519
fa f 349 2864 1432
sol g 392 2550 1275
la a 440 2272 1136
si b 493 2028 1014
do C 523 1912 956

Tras indagar por la Red, compruebo que estos valores son bastante comunes y sólo encuentro ligeras diferencias, por lo que los doy por válidos. Mediante señales digitales y modulando su anchura de impulso, PWM, podemos conseguir las diferentes notas. Como sabemos, Arduino dispone de 14 puertos de salida digital de los cuales seis proporcionan PWM: 3, 5, 6, 9, 10, y 11.

Tomando como base Melody creo NotasMusicales, un programa que emite todas las notas anteriores en orden ascendente primero y descendente a continuación, que desde este enlace puede ser descargado. Seguidamente pasamos a describir su código.

// ****************DECLARACIÓN DE VARIABLES****************
int zumbadorPin = 11;
int N = 17;
char notas[] = "cdefgabCCbagfedc ";
int golpes[] = { 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 4 };
int tempo = 300;

  • zumbadorPin: puerto al que ha de conectarse el zumbador piezoeléctrico.
  • N: número de notas que contiene la melodía más uno.
  • notas[]: variable matricial con cada una de las notas de la melodía. Sería como la partitura de nuestra melodía. Debe terminar en un espacio en blanco, que será el símbolo utilizado para indicar que la melodía ha finalizado.
  • golpes[]: contiene los valores que, multiplicados por tempo, nos dará la duración de cada una de las notas. Debe tener tantos valores como el asignado a N.
  • tempo: constante que se utilizará para multiplicar los distintos valores que contenga golpes[] y obtener de este modo su tiempo.


void setup() {
pinMode(zumbadorPin, OUTPUT);
}
// ******************PROGRAMA PRINCIPAL******************
void loop() {
for (int i = 0; i < N; i++) {
if (notas[i] == ' ') {
delay(golpes[i] * tempo);
}
else {
tocarNota(notas[i], golpes[i] * tempo);
}
delay(tempo / 2);
}
}
Tras configurar zumbadorPin como salida, el programa principal consta de un bucle que se repetirá N+1 veces y que llamará N veces a la función tocarNota(x, y), con un valor de x igual a una de las notas de la partitura, y uno de y que será el resultado de multiplicar tempo, 300, por el valor asignado en golpes[] a la nota correspondiente. Al llegar al espacio en blanco, notas[i]==’  ‘, se hará un retardo de golpes[17]*tempo=1,2 s. Para finalizar se pone entre nota y nota un retardo de 0,15 s.

//*********************FUNCIONES***********************
void tocarNota(char nota, int duracion) {
char nombre[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
int tonos[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956 };
for (int i = 0; i < 8; i++) {
if (nombre[i] == nota) {
tocarTono(tonos[i], duracion);
}
}
}
La función tocarNota(x, y) utiliza las variables matriciales nombre[] y tonos[] para asignar a cada nota su ancho de impulso. Mediante el bucle for se determina el valor de i que corresponde a la nota a tocar y se llama a la función tocarTono(u,v), con un valor de u igual al ancho de impulso de dicha nota y un valor v igua a y. Por ejemplo, si del programa principal se viene con i=2, la llamada viene como tocarNota(‘e’, 300) y se llama a tocarTono(1519, 300).

void tocarTono(int tono, int duracion) {
for (long i = 0; i < duracion * 1000L; i += tono * 2) {
digitalWrite(zumbadorPin, HIGH);
delayMicroseconds(tono);
digitalWrite(zumbadorPin, LOW);
delayMicroseconds(tono);
}
}
Esta función crea una señal cuyo semiperíodo corresponde con el valor del tono de la nota que se repetirá hasta que se alcance el valor de multiplicar por mil el contenido de duración. Por ejemplo: si del programa principal i=7 en la función tocarNota(), nota=notas[7]=’C’ y duracion=golpes[7] * tempo= 2*300=600. Al ejecutarse esta función y llamar a tocarTono(), se tiene que tono=tonos[7]=956 y duracion=600. El bucle se repetirá hasta alcanzar el valor duracion*1000L=600.000. Los valores i para el bucle serán 0, tono*2=1912, tono*4=3824, tono*6= 5736 … tono*2k. Esto hace que el bucle se repita un total de 314 veces, desde k=0 hasta K=313: tono*2*313=598456.  De este modo se consigue una señal con una frecuencia de 523 Hz sonando durante un tiempo de 314/523=0,6s.

Este programa podrá tomarse como base para obtener cómodamente otras melodías sencillas que puedan obtenerse con la escala de la tabla. Sólo habrá que asignar a las variables N, notas[] y golpes[] los valores adecuados de acuerdo con lo comentado. Tras encontrar fácilmente la partitura en la Red y pedir un poco de ayuda obtengo lo deseado.

himno-alegria

En total son 26 notas, y dando a las blancas un tiempo doble que a las negras, tenemos:

  • N=27
  • notas[] = “efggfedccdeedefggfedccdedc “
  • golpes[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4}

Por lo tanto, objetivo cumplido. Aquí podemos oír a nuestro rey cantando de alegría descansado apaciblemente sobre una máquina GNU/Linux, cómo no.