Jugando con ESP32 y Arduino IDE

Exploraremos la programación del ESP32 con Arduino IDE, sus funciones y bibliotecas más comunes, las diferencias y nuevas funcionalidades.

 ESP-32

Introducción

Iniciaremos la exploración del ESP32, el nuevo y fantástico kit de desarrollo para IoT. Esta placa desarrollada por Espresiff debería ser la sucesora del NodeMCU, debido a su bajo precio y sus grandes características.

Pero debe saber también que no todas las bibliotecas que o funciones con las que trabaja con el ESP8266 y/o Arduino IDE, están funcionando en esta nueva placa de desarrollo. Probablemente la compatibilidad completa llegue muy pronto, asi que revise regularmente el foro de ESP32 en la pagina web.

Aquí aprenderemos cómo programar el ESP32 en Arduino IDE, explorando sus funciones y librerías más comunes, señalando algunas de las diferencias importantes y las nuevas características introducidas con este gran chip.

En resumen veremos:

  • Salidas Digitales, parpadeando un led.
  • Entrada Digital, lectura de un sensor tactil.
  • Entrada Análoga, lectura de una tensión variable desde un potenciometro.
  • Salida Analógica, control del brillo de un led.
  • Salida Analógica, control de la posición de un servo.
  • Lectura de datos de Temperatura/Humedad con un sensor digital.
  • Conectarse a internet y obtener la hora local.
  • Recibir datos desde una simple pagina web local, encendiendo y apagando un led.
  • Transmitiendo datos a una simple página web local.

Características Principales del ESP32

 Arquitectura del ESP32

El ESP32 es una placa con un valor inferior a US$10, con grandes ventajas sobre placas IoT similares en el mercado.

Esta placa tiene un microprocesador de doble núcleo que ayuda mucho, porque cuando un procesador maneja la comunicación, el otro está a cargo del control de E/S, por ejemplo. Esta característica evitará algunos problemas que ocurren con ESP8266, donde la única CPU necesita detener el control de E/S cuando se maneja con Comunicaciones. Además, el ESP32 ha integrado WiFi, BLUETOOTH, DAC, varios ADC (no solo uno como el ESP8266), sensores táctiles capacitivos, etc. (observe el diagrama de bloques de arriba). Y la buena noticia es que el consumo de energía es casi el mismo que el ESP8266.

A continuación un gráfico que puede mostrarnos sus principales características y diferencias en comparación con ESP8266:

Especificaciones ESP8266 ESP32
MCU Xtensa Single Core 32 bits L106 Xtensa Dual Core 32 bits LX6 (600 DMIPS)
802.11 b/g/n WiFi Si, HT20 Si, HT40
Bluetooth No Bluetooth 4.2 y menor
Frecuencia Típica 80MHz 160MHz
SRAM 160KByte 512KByte
Flash SPI Flash, hasta 16MBytes SPI Flash, hasta 16MByte
GPIO 17 36
PWM Hardware/Software No / 8 canales 1 / 16 canales
SPI / I2C / I2S / UART 2/1/2/2 4/2/2/2
ADC 10 bits 12 bits
CAN No 1
Ethernet MAC interface No 1
Touch Sensor No Si
Sensor de Temperatura No Si
Temperatura de Trabajo -40ºC a 125ºC -40ºC a 125ºC

Propiedades Principales con más detalle

Características Principales

  • Microcontrolador Tensilica LX6 de 240MHz, dual core com 600DMIPS.
  • Memoria SRAM integrada 520KByte
  • Transceptor integrado 802.11 b/g/n HT40 WiFi, banda base, stack y LwIP.
  • Doble modo Bluetooth integrado (clásico y BLE).
  • Flash 16MB, mapeo de memoria para el espacio de código de la CPU.
  • Voltaje de Operación desde 2.3V a 3.6V
  • Temperatura de Operación desde -40ºC hasta +125ºC.
  • Antena integrada en la PCB o con conector IPEX para antena externa.

Sensores

* Amplificador análogo de ultra bajo ruido,
* Sensor Hall
* 10 interfaces táctiles capacitivas.
* Oscilador de Cristal de 32KHz.

34 x GPIO

  • 3 x UART, incluyendo control de flujo por hardware.
  • 3 x SPI
  • 2 x I2S
  • 2 x I2C
  • 18 x canales de entradas ADC
  • 2 x DAC
  • I/O/PWM/timer disponible en cada pin de GPIO.
  • Interface de depuración OpenOCD con buffer TRAX de 32KB.
  • SDIO master/slave de 50MHz
  • Soporta Flash externa SPI de hasta 16MB.
  • Soporta interface SD-card

