6891 bytes añadidos
, hace 5 años
{{Título}}
Hoy en día la manera más común de comunicación entre dispositivos electrónicos es la comunicación serial y Arduino no es la excepción. A través de este tipo de comunicación podremos enviar datos a y desde nuestro Arduino a otros microcontroladores o a un computador corriendo alguna plataforma de medios (Processing, PD, Flash, Director, VVVV, etc.). En otras palabras conectar el comportamiento del sonido o el video a sensores o actuadores. Explicaré aquí brevemente los elementos básicos de esta técnica:
== Funciones básicas ==
El mismo cable con el que programamos el Arduino desde un computador es un cable de comunicación serial. Para que su función se extienda a la comunicación durante el tiempo de ejecución, lo primero es abrir ese puerto serial en el programa que descargamos a Arduino. Para ello utilizamos la función
<code>beginSerial(19200);</code>
Ya que solo necesitamos correr esta orden una vez, normalmente iría en el bloque void setup(). El número que va entre paréntesis es la velocidad de transmisión y en comunicación serial este valor es muy importante ya que todos los dispositivos que van a comunicarse deben tener la misma velocidad para poder entenderse. 19200 es un valor estándar y es el que tienen por defecto Arduino al iniciar.
Una vez abierto el puerto lo más seguro es que luego queramos enviar al computador los datos que vamos a estar leyendo de uno o varios sensores. La función que envía un dato es
<code>Serial.print(data);</code>
Una mirada en la referencia de Arduino permitirá constatar que las funciones print y println (lo mismo que la anterior pero con salto de renglón) tienen opcionalmente un modificador que puede ser de varios tipos:
<code>Serial.print(data, DEC); // decimal en ASCII</code>
<code>Serial.print(data, HEX); // hexadecimal en ASCII</code>
<code>Serial.print(data, OCT); // octal en ASCII</code>
<code>Serial.print(data, BIN); // binario en ASCII</code>
<code>Serial.print(data, BYTE); // un Byte</code>
Como puede verse, prácticamente todos los modificadores, menos uno, envían mensajes en ASCII. Explicaré brevemente:
== Series de pulsos ==
En el modo más sencillo y común de comunicación serial (asincrónica, 8 bits, más un bit de parada) siempre se está enviando un byte, es decir un tren de 8 pulsos de voltaje legible por la máquina como una serie de 8, 1s ó 0s:
[[Archivo:Serie de pulsos - diagrama.png|alt=Serie de pulsos - diagrama|centre|frameless|400x400px|Serie de pulsos - diagrama]]
O sea que no importa cual modificador usemos siempre se están enviando bytes. La diferencia esta en lo que esos bytes van a representar y sólo hay dos opciones en el caso del Arduino: una serie de caracteres ASCII o un número.
Si Arduino lee en un sensor analógico un valor de 65, equivalente a la serie binaria 01000001 esta será enviada, según el modificador, como:
{| class="wikitable"
!Dato
!Modificador
!Envío (pulsos)
|-
|65
|<nowiki>---DEC----</nowiki>
|(“6′′ y “5′′ ACIIs 54–55) 000110110–000110111
|-
|65
| ---HEX----
|(“4′′ Y “1′′ ACIIs 52–49) 000110100–000110001
|-
|65
| ---OCT----
|(“1′′, “0′′ y “1′′ ACIIs 49–48–49) 000110001– 000110000–000110001
|-
|65
| ---BIN----
|(“0′′,”1′′,”0′′,”0′′,”0′′,”0′′,”0′′y”1′′ ACIIs 49–48– 49–49–49–49–49–48) 000110000-...
|-
|65
| ---BYTE---
|01000001
|}
No explicaremos conversiones entre los diferentes sistemas de representación numérica, ni la tabla ASCII (google), pero es evidente como el modificador BYTE permite el envío de información más económica (menos pulsos para la misma cantidad de información) lo que implica mayor velocidad en la comunicación. Y ya que esto es importante cuando se piensa en interacción en tiempo real es el modo que usaremos acá.
=== Un ejemplo sencillo ===
Enviar un sólo dato es realmente fácil. En el típico caso de un potenciómetro conectado al pin 24 del ATmega:
<code>int potPin = 2;</code>
<code>int ledPin = 13;</code>
<code>int val = 0;</code>
<code>void setup()</code>
<code>{</code>
<code>Serial.begin(9600);</code>
<code>pinMode(ledPin, OUTPUT);</code>
<code>digitalWrite(ledPin, HIGH); //activamos el pin para saber cuando arranco</code>
<code>}</code>
<code>void loop()</code>
<code>{ </code>
<code>val = analogRead(potPin); // lee el valor del Pot</code>
<code>Serial.println(val);</code>
<code>}</code>
Si no utilizamos ningún modificador para el Serial.println es lo mismo que si utilizáramos el modificador DEC. Así que no estamos utilizando el modo más eficiente pero si el más fácil de leer en el mismo Arduino. Al correr este programa podremos inmediatamente abrir el monitor serial del software Arduino (último botón a la derecha) y aparecerá el dato leído en el potenciómetro tal como si usáramos el println en Processing.
=== Envío a Processing (versión ultra simple) ===
Para enviar este mismo dato a Processing si nos interesa utilizar el modo BYTE así que el programa en Arduino quedaría así:
<code>int potPin = 2;</code>
<code>int ledPin = 13;</code>
<code>int val = 0;</code>
<code>void setup()</code>
<code>{</code>
<code>Serial.begin(9600);</code>
<code>pinMode(ledPin, OUTPUT);</code>
<code>digitalWrite(ledPin, HIGH); // activamos el pin para saber cuando arranco</code>
<code>}</code>
<code>void loop(){</code>
<code>; // lee el Pot y lo divide entre 4 para quedar entre 0-255</code>
<code>val = analogRead(potPin)/4</code>
<code>Serial.print(val, BYTE);</code>
<code>}</code>
En Processing tenemos que crear un código que lea este dato y haga algo con él:
<code>import processing.serial.*;</code>
<code>Serial puerto; // Variable para el puerto serial</code>
<code>byte pot;// valor entrante</code>
<code>int PosX;</code>
<code>void setup()</code>
<code>{</code>
<code>size(400, 256);</code>
<code>println(Serial.list()); // lista los puertos seriales disponibles</code>
<code>//abre el primero de esa lista con velocidad 9600 </code>
<code>port = new Serial(this, Serial.list()[0], 9600);</code>
<code>fill(255,255,0);</code>
<code>PosX = 0;</code>
<code>pot = 0;</code>
<code>}</code>
<code>void draw()</code>
<code>{</code>
<code>if (puerto.available() > 0) { // si hay algún dato disponible en el puerto</code>
<code>pot = puerto.read();// lo obtiene</code>
<code>println(pot);</code>
<code>}</code>
<code>ellipse(PosX, pot, 3, 3); // y lo usa</code>
<code>if (PosX < width)</code>
<code>{</code>
<code>PosX++;</code>
<code>}</code>
<code>else</code>
<code>{</code>
<code>fill(int(random(255)),int(random(255)),int(random(255)));</code>
<code>PosX = 0;</code>
<code>}</code>
<code>}</code>
Si ya se animó a intentar usar más de un sensor notará que no es tan fácil como duplicar algunas líneas.