Una de las ventajas mas grande de las comunicaciones hoy en dia es la transmision de los datos por medios inalambricos el cual utilizan medios no guiados para la transmision, esto ha echo que nosotros podamos transformar la forma en como los dispositivos se comunican y transfieren la informacion.

El modulo ESP8266

Es un dispositivo digital que cuenta con un microprocesador y una electronica necesaria para poder realizar la transferencia de los datos de modo inalambrico utilizando el protocolo 802.11 b/g/n.
Adicional, el modulo cuenta con 2 pines de Entrada/Salida de proposito general(GPIO) y con un puerto de comunicacion serial que soporta la conexion con el protocolo RS232.
Cabe resaltar que los niveles de tension de este CHIP son a 3.3V, tanto la alimentacion como la tension en los puertos GPIO y Serial.

Laboratorio:

  • Idea: Poder enviar datos por medio de los puertos seriales de un Modulo a otro sin utilizar ningun AccessPoint adicional que no sean ellos mismos haciendo que el envio de datos sea transperante entre los puertos.

  • Investigacion Previa: Se descargaron los DataSheet de los dispositivos y tambien la guia de los comandos AT, se analizaron algunos de los comandos disponibles y concluimos que es posible configurarlos siguiendo el modelo "Cliente-Servidor"

  • Conclusion: Desde un Cliente, Podemos enviar datos recolectados por el puerto serie del dispositivo hacia la red Inalambrica, estos datos seran recogidos por el Servidor que a su vez los envia por el serial.
    Al lograr esto, podemos enviar datos desde cualquier Lenguaje de programacion o Aplicacion que permita la conexion con dispositivos seriales que se encuentren a largas distancias o en lugares donde no es posible cablear, asi romperiamos el medio guiado para convertirlo en un medio Inalambrico.
    Esto haria que la transmision de datos de un puerto serial a otro sean totalmente transparentes.

Herramientas

  • Computador con GNU/Linux instalado, Basada en debian preferiblemente.
  • 2 x adaptadores USB-TTL
  • 2 x Modulos ESP8266-01 con Firmware AT instalado.
  • Arduino IDE 1.8.5
  • 2 x PIC18F4550

Conectando el CHIP a un Computador.

Para Interfazar el CHIP con el puerto USB de nuestro computador, es necesario utilizar un dispositivo de intermedio (USB-TTL), para ello tenemos la siguiente imagen que nos guiara sobre la conexion.
Normal-Mode
Conexion del CHIP en modo "Normal u Operacion" con modulo USB-TTL

Una vez echa la conexion procedemos a conectar la interfaz TTL al computador por algun puerto USB disponible.

Confirmamos sobre el PC la disponibilidad del nuevo Producto conectado con el comando "dmesg"

$ sudo dmesg -c 
[20839.361629] usb 2-1: new full-speed USB device number 30 using xhci_hcd
[20839.510384] usb 2-1: New USB device found, idVendor=067b, idProduct=2303
[20839.510389] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[20839.510393] usb 2-1: Product: USB-Serial Controller
[20839.510396] usb 2-1: Manufacturer: Prolific Technology Inc.
[20839.510934] pl2303 2-1:1.0: pl2303 converter detected
[20839.511451] usb 2-1: pl2303 converter now attached to ttyUSB0

Como evidenciamos, el PC detecto un nuevo dispositivo USB que se ha conectado, este ha tomado un nombre de dispositivo que podremos ver sobre el archivo /dev/ttyUSB0

Procedemos a conectar el otro dispositivo y validamos su conexion.

$ sudo dmesg -c 
[21018.032369] usb 2-2: new full-speed USB device number 31 using xhci_hcd
[21018.180845] usb 2-2: New USB device found, idVendor=067b, idProduct=2303
[21018.180849] usb 2-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[21018.180852] usb 2-2: Product: USB-Serial Controller
[21018.180854] usb 2-2: Manufacturer: Prolific Technology Inc.
[21018.181342] pl2303 2-2:1.0: pl2303 converter detected
[21018.182131] usb 2-2: pl2303 converter now attached to ttyUSB1

Este otro, fue montado sobre el archivo /dev/ttyUSB1

Instalando miniterm.py

miniterm.py, es una aplicacion de la herramienta pyserial con la cual podremos acceder al puerto serial que se ha creado al conectar nuestro dispositivo al PC por USB.

para instalar la herramienta, se debe de contar con el gestor de librerias para python "pip"