Relativo a la Seguridad

  • WEP, WPA/WPA2 PSK/Enterprise.
  • Hardware de Encriptación Acelerada: AES/SHA2/Criptografía de Curva Eliptica/RSA-4096.

Rendiemiento

  • Soporta Sniffer, Estación, SoftAP y modo directo WiFi.
  • Rango de datos máximo de 150Mbps@11n HT40, 72Mbps@11n HT20, 54Mbps@11g y 11Mbps@11b.
  • Potencia de transmisión máxima de 19,5dBm@11b, 16,5dBm@11g, 15,5dBm@11n.
  • Sensibilidad mínima de recepción de -97dBm.
  • Rendimiento sostenido en UDP de 135Mbps
  • Consumo en Sueño Profundo de 5µA.

Instalación en Arduino IDE

Utilizaremos el IDE de Arduino para programar nuestro ESP32, de la misma forma que lo hacemos con la familia ESP8266.

Instalar controladores:

Es importante que haya instalado en su computadora el controlador actualizado de CP210x USB a UART. Ingrese en este enlace: usb-to-uart-bridge-vcp-drivers e instale el controlador apropiado para su sistema operativo.

Instalando la Biblioteca

La novedad aquí es que Expressif, en su GitHub, nos dará las instrucciones correctas para la instalación de la biblioteca: arduino-esp32. Sigue las instrucciones para tu sistema operativo. En mi caso (MacOS), la instalación es muy simple:

Abra la Terminal y ejecute el siguiente comando (copiar→ pegar y presionar enter):

mkdir -p ~/Documents/Arduino/hardware/espressif
cd ~/Documents/Arduino/hardware/espressif
git clone https://github.com/espressif/arduino-esp32.git esp32 
cd esp32/tools/
python get.py

Después de eso, reinicie el Arduino IDE y listo. Debes ver varias tablas en el menú “HERRAMIENTAS”. Seleccione el apropiado para usted. En general, el MÓDULO ESP32 DEV “genérico” funciona bien.

Cuando abre el Arduino IDE por primera vez, notará que la velocidad de carga predeterminada es 921600 baudios. Esto puede provocar inestabilidad. ¡Cámbialo a 115,200 baudios!

Parpadeando un LED

 Pines del ESP32

Como siempre, lo primero que debemos hacer cuando exploramos un nuevo hardware es hacer parpadear un led. Vaya al menu de ejemplos y cargue el programa de Blink.

El kit de desarrollo ESP32, tiene un led inforporado que está conectado a su GPIO2. Es importante verificar si el IDE de Arduino reconoce automáticamente el LED_BUILTIN. Si no debe agregar la siguiente línea:

#define LED_BUILTIN		2

Cada tarjeta ESP32 tiene un LED interno conectado a un diferente GPIO.

/*
  Usamos el ESP32S de DIYmall, que se define como una placa Node32S, o ESP32 dev Module, la cual
  para cargar el programa se debe resetear manteniendo presionado el botón que se encuentra a la
  derecha del conector de USB visto de frente, una vez que compila el programa y detecta el RST 
  presionado, el IDE procede a cargar el programa en el ESP32.
*/

#define LED_BUILTIN   2

void setup() {
  Serial.begin(115200);
    while(!Serial){;}
  
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.println("\n\nESP32 Inicialiado");
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.println("Encendemos");
  delay(2000);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.println("Apagamos");
  delay(3000);
}

Debajo del LED interno parpadea (observe la luz azul) junto con uno externo conectado a GPIO 2:

ESP32 Blink

Hay varios tarjetas diferentes con diferentes mapas de pin en el mercado. El diagrama de arriba muestra la placa que estoy usando. Puede encontrarlo aquí: ESP32-Development-Board.

¡Perfecto! Por lo tanto, digitalWrite() funciona perfectamente, del mismo modo con ESP8266 y Arduino. Por cierto, digitalRead() también funciona de la misma manera para leer una entrada digital, como un botón, por ejemplo.

Sensor Touch

Pasamos a una nueva característica interesante, el sensor táctil.

El ESP32 tiene 10 sensores táctiles capacitivos internos. Puede usarlo como botones, por ejemplo.

Esos sensores están conectados con varios GPIO:

  • T0: GPIO4
  • T1: GPIO0
  • T2: GPIO2
  • T3: GPIO15
  • T4: GPIO13
  • T5: GPIO12
  • T6: GPIO14
  • T7: GPIO27
  • T8: GPIO33
  • T9: GPIO32

