Tutorial - Comunicación Maestro / Esclavo : Parte 2 (Comunicación Serial Simulada)

PUERTOS SERIALES POR MEDIO DE SIMULACIÓN
La transferencia de información entre dos computadores se usa comunmente un puerto serial, este puerto serial se basa en el hardware llamado "UART" (Universal Asynchronous Receiver / Transmitter) que se contiene en el procesador de un chip. El UART se encarga de generar y decodifcar las señales usadas que pasan a través de RX y TX, por lo que el programador sólo debe enfocarse en el mensaje a enviar y el formato en que se envian.

Muchas veces las desventajas en varios proyectos es la necesidad de tener más de un puerto serial, pero algunas plataformas como el Arduino basado en el ATmega328 sólo dispone de un solo puerto UART; en cambio los basados en el ATmega2560 tienen hasta cuatro UARTs por lo que este obstáculo puede ser solucionado usando una plataforma como la descrita al final. Lamentablemente, unas veces no tenemos a la mano una plataforma como el Arduino MEGA2560, o por otro lado, el costo es mucho mayor para un proyecto donde sólo necesitamos unas cuantas entradas y salidas.

Para casos donde lo último mencionado es importante, debemos saber que la misma función que realiza el UART en Hardware también se puede simular en Software. Para ello, usamos una librería llamada "New Software Serial Library", que fué desarrollado por Mikal Hart.

PRUEBA DE LA LIBRERÍA "NEW SOFTWARE SERIAL"
Primero debemos saber como utilizar esta librería, para ello debemos las siguientes funciones:
#  SoftwareSerial nombre_puerto(Pin_receptor, Pin_transmisor) : Con esta función establecemos que pines usaremos para comunicación. El "nombre_puerto" será el que deseemos.
# nombre_puerto.begin(baudios) : Con esta función especificamos los baudios usados para la comunicación.
# nombre_puerto.print(argumento) : Esta función funciona de la misma manera que Serial.print() y se puede escribir tanto números como texto.
# nombre_puerto.println(argumento) : Esta función funciona de la misma manera que Serial.println() y se puede escribir tanto números como texto y saltar a una línea nueva.
# nombre_puerto.available() : Esta función retorna el número de bytes recibidos, que también pueden ser leídos.
# nombre_puerto.read() : Esta función lee el byte del puerto. En caso no se tenga ningún byte, se recibirá -1 como dato.
# nombre_puerto.write(byte) : Transmite un byte a la vez.
# nombre_puerto.flush() : Esta función descarta cualquier dato que no haya sido leído.
# nombre_puerto.parseInt() : Recolecta los datos tipo integer del byte del buffer del puerto serial.
# nombre_puerto.peek() : Discrimina la letra del puntero del byte que se lee en el buffer del puerto serial.
# nombre_puerto.listen() : Discrmina el puerto que se va a escuchar uno a la vez.

NOTA: Al momento de querer recibir datos de parte de dos nodos a uno central "No se podrá", debemos discriminar el puerto del que se va a recibir datos, "Uno a la vez". En cambio, sí se pueden enviar datos a dos nodos a partir de uno central sin discriminar.

Teniendo en cuenta lo anterior, desarrollaremos una simple aplicación usando un potenciómetro de 10 kohm conectado al PIN A0 de un Arduino mientras que otro recibe los datos y los muestra en pantalla. La conexión será la siguiente:

# PIN 4 : Arduino UNO del Nodo 1 => TX : Arduino UNO del Nodo 2
# PIN 3 : Arduino UNO del Nodo 1 => RX : Arduino UNO del Nodo 2
# PIN A0 : Arduino UNO del Nodo 2 => PIN CENTRAL : Potenciómetro
# GND : Los dos GND deben estar conectados => EXTREMO : Potenciómetro
# 5V : Los dos 5V deben estar conectados => EXTREMO : Potenciómetro