$ sudo pip install pyserial

una vez instalada, tendremos la herramienta miniterm.py disponible sobre nuestro path del sistema.

Si todo ha sido correcto hasta ese paso, podremos conectarnos al modulo para empezar a configurarlo.

Hola AT

Para comprobar que el CHIP este funcionando y que tiene el firmware AT instalado correctamente, vamos a proceder a interfazar nuestro PC con el Modulo por medio de la comunicacion Serial, para ello utilizaremos la aplicacion miniterm.py que hemos instalado.

La tasa de bits o el BaudRate por defecto del dispositivo es de "115200", este valor es necesario tenerlo en cuenta para su conexion.
Tambien debemos de tener encuenta los puertos virtuales que se montaron sobre el host al conectar los dispositivos /dev/ttyUSB0 y /dev/ttyUSB1

Conectarse al CHIP con miniterm.py

$ miniterm.py  /dev/ttyUSB0 115200

--- Miniterm on /dev/ttyUSB0  115200,8,N,1 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---

si no ha dado ningun error y la terminal se queda a la espera, indica que todo salio correcto.

Para comprobar el Status del CHIP procedemos con el primer comando.
Verificar estatus

AT
OK

AT
Si la salida es OK, determina que el dispositivo esta en linea y listo para ser configurado.

La lista completa de comandos disponibles para esta version del Firmware se pueden encontrar sobre el DataSheet del desarrollador.

Verificando la version del Firmware.

Posiblemente el chip que tengamos tenga alguna version de Firmware no actualizada, podemos verificarla por medio del siguiente comando.

AT+GMR
AT version:1.6.0.0(Feb  3 2018 12:00:06)
SDK version:2.2.1(f42c330)
compile time:Feb 12 2018 16:31:29
Bin version(Wroom 02):1.6.1
OK

Si la version actual no es la ultima, podemos realizar la actualizacion del Firmware para el modulo por medio del siguiente tutorial.
https://uavlabs.org/2018/06/02/actualizando-firmware-de-esp8266/

Si en algun momento necesitamos restaurar los valores por defecto para el CHIP, podemos hacerlo con el siguiente comando.

AT+RESTORE

Monitor de terminal de Arduino (Opcional).

Desde este punto, decidimos trabajar con el emulador de terminal de arduino, ya que el anteriormente mencionado, tiene problema con la codificacion de los caracteres en algun momento, probocando que el Modulo se pierda y no entienda la informacion, probablemente el error se deba a la velocidad de los baudios con la que se encuentra por defecto el chip, se realizaran las pruebas necesarias para determinar el por que de este error.

Seteando el modulo Wifi.

El modulo, permite almaenar sobre su misma memoria flash los cambios realizados sobre algunos parametros de inicializacion del chip.

Para empezar con las configuracion que se realizaran sobre el modulo, es necesario setear los baudios del puerto Serial a una tasa de bits mas baja con el fin de que los mismos datos no se pierdan en la transferencia.

Configurando los baudios o tasa de bit por segundo del dispositivo y almacenandolo en flash.

1.- Consultamos la configuracion actual para el UART

AT+UART?
+UART:115273,8,1,0,1
OK
  1. Reconfiguramos los datos del puerto y sobreescribimos la memoria.
AT+UART_DEF=9600,8,1,0,1
OK

Esto pondra el puerto serial del dispositivo en sincronizacion con todo lo que este bajo la velocidad de 9600 Baudios por segundo.
Es necesario realizar esta configuracion sobre los dos modulos.

Configurando el Modulo ESP8266 - Servidor

Lo primero que tenemos que hacer con los modulos, es confirmar el MODO de funcionamiento actual, por defecto vienen en modo Servidor los dos, para ello definimos cual de los dos CHIPS usaremos como servidor y lo conectamos.
Despues de conectarnos y validar que el CHIP responde al "Hola AT" podremos configurar el servidor.

  1. Consultamos el modo del chip
AT+CWMODE?
+CWMODE:2

OK

Los modos disponibles para este son:
1: Station mode
2: SoftAP mode
3: SoftAP+Station mode

ya que por defecto se encuentra en el modo 2, no es necesario reconfiguralo, si lo quisieramos hacer, podriamos escribir en memoria el valor del modo con el siguiente comando

AT+CWMODE_DEF=2
OK

Cambiando el nombre de la red Wifi para el modulo