Para leerlos debes usar la función: touchRead(Touch Pin#);

Por ejemplo, para leer el sensor táctil 0 (T0), debe hacer algo como:

int value = touchRead(4);

Vamos a crear un código, donde si tocamos el sensor T0 (GPIO4), el LED se encenderá.

Use el monitor serie para verificar los valores leídos por el sensor y ajuste el código correctamente.

Debajo del código completo:

/***************************************************** 
* ESP32 Touch Test and LED Ctrl
* Touch pin ==> Touch0 is T0 which is on GPIO 4 (D4).
* LED pin   ==> D2
* 
* MJRoBot.org 6Sept17
*****************************************************/
#define TOUTCH_PIN 	T0 		// ESP32 Pin GPIO4 o D4
#define LED_PIN 		2

int touch_value = 100;

//---------------------------------------------------
void setup(){
  Serial.begin(115200);
  	 while(!Serial){;}
  	 
  Serial.println("ESP32 Touch Test");
  pinMode(LED_PIN, OUTPUT);
  digitalWrite (LED_PIN, LOW);
}

//--------------------------------------------------
void loop(){
  touch_value = touchRead(TOUTCH_PIN);
  
  Serial.println(touch_value);
  
  if (touch_value < 50){
    digitalWrite(LED_PIN, HIGH);
  	 }
  else{
    digitalWrite(LED_PIN, LOW);
  	}
  delay(1000);
}

ESP32 Touch

Entrada Análoga

Ahora probaremos como ingresar valores análogos de voltaje con un máximo de 3,3Vdc.

Hay en total 18 canales de entrada ADC de 12 bits cada uno, versus 1 ADC de 10 bits del ESP8266.

Canales ADC del ESP32:

  • GPIO0 =⇒ ADC2CH1 * GPIO2 =⇒ ADC2CH2
  • GPIO4 =⇒ ADC2CH0 * GPIO12 =⇒ ADC2CH5
  • GPIO13 =⇒ ADC2CH4 * GPIO14 =⇒ ADC2CH6
  • GPIO15 =⇒ ADC2CH3 * GPIO25 =⇒ ADC2CH8
  • GPIO26 =⇒ ADC2CH9 * GPIO27 =⇒ ADC2CH7
  • GPIO32 =⇒ ADC1CH4 * GPIO33 =⇒ ADC1CH5
  • GPIO34 =⇒ ADC1CH6 * GPIO35 =⇒ ADC1CH7
  • GPIO36 =⇒ ADC1CH0 * GPIO37 =⇒ ADC1CH1
  • GPIO38 =⇒ ADC1CH2 * GPIO39 =⇒ ADC1CH3

Para leer una entrada análoga, debe hacer lo mismo que ha hecho con el Arduino IDE y el ESP8266:

int analog_value = analogRead(36);

Es muy importante tener en cuenta que los ADC del ESP32 tienen 12bits de resolución (frente a 10bits en ESP8266 y Arduino), por lo que el rango total de lectura de ADC va a 4.095 (en vez de 1.027 en Arduinos y ESP8266) cuando se aplica un máximo de 3.3V a sus entradas.

Para la entrada, usemos un potenciómetro de 10K ohm, conectándolo entre 3.3V y GND. Usemos su salida variable del potenciometro para la entrada para los pines ESP32 ADC. El diagrama de arriba muestra el potenciómetro conectado a GPIO36 que es el ADC1 canal 0. Pruebe también otras entradas en su tarjeta.

#define ANALOG_PIN_0  36

int analog_value = 0;

//----------------------------------------------------
void setup(){
  Serial.begin(115200);
    while (!Serial) {;}
    
  Serial.println("\n\nESP32 Analog IN Test");
}

//----------------------------------------------------
void loop(){
  analog_value = analogRead(ANALOG_PIN_0);

  float voltage = (analog_value * (3.3 / 4095));
  
  Serial.print("Valor Analogo: ");  Serial.print(analog_value);
  Serial.print(", Voltaje: ");      Serial.println(voltage, 3);
  delay(500);
}

Gire su potenciómetro y observe en la salida del Serial Monitor del IDE Arduino, las mediciones que van de 0 a 4095.

Salida Análoga usando PWM (dimmer digital)

Si queremos Atenuar un LED en ESP8266 o Arduino, podemos simplemente usar un comando como analogWrite(), que variará el valor de PWM de su salida, simulando un valor analógico. Desafortunadamente, todavía no tenemos ese tipo de comando desarrollado para el ESP32 en Arduino IDE. Pero la muy buena noticia es que los 36 GPIO's del ESP32 tienen una capacidad PWM, ¡lo que es genial!. Solo debemos usar código más complejo para alcanzar el mismo resultado.

Entonces, programemos uno de esos GPIO con una señal de salida PWM.

Puede encontrar un muy buen tutorial en detalles sobre cómo funciona PWM en este enlace: esp32-arduino-led-pwm-fading.

Lo primero que hay que pensar sobre la generación de una señal PWM es su frecuencia. Utilizaremos un valor de 5000 Hz, que funciona bien con el LED. También debemos especificar el canal LED PWM y la resolución del ciclo de trabajo PWM, en bits. Podemos elegir un canal de 0 a 15 y una resolución entre 1 y 16 bits. Usaremos el canal 0 y una resolución de 8 bits.

int freq = 5000;
int ledChannel = 0;
int resolution = 8;

Usemos GPIO2, donde tenemos nuestro LED externo conectado (y el interno) o podemos usar el GPIO0 para un led externo.

#define LED_PIN	0

Estos parámetros deben ser definidos en la etapa del setup(), usando las siguientes funciones:

void setup(){
	ledcSetup( ledChannel, freq, resolution );
	ledcAttachPin( LED_PIN, ledChannel );
}

Para encender el LED con un brillo específico, debemos definir el “ciclo de trabajo”.

Por ejemplo, para apagar el LED, el ciclo de trabajo debe ser cero y la función ledcWrite (ledChannel, dutyCycle) utilizada para enviar el valor a través de un canal PWM específico:

int dutyCycle = 0;

ledcWrite( ledChannel, dutyCycle );

Los diferentes valores de la variable dutyCycle encenderán el LED con diferente brillo. Esta variable, dutyCycle, variará de 0 a 255, una vez que la resolución utilizada sea de 8 bits.

Podemos usar el potenciómetro (conectado a la variable analog_value) para configurar manualmente la variable dutyCycle, pero una vez que su rango de valores sea diferente, usemos una función de mapa para hacer coincidir la entrada y la salida:

dutyCycle = map( analog_value, 0, 4095, 0, 255 );

Ahora veremos el código completo:

/***************************************************** 
* ESP32 Analog Input/Output Test 
* Analog Input: ADC_1_0 pin ==> GPIO36 (VP).
* PWM LED pin   ==> GPIO0
* 
* MJRoBot.org 6Sept17
*****************************************************/
//Analog Input
#define ANALOG_PIN_0  36

// PMW LED
#define LED_PIN       0

int freq = 3000;          // Periodo de PWM
int ledChannel = 0;
int resolution = 8;
int dutyCycle = 0;

int analog_value = 0;
//-------------------------------------------------------
void setup(){
  Serial.begin(115200);
    while(!Serial){;}

  Serial.println("\n\nESP32 Analog IN/OUT Test");
  
  ledcSetup(ledChannel, freq, resolution);
  ledcAttachPin(LED_PIN, ledChannel);
  ledcWrite(ledChannel, dutyCycle);
}

//-------------------------------------------------------
void loop(){
  analog_value = analogRead(ANALOG_PIN_0);
  Serial.println(analog_value);
  
  dutyCycle = map(analog_value, 0, 4095, 0, 255);
  ledcWrite(ledChannel, dutyCycle);
  delay(500);
}

ESP32 PWM + POT

Control de Motor Servo

Controlemos un Motor Servo usando la capacidad PWM de nuestro ESP32.

El código será básicamente el mismo que se usó para controlar el brillo del LED.

En primer lugar, es importante recordar que la frecuencia para trabajar con un Micro Servo es de 50Hz, por lo que debemos cambiar el parámetro de frecuencia a 50 (en lugar de 5000 con LED). También debemos especificar el canal LED PWM y la resolución del ciclo de trabajo PWM, en bits. Usaremos nuevamente el canal 0 y una resolución de 8 bits.

int freq = 50;
int channel = 0;
int resolution = 8;

La salida hacia el Motor Servo, se conectará a la salida GPIO5.

#define SERVO_PIN	5

Al igual que con el LED, esos parámetros se deben definir durante la fase de setup(), utilizando las siguientes funciones:

void setup(){
	ledcSetup( channel, freq, resolution );
	ledcAttachPin( SERVO_PIN, channel );
}

Para colocar el servo en un ángulo específico, debemos definir el “ciclo de trabajo” (por favor, vea el diagrama de arriba).

Por ejemplo, para colocar el servo alrededor de 90 grados, el ciclo de trabajo debe estar alrededor de 21 y la función ledcWrite(ledChannel, dutyCycle) se debe usar para enviar el valor a través del canal PWM:

int dutyCycle = 21;

ledcWrite( channel, dutyCycle );

Diferentes valores de la variable dutyCycle posicionarán el servo con diferentes ángulos. Esta variable, dutyCycle, debe variar de 10 a 32 (este rango se obtuvo manualmente).

Al igual que con el LED, el potenciómetro (conectado a la variable de valor analógico) se puede utilizar para configurar manualmente la variable dutyCycle y así cambiar la posición del servo. Una vez que sus rangos de valores son diferentes, utilicemos una función de mapa para que coincida con la entrada y la salida:

dutyCycle = map( analog_value, 0, 4095, 10, 33);

Ahora veremos el código completo:

/***************************************************** 
* ESP32 Servo Control 
* Analog Input: ADC_1_0 pin ==> GPIO36 (VP).
* PWM SERVO pin   ==> GPIO 05
* 
* MJRoBot.org 6Sept17
*****************************************************/

//Analog Input
#define ANALOG_PIN_0 36

int analog_value = 0;

// PMW SERVO
#define SERVO_PIN 5

int freq = 50;
int channel = 0;
int resolution = 8;
int dutyCycle = 21;

//----------------------------------------------------
void setup(){
  Serial.begin(115200);
  	while(!Serial){;}
  
  Serial.println("\n\nESP32 Servo Control");
  
  ledcSetup(channel, freq, resolution);
  ledcAttachPin(SERVO_PIN, channel);
  ledcWrite(channel, dutyCycle);
}

//----------------------------------------------------
void loop(){
  analog_value = analogRead(ANALOG_PIN_0);
  
  Serial.print(analog_value);
  Serial.print(" Duty Cycle ==> ");
  Serial.println(dutyCycle);
  
  dutyCycle = map(analog_value, 0, 4095, 10, 33);
  ledcWrite(channel, dutyCycle);
  delay(50);
}

Ahora podemos trabajar con el sensor ultrasónico en la parte superior del servo y construir un Radar IoT!. ¡Pero este será otro tutorial!

ESP32 Servo

Conectando a Internet para tener la hora local

Después de probar algunas de las capacidades digitales/analógicas y de entrada/salida de GPIO, ¡conectemos nuestro ESP32 en Internet!

Con la familia ESP8266 estábamos usando la biblioteca esp8266wifi.h para eso. Con el ESP32, la biblioteca que se debe usar es:

<wifi.h>

Un ejemplo muy simple sería programar nuestra placa para capturar desde Internet la hora local. Esta es una muy buena característica para tener a mano en proyectos. El siguiente código lo hará por nosotros:

/**************************************************************
 * Local Time Stamp with ESP32
 * Developed by Marcelo Rovai - 8 September 2017
 **************************************************************/
#include <NTPClient.h>
#include <WiFi.h>
#include <WiFiUdp.h>

#define NTP_OFFSET  	-3  * 60 * 60 		// In seconds
#define NTP_INTERVAL 	60 * 1000    		// In miliseconds
#define NTP_ADDRESS  	"europe.pool.ntp.org"

WiFiUDP ntpUDP;

NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);

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

