F006 Comunicación serie con el mundo exterior

                                                                                                                                        ADM

Pronto vamos a necesitar comunicar nuestro Arduino con nuestro PC, con la idea de enviarle órdenes o recibir información o señales, mientras arduino está trabajando. Para ello vamos a usar el puerto USB que establecerá una conexión en serie con nuestro PC.

La comunicación en serie es muy sencilla, con solo dos cable podemos tener una diferencia de tensión entre ellos cuando la diferencia sea de (5V) tendremos nivel alto y cuando sea de (0V) tendremos nivel bajo y con esto podemos transmitir información digital. Ahora solo nos falta establecer dos cosas entre el emisor y el receptor

         Un código común para codificar los caracteres que se envían.
        
         Un acuerdo de velocidad para saber a qué ritmo hay que leer los datos.
 

El código común que vamos a usar con Arduino se llama código ASCII y es estándar en todos los PCs. Es una forma de codificar las letras mediantes números en código binario que representas estos caracteres. Recordad que solo podemos transmitir unos y ceros.

Prácticamente todos los PCs utilizan este código y eso incluye a Windows, Mac y Linux, pero es importante comprender que esté es uno más entre varios códigos de caracteres posibles.

En realidad, lo que se suele usar actualmente es una extensión del código ASCII (llamada Unicode) que permita el uso de caracteres no incluidos en la tabla original, y que permite representar caracteres como las Ñ, o acentos para el español.

El otro factor que hay que establecer para realizar una comunicación serie es la velocidad. Dado que solo disponemos de dos hilos para transmitir, necesitamos saber cuándo hay que leer la línea y esto se hace estableciendo un acuerdo de velocidad. Si la velocidad de envío es distinta de la velocidad de lectura, el mensaje final será irreconocible.

Buena parte de los errores de comunicación serie programando con Arduino se suelen deber a una diferencia de velocidad entre el emisor y el receptor.

Esta velocidad se mide en bits por segundo y vamos a ver que Arduino soporta diferentes velocidades de comunicación serie.

Estableciendo la comunicación Serie

Arduino dispone de una librería serie incluida llamada Serial, que nos permite envía información al PC y para usarla, simplemente tenemos que pedirle en nuestro setup() que la incluya. La instrucción que se encarga es:

Serial.begin( velocidad )  ;

¡Ojo! que Serial tiene la S mayúsculas y que C++ diferencia entre mayúsculas y minúsculas
 

La velocidad es un valor entre 300 y 2.000.000 bits por segundo. Normalmente se establece en 9600 (el valor por defecto) pero no hay ninguna razón para que sea esta la velocidad por defecto, de hecho esta no es una velocidad especialmente alta hoy se utiliza 115200 para que se comunique con la placa ESP32.

Para enviar un mensaje desde Arduino a nuestro PC podemos usar  las funciones
 
Serial.print();
Serial.println();

int LED = 3;
int brillo;
int pot = 0;

void setup() {
  pinMode(LED, OUTPUT);
  Serial.begin(115200);
}

void loop() {
  brillo = analogRead(pot)/4;
  analogWrite(LED, brillo);
  .println (brillo);
}

El println()  enviara el valor de la variable brillo al puerto serie de Arduino (repetidamente). Para leerlo en nuestro PC necesitamos un monitor de puerto serie. El IDE de Arduino incluye uno muy sencillo, pero suficiente que se invoca con el botón del monitor:

Necesitamos además asegurarnos de que la velocidad de conexión es la misma en ambos extremos. Fíjate en la parte inferior derecha del monitor serie:


Normalmente la velocidad por defecto son los 9600 bits por segundo o baudios en los que hemos programado nuestra puerta serie, y si lo desplegáis, veréis las diferentes velocidades aceptables para Arduino, en la imagen vemos que tenemos 115200.

Estrictamente hablando, bits por segundo y baudios no son exactamente lo mismo salvo bajo ciertas condiciones particulares que en Arduino se cumplen, por lo que aquí podemos usarlos como sinónimos.

Ahora que sabemos enviar  información y resultados al PC, vamos a ver cómo podemos operar con enteros y mostrar el resultado en la puerta serie. 

En C++ los operadores numéricos son los normales en cálculo (y algunos menos frecuentes):

Adición:                +

Resta:                   –

Multiplicación:        *