AT+CWSAP_DEF="ESP-Server","",1,0,8,0
OK

Veremos que se creara la nueva red y sera visible para nuestro alcance local.
La red quedo configurada de la siguiente manera:

  • SSID: ESP-Server
  • Pass: NO
  • Channel:1
  • Encriptacion: No
  • Maximo Clientes: 8
  • Red visible: OK

Activamos el soporte a multiples conexiones al servidor.

AT+CIPMUX=1
OK

Creamos un servidor TCP que escuchara por el puerto 22 del dispositivo.

AT+CIPSERVER=1,22
OK

Validamos la IP con la cual podremos acceder al puerto del dispositivo

AT+CIFSR
+CIFSR:APIP,"192.168.4.1"
+CIFSR:APMAC,"86:f3:eb:96:87:90"
OK

Configurando el Modulo ESP8266 - Cliente

Una vez configurado el servidor, debemos configurar uno de nuestros clientes para que se conecte con el servidor.

Lo primero que hacemos es conectar el dispositivo y configurarlo en modo cliente

AT+CWMODE_DEF=1
OK

Listamos los accesPoints disponibles para la conexion, entre ellos deberia de estar el "ESP-Server" que se ha creado.

AT+CWLAP
+CWLAP:(0,"ESP-Server",-37,"86:f3:eb:96:87:90",1,-16,0,0,0,3,0)
+CWLAP:(4,"Mired",-58,"fc:c8:97:65:59:8b",12,-49,0,5,3,7,0)

OK

Como observamos, encuentra el modulo servidor disponible para conexion como AccesPoint.

Salvamos en memoria flash los datos de conexion a la red del servidor.

AT+CWJAP_DEF="ESP-Server",""
WIFI CONNECTED
WIFI GOT IP

OK

Validamos la ip que ha tomado el dispositivo

AT+CIFSR
+CIFSR:STAIP,"192.168.4.2"
+CIFSR:STAMAC,"18:fe:34:d4:b0:9f"

OK

Como evidenciamos, tomo una ip despues de la puerta de enlace destinada sobre el Servidor.

Habilitamos sobre el cliente las conexiones multiples

AT+CIPMUX=1
OK

Iniciamos una conexion con el servidor por el puerto 22 tal cual como se destino previamente, para ello utilizaremos el protocolo TCP.

AT+CIPSTART=1,"TCP","192.168.4.1",22
1,CONNECT

OK

Envio de datos en modo half duplex.

Para lograr que desde el servidor podamos enviar datos a el cliente y viceversa, tambien debemos de configurar sobre el servidor el puerto y la ip de por donde escuchara el cliente.

Sobre el cliente.
Habilitamos el la escucha por el puerto 22

* AT+CIPSERVER=1,22
OK

Sobre el Server.
Agregamos la conexion hacia el puerto 22 del cliente indicando que tambien vamos a proceder con el envio de datos hacia el

AT+CIPSTART=1,"TCP","192.168.4.2",22
OK

Enviando datos de un Modulo a otro.

Para generar el envio de los datos por, es necesario indicar el ID del equipo y el numero de caracteres que contemplara la cadena para el envio de datos.

Del server al Cliente

AT+CIPSEND=1,9
>holamundo

Si todo fue correcto, podremos enviar datos en los dos sentidos invocando el ultimo parametro.

Probando la comunicacion desde dos PIC18F4550 via RS232

Ahora, para probar la transparencia de la comunicacion con los modulos, vamos a unificar el protocolo con dos PICS de la marca MicroChip el cual estaran conectados siguiendo el modelo "Cliente-Servidor" utilizando comunicacion Serial RS232.

Los MicroControladores inicializaran el puerto serial que a su vez por medio del mismo utilizara los comandos AT del modulo ESP8266 para Lograr un Link o Enlace TCP utilizando el protocolo 802.11g.

Cabe aclarar que la comunicacion entre los dos PICs sera transparente, es decir que no entenderan que detras de la comunicacion serial existe una red Inalambrica.

Codigo de prueba.

El siguiente codigo, describe el funcionamiento de lo antes mencionado.

  • Tendremos dos PIC18f4550 conectados en modelo cliente servidor
  • El PiC Cliente tendra 3 botones que encenderan los numeros binarios representados por 3 posibles combinaciones de bits en el Servidor.
  • Estos numeros se visualizaran en un Display d 7 Segmentos conectado a uno de los puertos del PIC Servidor.
  • El pic Servidor, al mismo tiempo podra enviar un dato al pic cliente que encendera un LED como marca de dato recibido.
  • Esto demostrara que es posible realizar una comunicacion entre dos PICS Bidireccional FullDuplex de modo Inalambrico utilizando dos moduloes ESP8266.