Simple Servidor WiFi

Probemos ahora nuestro ESP32 como un servidor WiFi simple.

  • Abra el menú de ejemplos en el IDE Arduino y obtenga el programa de ESP32 WiFi/SimpleWiFiServer.ino

Acerca de este programa:

Parpadeo de LED mediante WiFi Web Server

  • Creado para el Arduino el 25/11/2012 por Tom Igeo.
  • Portada para Sparkfun ESP32 31.01.2017 por Joan Hendrik Berlin.

Un servidor web simple que le permite parpadear un LED a través de la web. Este programa imprimirá la dirección IP de su red WiFi ESP32 en el monitor serie. Desde allí, puede abrir esa dirección en un navegador web para encender y apagar el LED en el pin 5.

Si la dirección IP de su tarjeta es por ejemplo 10.0.1.40:

Este ejemplo está escrito para una red que utiliza el cifrado WPA. Para WEP o WPA, cambie la llamada adecuadamente de Wifi.begin().

Circuito: LED conectado al pin 5

Entonces, usemos el programa sin modificaciones significativas. Cambiar el pin del LED externo a GPIO5.

Por supuesto, si prefiere cambiar el código para GPIO2 sin cambiar el HW.

Primero ingrese sus credenciales de la red WiFi:

const char * ssid = "SSID";
const char * password = "su-password";

Y cargue el programa en su ESP32.

iot/esp/esp32-ide.txt · Última modificación: 2020/07/03 17:12 (editor externo)
Recent changes RSS feed Creative Commons License Donate Minima Template by Wikidesign Driven by DokuWiki