El programa para el NODO 1 se muestra a continuación:
/*
   PROGRAMA DE PRUEBA DE COMUNICACION ENTRE DOS PUNTOS: USO DE LA LIBRERIA NEW SOFTWARE SERIAL
   (PROGRAMA PARA EL NODO 1)
   
   NODO 1: Arduino UNO (1)
   NODO 2: Arduino UNO (2)
   
   CONEXION:
             Pin 4(Arduino UNO (1) / RX_1 - NODO 1): TX (Arduino UNO (2) - NODO 2)
             Pin 3(Arduino UNO (1) / TX_1 - NODO 1): RX (Arduino UNO (2) - NODO 2)
             Potenciometro: Pin A0 (Arduino UNO(2) - NODO 2) 
             GND: Conectar los dos GND
             VCC: Conectar los dos 5V
   
   En el siguiente programa probaremos la comunicacion entre dos nodos 1 y 2; el primer nodo permite 
   la visualizacion de los datos obtenidos de leer el potenciometro que va conectado al nodo 2. 
   
   Para correr el programa se necesita la libreria New Software Serial Library (NewSoftSerial.h)
   
   Se pueden encontrar en: 
   http://arduiniana.org/libraries/newsoftserial/

   Tambien en el tutorial de correspondiente en http://beetlecraft.blogspot.pe/  
   
   Autor: Renato H.
   http://beetlecraft.blogspot.pe/
   
   El siguiente programa es de uso publico, cualquier modificacion o mal uso del mismo que pudiera 
   ocasionar el mal funcionamiento de la plataforma de uso de la misma no es responsabilidad del 
   autor
*/

#include <SoftwareSerial.h> // Libreria de manejo de comunicacion serial alterna

const int RX_1 = 4; // Pin de UART virtual RX del NODO 1 conectado al pin TX del NODO 2
const int TX_1 = 3; // Pin de UART virtual TX del NODO 1 conectado al pin RX del NODO 2
int POT = 0;        // Variable de almacenamiento del valor leido del potenciometro del NODO 2

SoftwareSerial Serialvirt(RX_1, TX_1); // Declaracion de pines usados para comunicacion con el NODO 2
                                       // y el nombre del puerto virtual

void setup() {
  Serial.begin(9600);     // Velocidad de comunicacion con la PC
  Serialvirt.begin(9600); // Velocidad de comunicacion del NODO 2
  
  // Mensaje inicial en el Monitor Serial
  Serial.println("Los valores del potenciometro se observan de 0 a 100% ");
  Serial.println("Esperar...");
  delay(100);
}

void loop() {
  if (Serialvirt.available()) { // Verificacion que el puerto serial virtual recibe datos                                  
   delay(10);                
                             
   lectura_pot(); // Rutina de lectura del potenciometro
   delay(100);    // Tiempo de demora para siguiente lectura de puerto
  }
}

void lectura_pot(){        // RUTINA DE LECTURA DE DATOS DEL POTENCIOMETRO
  POT = Serialvirt.read(); // Lectura del valor del potenciometro del NODO 2
  
  // Mensaje de muestra del porcentaje del voltaje leido del potenciometro
  Serial.print("Porcentaje de voltaje: "); 
  Serial.print(POT);                       
  Serial.println(" %");                    
}
El programa para el NODO 2 se muestra a continuación:

NOTA: Al momento de querer programar el NODO 2, debe tener desconectado las conexiones del puerto serial con las correspondientes al NODO 1 para evitar problemas de compilación.
/*
   PROGRAMA DE PRUEBA DE COMUNICACION MAESTRO / ESCLAVO: MAESTRO / ESCLAVO POR SERIAL VIRTUAL
   (PROGRAMA PARA EL NODO 2)
   
   NODO 1: Arduino UNO (1)
   NODO 2: Arduino UNO (2)
   
   CONEXION:
             Pin 4(Arduino UNO (1) / RX_1 - NODO 1): TX (Arduino UNO (2) - NODO 2)
             Pin 3(Arduino UNO (1) / TX_1 - NODO 1): RX (Arduino UNO (2) - NODO 2)
             Potenciometro: Pin A0 (Arduino UNO(2) - NODO 2) 
             GND: Conectar los dos GND
             VCC: Conectar los dos 5V
   
   En el siguiente programa probaremos la comunicacion entre dos nodos 1 y 2; el primer nodo permite 
   la visualizacion de los datos obtenidos de leer el potenciometro que va conectado al nodo 2. 
   
   NOTA: Al momento de compilar el programa para el NODO 2, evitar que los cables del puerto serial
   esten conectados con los correspondientes al NODO 1.
   
   Para correr el programa se necesita la libreria New Software Serial Library (NewSoftSerial.h)
   
   Se pueden encontrar en: 
   http://arduiniana.org/libraries/newsoftserial/

   Tambien en el tutorial de correspondiente en http://beetlecraft.blogspot.pe/  
   
   Autor: Renato H.
   http://beetlecraft.blogspot.pe/
   
   El siguiente programa es de uso publico, cualquier modificacion o mal uso del mismo que pudiera 
   ocasionar el mal funcionamiento de la plataforma de uso de la misma no es responsabilidad del 
   autor
*/

int POT = A0;      // Pin de entrada de senal del potenciometro
int POT_valor = 0; // Variable de almacenamiento del porcentaje del potenciometro 
int porcentaje;    // Variable de conversion a porcentaje

void setup() {
  Serial.begin(9600); // Inicializacion del puerto serial a 9600 baudios
}

void loop() {
  POT_valor = analogRead(POT);              // Lee el valor del sensor (Rango de 0 a 1023)
  porcentaje = map(POT_valor,0,1023,0,100); // Porcentaje del rango de 0 a 100%
                                            // 100 corresponde a 5V y 0 a 0V
  Serial.write(porcentaje);                 // Escritura por puerto del porcentaje de voltaje
  delay(100);                               // Tiempo de retraso para siguiente rutina
}
Al abrir el Monitor Serial del NODO 1 obtendremos lo siguiente:


COMUNICACIÓN MAESTRO / ESCLAVO USANDO TRES ARDUINOS Y LA PC
Una de las varias variantes que se pueden establecer en este tipo de comunicación, es establecer una red bidireccional (Emisión y recepción de datos) usando como enlace los puertos seriales cruzados de dos Arduinos UNO conectados a cuatro pines ajenos de un Arduino UNO (que cumplirán la función de dos puertos seriales virtuales).

Las conexiones que se deben realizar se pueden ver en la siguiente figura:

# PIN 2 : Arduino UNO del Maestro => TX : Arduino UNO del Esclavo 1
# PIN 3 : Arduino UNO del Maestro => RX : Arduino UNO del Esclavo 1
# PIN 4 : Arduino UNO del Maestro => TX : Arduino UNO del Esclavo 2
# PIN 5 : Arduino UNO del Maestro => RX : Arduino UNO del Esclavo 2
# GND : Los dos GND deben estar conectados.
# 5V : Los dos 5V deben estar conectados


NOTA: Al momento de querer programar los Esclavos, estos deben tener desconectadas sus conexiones del puerto serial con el Maestro, en caso contrario, el programa no se podrá compilar y se establecerá un error en el IDE de Arduino.

PROGRAMA DE PRUEBA
Como prueba de comunicación, realizaremos un pequeño de ejercicio de envio y recepción de datos en el cual los dos esclavos se identificarán. Para ello, el siguiente procedimiento se debe cumplir:

# El Maestro al enviar la letra "a" ingresada por "Monitor Serial" serial de la PC y debe hacer que encienda el led del Pin 13 del "Esclavo 1", quien a su vez enviará el dato "A1" siendo "A" el puntero del mensaje y "1" el identificador del Esclavo. Al recibir dicho mensaje, en el Monitor Serial deberá aparecer "Esclavo id: 1", siendo el número quien identifique el Esclavo y que recibió el mensaje.
# El Maestro al enviar la letra "b" ingresada por "Monitor Serial" serial de la PC y debe hacer que encienda el led del Pin 13 del "Esclavo 2", quien a su vez enviará el dato "A2" siendo "A" el puntero del mensaje y "2" el identificador del Esclavo. Al recibir dicho mensaje, en el Monitor Serial deberá aparecer "Esclavo id: 2", siendo el número quien identifique el Esclavo y que recibió el mensaje.

El programa del Maestro es el siguiente:
/*
   PROGRAMA DE PRUEBA DE COMUNICACION MAESTRO / ESCLAVO: MAESTRO / ESCLAVO POR SERIAL VIRTUAL
   (PROGRAMA PARA EL MAESTRO)
   
   MAESTRO: Arduino UNO (1)
   ESCLAVO 1: Arduino UNO (2)
   ESCLAVO 2: Arduino UNO (3)
   
   CONEXION:
             Pin 2 (Arduino UNO (1) / RX_1 - MAESTRO): TX (Arduino UNO (2) - ESCLAVO 1)
             Pin 3 (Arduino UNO (1) / TX_1 - MAESTRO): RX (Arduino UNO (2) - ESCLAVO 1)
             Pin 4 (Arduino UNO (1) / RX_1 - MAESTRO): TX (Arduino UNO (3) - ESCLAVO 2)
             Pin 5 (Arduino UNO (1) / TX_1 - MAESTRO): RX (Arduino UNO (3) - ESCLAVO 2)
             GND: Conectar los dos GND
             VCC: Conectar los dos 5V
   
   En el siguiente programa probaremos la comunicacion Maestro / Esclavo usando un Arduino UNO como
   Maestro y dos Arduino UNO como esclavos. El Maestro envia la letra "a" para discriminar al primer
   esclavo para que encienda el led del PIN 13 y envie A1 para identificarse; de la misma manera, al 
   enviar la letra "b" se discrimina el segundo esclavo para que encienda el led del PIN 13 y envie A2
   
   NOTA: El maestro discrimina de manera intercalada la recepcion de datos de cada Esclavo, por lo que
   solamente se puede ingresar sucesivamente a - b - a - b ...

   Para correr el programa se necesita la libreria New Software Serial Library (NewSoftSerial.h)
   
   Se pueden encontrar en: 
   http://arduiniana.org/libraries/newsoftserial/

   Tambien en el tutorial de correspondiente en http://beetlecraft.blogspot.pe/  
   
   Autor: Renato H.
   http://beetlecraft.blogspot.pe/
   
   El siguiente programa es de uso publico, cualquier modificacion o mal uso del mismo que pudiera 
   ocasionar el mal funcionamiento de la plataforma de uso de la misma no es responsabilidad del 
   autor
*/

#include <softwareserial.h> // Libreria de manejo de comunicacion serial alterna

const int RX_1 = 2; // Pin de UART RX_1 del Maestro conectado al pin TX del Esclavo 1
const int TX_1 = 3; // Pin de UART TX_1 del Maestro conectado al pin RX del Esclavo 1
const int RX_2 = 4; // Pin de UART RX_2 del Maestro conectado al pin TX del Esclavo 2
const int TX_2 = 5; // Pin de UART TX_2 del Maestro conectado al pin RX del Esclavo 2

SoftwareSerial Serialvirt1(RX_1, TX_1); // Declaracion de pines usados para comunicacion con el 
                                        // Esclavo 1 y el nombre del puerto virtual
SoftwareSerial Serialvirt2(RX_2, TX_2); // Declaracion de pines usados para comunicacion con el 
                                        // Esclavo 2 y el nombre del puerto virtual
                                        
int id; // Variable del identificador del Esclavo