Para el proyecto, tendremos dos versiones de la comunicacion RS232.

  1. Directa entre los dos PICs via Cable utilzando RS232.
  2. Indirecta RS232, via ESP8266 utilizando TCP.

Codigo Conexion Cableada.

El siguiente codigo, realiza la conexion entre los dos PICs de modo cableada utilizando RS232.

Codigo del PIC que "Envia"

#include <18F4550.h>
#fuses xt, nowdt, noprotect, put, CPUDIV1
#use delay(internal = 8000000)
#use rs232(baud = 9600, bits = 8, parity = N, xmit = PIN_C6, RCV = PIN_C7, stop=1, ERRORS)

/*
  Este programa recibe 3 pulsos en binario y envia su correspondiente en
  deciman por rs-232
*/

//definicion de los puertos
#use fast_io(a)
#use fast_io(b)

#byte PORTB = 0XF81

#int_rda
void rb_isr() {
    // si algo llega por rs-232
    if (kbhit()) {
        char dato_recibido = getc();
        if (dato_recibido == '1') {
            output_toggle(pin_a0);
        }
    }
}

int leer_puerto() {
    int puertob = PORTB;
    puertob = puertob >> 4;
    return puertob += 48;
}

void main() {
    set_tris_b(0xff); // inicia el puerto B somo entrada. 
    set_tris_a(0x00); // inicia el puerto A somo salida.
    //habilita las interrupciones por serial
    enable_interrupts(int_rda);
    //habilita las interrupciones glovales
    enable_interrupts(global);
    while (true) {
        delay_ms(200);
        if (input(PIN_B4) || input(PIN_B5) || input(PIN_B6)) {
            putc(leer_puerto());
        }
    }
}

Codigo del PIC que "Recibe"

#include <18F4550.h>
#fuses xt, nowdt, noprotect, put, CPUDIV1
#use delay(internal = 8000000)
#use rs232(baud = 9600, bits = 8, parity = N, xmit = PIN_C6, RCV = PIN_C7, stop=1, ERRORS)
// Indica el uso de los puertos 

#use fast_io(b)
#use fast_io(d)

//numeros del display
int8 display[10] = {192,249,164,176,153,146,130,248,128,144};

#int_rda
void rb_isr(){ 
    //si llega algo al puerto
   if(kbhit()){
      int dato_recibido = getc();
      dato_recibido -= 48;
      output_d(display[dato_recibido]);
   }
}

#int_rb
void int_rb_pulsadores(){
   if (input(pin_b4)){    
       putc('1');
       delay_ms(100);
   }
}

void main(){
    set_tris_b(0xFF); // Inicia el puerto B como Entrada. 
    set_tris_d(0x00); // indica el puerto D como Salida

    //habilita las interrupciones por serial
    enable_interrupts(int_rda);
    //habilita las interrupciones puerto b
    enable_interrupts(int_rb);
    //habilita las interrupciones glovales
    enable_interrupts(global);
    //intrerrupcion por flanco de subida
    ext_int_edge(L_TO_H);
}

Cabe resaltar sobre los dos anteriores codigos que el que Envia no solo envia, la comunicacion es en dos sentidos, los hemos llamado asi por definicion.

Codigo Conexion Inalambrica.
Este codigo, realiza la misma comunicacion anterios pero de manera inalambrica utilizando los modulos previamente mencionados.
El que Envia, actuara como "Cliente" y el que recibe como "Servidor", esta denotacion se le ha dado de esta manera por que sobre la red inalambrica que establencen los dos dispositivos se sigue este modelo Cliente-Servidor.
Recordar que uno de los modulos actua como "SoftAP" y el otro como "Cliente IP"

Antes de inicializar el codigo, es necesario haber configurado y flasheado sobre la memoria los dos ESP8266 los comandos necesarios para poder estabilizar la conexion o el enlace Wi-Fi entre los dos dispositivos, esto se debe de realizar por que no nos parecio necesario poner dentro del codigo del PIC parametros de inicializacion que se pueden realizar del lado del modulo Wi-Fi.

Codigo del Cliente (Envia).

