Avanxe 7 – Aplicación 5: Websocket con ESP32

Aplicación demostrativa utilizando el ESP32 como websocket para enviar y recibir datos desde un explorador web.

Para la aplicación se utilizarán el ESP32, ADC y DAC integrados en la tarjeta Avanxe.

IMPORTANTE: Leer la documentación oficial de Espressif y seguir los pasos para poder programar el ESP32 en Eclipse.

El proyecto se divide en 2 partes:

  1. Código en VHDL que se encarga del control del DAC y adquisición de datos.
  2. Código en Eclipse para el ESP32 utilizando el framework oficial de Espressif ESP-IDF.

El protocolo utilizado para la comunicación con el ESP32 es el RS232 con los siguientes parámetros:

  • 115200 baudios
  • 1 bit de inicio
  • 8 bits de datos
  • 1 bit de paro
  • Sin paridad

Código en VHDL

El código sigue la siguiente estructura:

Se encarga de adquirir los datos que mandan los siete canales del ADC así como de indicarle al DAC qué función generar. Para generar una función se utilizó una memoria ROM en donde se almacenan las muestras  de todas las funciones, cada función se genera a partir de 160 muestras.

El código en VHDL modela la siguiente máquina de estados:

  • Estado 0: Se recibe un byte con la función que generará el DAC (Se generan 5 funciones diferentes)
  • Estado 1: Se recibe un byte que modifica la frecuencia de la función a generar.
  • ESTADOS CANAL N: Consiste en 4 estados que controlan el canal del ADC.

  • EDO N: Selecciona el canal del 0 al 6.

 

  • EDO N+1: Genera un retardo de 10ms  con el contador contaADC para esperar a que el ADC haga la conversión.
  • EDO N+2: Envía un byte con los 8 bits más significativos del valor digital de la conversión.
  • EDO N+3: Espera 20us a que el ESP32 reciba el dato.

El proceso es el mismo para los 7 canales.

Configurar proyecto para ESP32

Una vez descargado el ejemplo se debe configurar algunos parámetros:

1.- Accedemos a la carpeta en donde se encuentre el proyecto desde el Ming32. Ejecutamos el comando “make menuconfig”

2.- Definimos el puerto COM donde se flasheará el ESP32

2.- Siempre guardar los cambios ante cualquier modificación con “Save”

3.- Definir el SSID y la contraseña con la cual se accederá al ESP.

Una vez configurado el proyecto se construye dando clic en Build All para que se actualicen los parámetros modificados.

El código realiza múltiples tareas (task) las cuales ponen al ESP32 en modo servidor, crea la página web ymantienen viva la conexión para la transferencia de datos. También hay dos tareas que se encargan de controlar al UART, transmisión y recepción respectivamente.

void app_main() {
  wifi_setup();
  led_setup();
  ws_server_start();
  init();
  xTaskCreate(&server_task,"server_task",3000,NULL,9,NULL);
  xTaskCreate(&server_handle_task,"server_handle_task",4000,NULL,6,NULL);
  xTaskCreate(&count_task,"count_task",6000,NULL,3,NULL);
  xTaskCreate(rx_task, "uart_rx_task", 1024*2, NULL, 2, NULL);
  xTaskCreate(&tx_task, "uart_tx_task", 1024*2, NULL,1, NULL);

}

La tarea encargada de la transmisión manda dos bytes, la función a generar y la frecuencia.

static void tx_task()
{
    static const char *TAG = "UART_TASK";
    static const char *TX_TASK_TAG = "RX_TASK";
    static const char *RX_TASK_TAG = "RX_TASK";
    esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO);
    const int DELAY = 10 / portTICK_PERIOD_MS; // 1 second

    for(;;){
    	char data1[] = {x2};
    sendData(data1, sizeof(data1));
    char data2[] = {x};
    sendData(data2, sizeof(data2));
    vTaskDelay(DELAY);
    }
}

Utiliza una función llamada sendData para mandar datos por el UART.

int sendData(const char* data, size_t len)
{
    //const int len = strlen(data);
    const int txBytes = 0;
    uart_write_bytes(UART_NUM_1, data, len);
     return txBytes;
}

Dependiendo el byte que se mande es la función a generar: se envía un 0x0A para generar una onda senoidal, 0x14 triangular, 0x1E cuadrada, 0x28  diente de sierra y 0x32 una función random. Para la frecuencia se utiliza un Slider cuyo valor varía de 0 a 255.  Dichos valores se generan desde Java Script dentro del archivo test.j

slider.oninput = function () {
  websocket.send("L" + slider.value);
}

 function FbotonSen() {
    websocket.send("S" + 10);
}

 function FbotonTri() {
    websocket.send("S" + 20);
}

 function FbotonCua() {
    websocket.send("S" + 30);
}

 function FbotonDie() {
    websocket.send("S" + 40);
}

 function FbotonRan() {
    websocket.send("S" + 50);
}

Para la recepción de datos se utiliza la tarea rx_task() la cual se encarga de recibir los 7 bytes correspondientes a los valores de los 7 canales del ADC para después ser enviados a la página web.

static void rx_task()
{
    static const char *RX_TASK_TAG = "RX_TASK";
    esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO);
    uint8_t* data = (uint8_t*) malloc(RX_BUF_SIZE+1);
    while (1) {
    	uint8_t* data = (uint8_t*) malloc(7);
        const int rxBytes = uart_read_bytes(UART_NUM_1, data, 7, 1000 / portTICK_RATE_MS);
        if (rxBytes > 0) {
            data[rxBytes] = 0;
            ESP_LOGI(RX_TASK_TAG, "Read %d bytes: '%d'", rxBytes, data[0]);
            ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rxBytes, ESP_LOG_INFO);
            A1 = data[0];
            A2 = data[1];
            A3 = data[2];
            A4 = data[3];
            A5 = data[4];
            A6 = data[5];
            A7 = data[6];

           // free(data);
        }
    }
    free(data);
}
Menú