void setup() {
  Serial.begin(9600);      // Velocidad de comunicacion con la PC
  Serialvirt1.begin(9600); // Velocidad de comunicacion del Esclavo 1
  Serialvirt2.begin(9600); // Velocidad de comunicacion del Esclavo 2
  Serialvirt1.listen();    // Discriminacion para recibir datos solo del Esclavo 1
  
  // Mensaje inicial en el monitor serial
  Serial.println("Envio de datos pueden ser de la siguiente manera: ");
  Serial.println("El programa comienza recibiendo datos del Esclavo 1");
  Serial.println("a: Para el esclavo 1");
  Serial.println("b: Para el esclavo 2"); 
  Serial.println(" ");
  Serial.println("Ingresar letra a: ");
}

void loop() {
  if (Serial.available()) {  // Verificacion que el puerto serial recibe datos                                  
   delay(10);                
                             
   identificacion_esclavo(); // Rutina de identificacion de esclavos 1 y 2
   delay(100);               // Retardo para la siguiente rutina
   mensaje_esclavo();        // Rutina de recepcion del mensaje del esclavo 1 o 2
   delay(100);               // Retardo para la siguiente rutina
   
    while (Serial.available() > 0){Serial.read();} // Rutina de limpieza del buffer del puerto serial
  }
}

void identificacion_esclavo(){    // RUTINA DE IDENTIFICACION DE ESCLAVOS 1 Y 2

                                  // RUTINA DE IDENTIFICACION DEL ESCLAVO 1
  while (Serial.peek() == 'a'){   // Discriminacion de la letra como diferenciador del esclavo 
    Serial.println("Esperar..."); // Mensaje de espera por datos de verificacion
    Serialvirt1.write('a');       // Redireccionamiento del mensaje al Esclavo 1
    break;
  }

                                  // RUTINA DE IDENTIFICACION DEL ESCLAVO 2
  while (Serial.peek() == 'b'){   // Discriminacion de la letra como diferenciador del esclavo  
    Serial.println("Esperar..."); // Mensaje de espera por datos de verificacion
    Serialvirt2.write('b');       // Redireccionamiento del mensaje al Esclavo 2
    break;
  }
}

void mensaje_esclavo(){                 // RUTINA DE ACREDITACION DE IDENTIFICACION

                                        // RUTINA DE ACREDITACION DEL ESCLAVO 2
  while (Serialvirt1.peek() == 'A'){    // Discriminacion de la letra como diferenciador del esclavo  
    Serialvirt1.read();                 // Lectura de datos del buffer
    id = Serialvirt1.parseInt();        // Extraccion de los numeros de las letras     
    Serial.print("Esclavo id: ");       // Mensaje de acreditacion del esclavo
    Serial.println(id);                 // Numero de identificacion del esclavo
    if (id == 1){Serialvirt2.listen();} // Eleccion del Esclavo 2 para recepcion de datos
    break;
  }

                                        // RUTINA DE ACREDITACION DEL ESCLAVO 2
  while (Serialvirt2.peek() == 'A'){    // Discriminacion de la letra como diferenciador del esclavo  
    Serialvirt2.read();                 // Lectura de datos del buffer
    id = Serialvirt2.parseInt();        // Extraccion de los numeros de las letras        
    Serial.print("Esclavo id: ");       // Mensaje de acreditacion del esclavo
    Serial.println(id);                 // Numero de identificacion del esclavo
    if (id == 2){Serialvirt1.listen();} // Eleccion del Esclavo 1 para recepcion de datos
    break;
  }
}
El programa de los Esclavos es el siguiente:
/*
   PROGRAMA DE PRUEBA DE COMUNICACION ENTRE DOS PUNTOS: USO DE LA LIBRERIA NEW SOFTWARE SERIAL
   (PROGRAMA PARA EL ESCLAVO)
   
   MAESTRO: Arduino UNO (1)
   ESCLAVO 1: Arduino UNO (2)
   ESCLAVO 2: Arduino UNO (3)
   
   CONEXION:
             Pin 2 (Arduino UNO (1) / RX_1 - MAESTRO): TX (Arduino UNO (2) - ESCLAVO 1)
             Pin 3 (Arduino UNO (1) / TX_1 - MAESTRO): RX (Arduino UNO (2) - ESCLAVO 1)
             Pin 4 (Arduino UNO (1) / RX_1 - MAESTRO): TX (Arduino UNO (3) - ESCLAVO 2)
             Pin 5 (Arduino UNO (1) / TX_1 - MAESTRO): RX (Arduino UNO (3) - ESCLAVO 2)
             GND: Conectar los dos GND
             VCC: Conectar los dos 5V
   
   En el siguiente programa probaremos la comunicacion Maestro / Esclavo usando un Arduino UNO como
   Maestro y dos Arduino UNO como esclavos. El Maestro envia la letra "a" para discriminar al primer
   esclavo para que encienda el led del PIN 13 y envie A1 para identificarse; de la misma manera, al 
   enviar la letra "b" se discrimina el segundo esclavo para que encienda el led del PIN 13 y envie A2
   
   Autor: Renato H.
   http://beetlecraft.blogspot.pe/
   
   El siguiente programa es de uso publico, cualquier modificacion o mal uso del mismo que pudiera 
   ocasionar el mal funcionamiento de la plataforma de uso de la misma no es responsabilidad del 
   autor
*/