#include <18F4550.h>
#fuses xt, nowdt, noprotect, put, CPUDIV1
// se define el uso del reloj interno a 8Mhz
#use delay(internal = 8000000)
// se define la comunicacion serial a 9600 baudios, sin paridad y un bit de stop
#use rs232(baud = 9600, bits = 8, parity = N, xmit = PIN_C6, RCV = PIN_C7, stop=1, ERRORS)

/*
  Este programa recibe 3 pulsos en binario y envia su correspondiente en
  deciman por rs-232
*/

//definicion de los puertos
#use fast_io(a)
#use fast_io(b)

#byte PORTB = 0XF81

#int_rda
void rb_isr() {
    // si algo llega por rs232
    if (kbhit()) {
        char dato_recibido = getc();
        if (dato_recibido == 'j') {
            output_toggle(pin_a0);
        }
    }
}

int leer_puerto() {
    int puertob = PORTB;
    puertob = puertob >> 4;
    return puertob += 107;
}

void main() {
    set_tris_b(0xff); // inicia el puerto B somo entrada.
    set_tris_a(0x00); // inicia el puerto A somo salida.

    /********* conexion *********/
    delay_ms(9000);
    printf("AT+CIPMUX=1\r\n");

    delay_ms(3000);
    printf("AT+CIPSERVER=1,222\r\n");
    
    delay_ms(5000);
    printf("AT+CIPSTART=2,\"TCP\",\"192.168.4.1\",222\r\n");
    
    //indica que se termino la etapa de conexion
    output_high(pin_a0);
    
    /********* fin conexion *********/

    //habilita las interrupciones por serial
    enable_interrupts(int_rda);
    
    //habilita las interrupciones glovales
    enable_interrupts(global);

    while (true) {
        delay_ms(200);
        if (input(PIN_B4) || input(PIN_B5) || input(PIN_B6)) {
            int caracter = leer_puerto();
            if(caracter != 107){
               printf("AT+CIPSEND=2,1\r\n");
               delay_ms(500);
               printf("%c\r\n",caracter);
            }
        }
    }
}

Codigo del Server (Recibe).

#include <18F4550.h>
#fuses xt, nowdt, noprotect, put, CPUDIV1
// se define el uso del reloj interno a 8Mhz
#use delay(internal = 8000000)
// se define la comunicacion serial a 9600 baudios, sin paridad y un bit de stop
#use rs232(baud = 9600, bits = 8, parity = N, xmit = PIN_C6, RCV = PIN_C7, stop=1, ERRORS)

#use fast_io(a)
#use fast_io(b)
#use fast_io(d)

int8 display[10] = {192,249,164,176,153,146,130,248,128,144};
char dato_recibido = 'l';

#int_rda
void rb_isr() {
    // si algo llega por rs232
    if (kbhit()) {
         dato_recibido = getc();
        if (dato_recibido > 107) {
            output_toggle(pin_a0);
        }
    }
}


void main(){
    set_tris_b(0xff); // inicia el puerto B somo entrada.
    set_tris_d(0x00); // inicia el puerto B somo entrada
    set_tris_a(0x00); // inicia el puerto A somo salida.
    
   /******CONFIGURACION COMUNICACION******/
   
   delay_ms(9000);
   printf("AT+CIPMUX=1\r\n");
   
   delay_ms(5000);
   printf("AT+CIPSERVER=1,222\r\n");
   
   delay_ms(6000);
   printf("AT+CIPSTART=2,\"TCP\",\"192.168.4.2\",222\r\n");
   
   delay_ms(1000);
       //indica que se termino la etapa de conexion
    output_high(pin_a0);
    /********* fin conexion *********/

    //habilita las interrupciones por serial
    enable_interrupts(int_rda);
    
    //habilita las interrupciones glovales
    enable_interrupts(global);
    
    
  while (true) {
        delay_ms(200);
        if (input(PIN_B4)) {
               printf("AT+CIPSEND=2,1\r\n");
               delay_ms(500);
               printf("j\r\n");
        }
        if (dato_recibido > 107) {
          dato_recibido -= 107;
          output_d(display[dato_recibido]);
        }
    }
}

Pruebas de la comunicacion realizada

Adjuntamos adicionalmente un Video donde se describe la comunicacion realizada.

Si se desea, se puede descargar el codigo fuente implementado en esta comunicacion desde uno de nuestros repositorios en GitHub.

URL Repositorio: https://github.com/UavLabsColombia/pic18f4550-rs232-esp8266