Pongámonos Serios: Comunicación Serial

Pongámonos Serios: Comunicación Serial

tecnoingenia / enero 19, 2020

En la entrada anterior veíamos como podemos conectar un dispositivo electrónico con nuestros teléfonos celulares a través de una aplicación muy sencilla y un módulo bluetooth HC-06. Para esto implementamos algunos comandos muy sencillos enviados por medio de comunicación serie, hasta aquí todo nos funcionó perfecto… o no?
 
El problema con lo que se implementó en el proyecto anterior, es que dejamos a la suerte si los datos fueron transmitidos correctamente, si no hubo interferencias en la recepción, sin tener si quiera idea de si se recibió el mensaje, que en ejemplos tan sencillos como encender una luz, puede parecer suficiente, si no la veo encendida vuelvo a presionar el botón… Pero cuando de ese mensaje depende la ración de alimento de nuestros animales de engorda, o el apagado del motor de una sierra el eléctrica al acercarse una mano, o simplemente la experiencia de usuario que al ver que tiene que presionar dos veces un botón para que se encienda una luz y de esto dependa si recomendará nuestro producto o no, se vuelve necesario y en ciertos casos imprescindible implementar un protocolo de comunicación que nos asegure la correcta transmisión y recepción los mensajes. (Por cierto en el ejemplo de la sierra, normalmente los dispositivos de seguridad se implementan por medio de hardware y no de software, pero ustedes entienden).
 
Lo más usual en estos casos es usar una estructura de mensaje o «trama», que nos ayude a reconocer si ha habido algún error en lo que se recibió y un protocolo que confirme cuando se realizó correctamente.
 
La imagen siguiente representa en forma gráfica la trama que implementaremos en esta ocasión: 

 

Normalmente la comunicación serial envía los mensajes en paquetes de 8 bits, llamados bytes, lo que para una cadena de texto vendría siendo un carácter y aparte cuenta con su propio protocolo para el inicio y fin de la transmisión, físicamente el envío es bit por bit ya que es un solo cable el que realiza la transmisión, esto lo hace automáticamente la interface UART por lo que no nos debe preocupar, lo único a tomar en cuenta es que desde la vista del software enviaremos un byte a la vez, pero al recibir el mensaje yo decidí implementar una recepción de los mensajes en formato String (cadena de texto), porque me parece la manera más sencilla para decodificarlos, por lo menos si hablamos de comandos de texto.

 

Siguiendo esta linea se enviará primero un byte especial que indicara que ha iniciado una transmisión es el caracter «STX» o «0x02» en hexadecimal, seguido de nuestro mensaje, un checkSum y el caracter ETX («0x03») para indicar el fin de la transmisión.
 
Un cheksum es una operación matemática que se realiza con todos los bytes que conforman el mensaje y que se repite en el receptor para confirmar que que no hubo errores o ruidos en la transmisión, pueden ser tan sencillos como hacer una suma de todos los bytes o tan complejos como queramos, el inconveniente de realizar solo una suma es que no se podría detectar si los datos cambiaron de posición, porque en una suma no importa el orden que se introduzcan los datos, existen diferentes métodos ya documentados para realizar un checksum de una manera más efectiva, por nuestra parte utilizaremos el checksum «fletcher16».

 

Para ayudarnos a manejar estos conceptos de forma más sencilla he confeccionado la librería SerialCenter.
 
Las funciones básicas son las siguientes:

 

serialCenter(); // Constructor 1 para hardware serial
serialCenter(SoftwareSerial *softPort);// Constructor para software serial
Tiene dos opciones de constructores la primera sin ningún parámetro, toma por automáticamente el puerto hardware serial o el puerto por defecto, en el segundo caso para poder utilizarlo con un softwareSerial, enviando un apuntador como parámetro.
int available();
El método available, funciona exactamente igual que en el serial por default, devuelve el número de bytes disponibles para leer en el buffer serial.
void sendMessage(String message);
sendMessage es el método con el que escribimos en el puerto serie, este método automáticamente nos agrega el caracter de inicio, el checkSum y el fin de trama, recibe como único parámetro un String.
String readNextMessage();
readNextMessage() es el método para leer el mensaje, siempre y cuando empiece por el caracter «STX», automáticamente calcula y valida el checkSum y responde con un ACK si el mensaje se recibió OK, o NACK en el caso contrario.
int tryGetACK(int timeOut);
tryGetACK() es para invocarlo después de enviar un mensaje, este espera recibir una respuesta ya sea ACK o NACK, regresa un dato entero 0, 1 o 2, que corresponden a OK, ERROR o NO_RESPONSE. Esto nos sirve para tomar acciones según la respuesta, como repetir el mensaje si no se recibió correctamente.
void setMaxString(int MAX);
setMaxString(int) Con este podemos cambiar el máximo de caracteres que puede tener cada mensaje, por defecto está en 64.
La librería la puedes descargar directamente de mi repositorio de gitHub en el siguiente enlace:
DESCARGAR: SerialCenter
 
Y ahora se preguntarán esto es lo máximo que podemos hacer para optimizar la comunicación por puerto serie?.. pues afortunadamente no, vivimos en un mundo en el que todo se puede mejorar y en el que las mejoras y actualizaciones están a la orden del día. Es un buen comienzo pero hay mucho más que se puede hacer en este tema, una de esas cosas podría ser el encriptado de los mensajes, pero eso es tema para otra entrada, hasta entonces.

Leave a Reply

TecnoIngenia | Blog personal -israel.barreras@tecnoingenia.com