División entera:      /              Cociente sin decimales (puesto que operamos con enteros

Resto:                  %            Devuelve el resto de una división.

 

En C++ tenemos que expresar las operaciones matemáticas en una sola línea y utilizar paréntesis para garantizar que se opera como necesitamos. Vamos con algunos ejemplos:


OPERACIÓN RESULTADO COMENTARIO

int i = 4 * 2         resultado =  8

int i = 4 * 2 / 3 resultado = 2         Porque desprecia los decimales al ser entero

int i = 14 % 3         resultado = 2 El resto de 14 entre 3

Int i = 2 + 8 / 2 resultado = 6         Calcula primero la división.

Int i = (2+8) / 2 resultado = 5         El paréntesis fuerza a que se realice primero la suma


Dada una expresión, la precedencia de operadores indica que operaciones se realizaran antes y cuales después en función de su rango. Pero es más seguro usar paréntesis.  Los paréntesis fuerzan las operaciones de una forma clara y conviene utilizarlos ya que, detectar los errores de operación puede volverse muy difícil 


El operador resto es más útil de lo que parece a primera vista porque nos permite saber si un numero es múltiplo de otro.  Supongamos que queremos saber si un número dado es par.


Podríamos escribir un programa como este:

nt LED = 3;
int brillo;
int pot = 0;

void setup() {
  pinMode(LED, OUTPUT);
  Serial.begin(115200);
}

void loop() {
  brillo = analogRead(pot)/4;
  analogWrite(LED, brillo);
  Serial.print(brillo);
  if (brillo % 2 == 0){
    Serial.println (" es par");
    }else{
    Serial.println (" es impar");
    }
  delay(100);
}

Podemos ver que según giramos el potenciómetro variamos el valor de la variable brillo y el monitor serie no dice que valor es y si es par o impar


Recibiendo mensajes a través del puerto serie

Hasta ahora solo hemos enviado mensajes desde Arduino hacia el PC, ¿Pero como recibimos mensajes en Arduino?

En primer lugar disponemos de una función llamada Serial.parseInt() que nos entrega lo que se escribe en el monitor serie convertido a entero:

void setup(){
  Serial.begin(115200);
}

void loop(){
  if (Serial.available()>0){      
    int x = Serial.parseInt();  
    Serial.println (x);          
  }
}

Este programa simplemente recibe en x los números que nos tecleen en la consola (cuando pulsemos intro) y si es un texto, lo interpreta como cero.

Hemos utilizado otra función  

Serial.available();

que es un booleano. Conviene por costumbre comprobar que antes de leer el puerto serie si hay algo que nos han enviado.  Si lo hay Available() es True y en caso contrario es False.

Para leer un String del puerto serie tenemos que complicarnos un poco más y hablar del tipo char.

Uno de de las mayores quebradero de cabeza al iniciarse en C++ es comprender la diferencia, anti-intuitiva, entre char y String. char es un tipo que representa un único carácter y se define con comillas simples, a diferencia de String que necesita comillas dobles:

char  c = 'a';

String s =”a”;


Aunque parezca lo mismo para C++ son muy distintos.


Para leer una cadena desde el puerto serie necesitamos leer un carácter cada vez y después montar un String a partir de ellos, pero antes, asegúrate de seleccionar ambos NL & CR en la parte inferior del monitor serie, para garantizar que se envía el carácter de fin de línea:


Selección de ajuste de linea


Un programa para leer la consola sería algo así:

void setup(){
  Serial.begin(115200);
}

void loop(){
  char c = ' ';
  String mensaje = " ";
  if (Serial.available()){        //comprobamos si hay algo esperando
    while(c != '\n'){             // Si lo hay leeremos hasta el intro
      mensaje = mensaje + c;      // Añadimos lo leido al mensaje
      c = Serial.read();          // Lee el primer carcater
      delay(25);
    }

    Serial.println(mensaje);     // Al salir imprimir el mensaje
    mensaje = "";                 // Borralo la próxima vez
  }
}


Aqui vemos una serie de instrucciones que no vienen al caso y que se verá más adelante en su correspondiente apartado. 

El motivo del delay(25) es que a una velocidad tan lenta, enviar un char de 8 bits por la puerta serie, tarda mucho más de lo que tarda Arduino en ejecutar las instrucciones del while y volver a empezar. Por eso si se suprime el delay (y os recomiendo la prueba) leerá un carácter bueno (de la palabra escrita y como 10 caracteres basura para un Arduino UNO o Mega).
Si subimos la velocidad de comunicación a 115200 bits por segundo, comprobareis que no hay este problema ya que al multiplicar la velocidad de envío por más de 10 Arduino ya no tiene tiempo de volver a por más caracteres antes de que lleguen.

Serial Plotter
Ya sabemos utilizar el monitor serie del IDE para mostrar valores de las variables de nuestro programa. Pero en ocasiones se necesita verlo en forma de gráfica.
Para ello, el IDE de Arduino incorpora una herramienta llamada Serial Plotter que permite crear gráficas a partir de las variables que le indiquemos. Es sencilla de usar, no ofrece muchas opciones, pero seguramente irá mejorando con nuevas versiones.

Para utilizarla no hay que aprender nada nuevo en cuanto a la programación. Simplemente, conectamos por USB a al PC nuestro arduino sin circuitería externa y vamos a cargar el siguiente programa que genere números aleatorios cada cierto tiempo, y los imprime por el puerto serie.
void setup() {
  Serial.begin(115200);
}

void loop() {
  int valor;
  valor = random(0,100);
  Serial.println(valor);
  delay(250);
}
Ahora la única diferencia es que en lugar de abrir el monitor serie, vamos a abrir el serial plotter, que está en la barra de herramientas, justo debajo del monitor serie.
 


Y cuando carguemos el programa en Arduino, veremos cómo se va generando una gráfica a partir de los valores aleatorios que se va guardando en la variable.
 


Cuando hay mas de una variable
Seria plotter nos da la opción de mostrar varias variables a la vez en la misma gráfica. La manera de hacerlo es sencilla, simplemente añadiremos una sentencia Serial.print(“,”); entre cada una de las variables que queramos graficar. Todas deben ser print() y solamente la última varable debe ser println() y automáticamente los dibujará en la misma gráfica con un color diferente.
vamos a añadir 4 variables más al programa que hemos realizado y también se la vamos a asignar aleatorias a fin de ver resultados en la gráfica. El programa queda así:
void setup() {
  Serial.begin(115200);
}

void loop() {
  int valor1 = random(0,100);
  int valor2 = random(0,100);
  int valor3 = random(0,100);
  int valor4 = random(0,100);
  int valor5 = random(0,100);
  Serial.print(valor1);
  Serial.print(", ");
  Serial.print(valor2);
  Serial.print(", ");
  Serial.print(valor3);
  Serial.print(", ");
  Serial.print(valor4);
  Serial.print(", ");
  Serial.println(valor5);
  delay(250);
}
Vemos que tenemos 5 variables que va a tormar valores entre 0 y 100, y vemos como hemos puesto los Serial.print() separando los de las variables por "," es muy importante hacerlo de este modo para que se impriman las 5 variables. Los colores en la gráfica los asigna arduino de forma automática y obtenemos este resultado.

Si necesitamos separar las componente para poder visualizarlas mejor cada una de ellas por separado, en tal caso, podemos hacer el siguiente código, en el cual dentro del Serial.print, le sumamos un número superior a el rango en el que se representa más uno.  Nota he cambiado el valor de 100 a 10 para que aparezcan todas las gráficas en la foto juntas, así que a la primera no le he sumado nada, a la segunda le he sumado 11 para que se represente entre el 11 y el 20, a la tercera le he sumado 21 para que se represente entre el 21 y el 30 y así sucesivamente. El código queda así
void setup() {
  Serial.begin(115200);
}

void loop() {
  int valor1 = random(0,10);
  int valor2 = random(0,10);
  int valor3 = random(0,10);
  int valor4 = random(0,10);
  int valor5 = random(0,10);
  Serial.print(valor1);
  Serial.print(", ");
  Serial.print(valor2+11);
  Serial.print(", ");
  Serial.print(valor3+21);
  Serial.print(", ");
  Serial.print(valor4+31);
  Serial.print(", ");
  Serial.println(valor5+41);
  delay(250);
}
bien este es el código y vamos a ver el resultado que da este código



para finalizar voy a repetir el mismo código pero las variables recibirán valores entre 0 y 2, para simular una entrada digital, por supuesto, el valor que se suma en los Serial.print han cambiado, son 2, 4, 6 y 8 y la idea es representar las entradas o salidas digitales, para así monitorizar el comportamiento de las entradas o salidas.
void setup() {
  Serial.begin(115200);
}

void loop() {
  int valor1 = random(0,2);
  int valor2 = random(0,2);
  int valor3 = random(0,2);
  int valor4 = random(0,2);
  int valor5 = random(0,2);
  Serial.print(valor1);
  Serial.print(", ");
  Serial.print(valor2+2);
  Serial.print(", ");
  Serial.print(valor3+4);
  Serial.print(", ");
  Serial.print(valor4+6);
  Serial.print(", ");
  Serial.println(valor5+8);
  delay(250);
}
y el resultado es este


Bueno hemos visto como utilizar el monitor gráfico del IDE de arduino, el Serial Plotter, y podemos utilizarlo generando valores, pero podemos sustituir las variable por otras que guarden el estado de las salidas o de las entradas, ya sean digitales o analógica y podemos compararlas, incluso lo podemos utilizar para crear un analizador lógico o monitorizar señales y descubrir fallas o averías.  Medir sensores, la velocidad de un motor, etc. El límite lo pone tu imaginación.