const int led = 13;

void setup() {
  pinMode(led, OUTPUT);
  Serial.begin(9600); // Configuracion del puerto serial de comunicacion con el ESCLAVO
}

void loop() {
  if (Serial.available()) {  // Verificacion que el puerto serial recibe datos                                  
   delay(10);                
                             
   identificacion(); // Rutina de identificacion de esclavos 1 y 2
   
    while (Serial.available() > 0){Serial.read();} // Rutina de limpieza del buffer del puerto serial
  }
}

void identificacion(){ 
                                // RUTINA DE IDENTIFICACION FISICA Y AUTENTIFICACION
  while (Serial.peek() == 'a'){ // Discriminacion de la letra de identificacion 
  // Cambiar 'a' por 'b' para el segundo esclavo
  
    digitalWrite(led, HIGH);    // Encendido del LED del PIN 13
    Serial.write('A');          // Envio de la letra de incio de trama de autentificacion
    Serial.print(1);            // Envio del numero de autentificacion del esclavo al Maestro
    // Cambiar Serial.print(1) por Serial.print(2) para el segundo esclavo         
    break;
  }
}
NOTA: En el programa encontrarán una subrutina llamada "void identificacion()" que debe ser modificada de la siguiente manera para el caso del Esclavo 2
void identificacion(){ 
                                // RUTINA DE IDENTIFICACION FISICA Y AUTENTIFICACION
  while (Serial.peek() == 'b'){ // Discriminacion de la letra de identificacion 
  // Cambiar 'a' por 'b' para el segundo esclavo
  
    digitalWrite(led, HIGH);    // Encendido del LED del PIN 13
    Serial.write('A');          // Envio de la letra de incio de trama de autentificacion
    Serial.print(2);            // Envio del numero de autentificacion del esclavo al Maestro
    // Cambiar Serial.print(1) por Serial.print(2) para el segundo esclavo         
    break;
  }
}
Al abrir el Monitor Serial y colocar "a" o "b" encontraremos en pantalla lo siguiente:


CONSIDERACIONES FINALES
# Debemos darle un tiempo de retraso (delay) entre cada proceso para este tipo de comunicación, que aumentará a medida que se añadan más subrutinas o se aumenten la cantidad de nodos. Esto en caso la comunicación sea bidireccional.
# Las pruebas se realizaron también a una distancia de 2 m de cable, por lo que es posible establecer nodos de 2 m de separación para este tipo de comunicación.

Autor: 

No hay comentarios:

Publicar un comentario