Hackathon - Curso introductorio

Este curso introductorio te proporcionará los conocimientos fundamentales necesarios para el Hackathon - 2025. Aprenderás como utilizar la plataforma de XIDE con el entorno de desarrollo de Arduino®.

Tabla de contenido

I. Descripción del kit de hardware

1.- ¿Qué es un zócalo mikroBUS?

El estándar mikroBUS™ define el patillaje (pinout) de tarjetas de desarrollo y módulos de expansión, esta interfaz no requiere habilidades para soldar o para leer hojas de datos.

El estándar define 3 interfaces seriales de comunicación: SPI, I2C, UART, 3 señales digitales: Interrupción, Reset y PWM. 1 señal analógica. El patillaje de un zócalo mikroBUS™ se organiza como se muestra en la imagen.

La plataforma XIDE está basada en este estándar, lo que permite al diseñador integrar un sistema de hardware en poco tiempo y le permite centrarse en construir la lógica de funcionamiento.

2.- ¿Cómo ensamblar un sistema XIDE?

El ensamblaje de un sistema con XIDE solo requiere 3 pasos:

  1. Identificar los módulos que se requieren en el sistema y escoger una tarjeta de expansión.

  2. Colocar los módulos en una tarjeta de expansión con cuidado de insertarlos correctamente.

  3. Programar el controlador del sistema.

Nota: Se recomienda colocar el controlador del sistema (XC01 R5-I) en el zócalo 5 de la tarjeta de expansión XBI01 - IIoTrainer. Lea el apartado Conectores estándar mikroBUS™ en la sección 3.- ¿Cómo funciona el XBI01? para obtener más información.

3.- ¿Cómo funciona el XBI01?

La tarjeta de expansión X-BOARD IIoTrainer es ideal para el desarrollo de prototipos y proyectos electrónicos, su diseño permite su inserción en una caja estanca IP65 ideal para proteger el sistema contra agua y polvo.

  1. Conectores estándar mikroBUS™ (El zócalo 5 está conectado en paralelo con los otros 4 zócalos).

  2. Conectores JST compatibles con el estándar Qwiic®.

  3. Doble header para configuración de los pines de los conectores mikroBUS™ (En la parte superior se muestran los pines de los zócalos 1 al 4, mientras que en la parte inferior los pines que están conectados en paralelo al zócalo 5).

  4. Versión de hardware: R1.

  5. Orificios para conexiones por debajo de la tarjeta

  6. Conectores tipo clema de propósito general como expansor de señales para cables AWG de calibre 24 a 20.

  7. Modelo de X-BOARD.

Más información sobre

(1) Conectores estándar mikroBUS™

El XBI01 - IIoTrainer cuenta con 5 zócalos mikroBUS™. Las comunicaciones seriales de todos los zócalos se encuentran conectadas (SCK, MISO, MOSI, TX, RX, SDA, SCL), por lo que su uso no requiere configuraciones adicionales.

Las señales digitales y analógicas: ANx, RSTx, CSx, PWMx y INTx se encuentran desconectadas. En la mayoría de los módulos de XIDE el uso de estas señales es innecesario para el funcionamiento básico, pero en algunos nodos es requerido, como es el caso del XC03 - Red celular LTE y GNSS, donde el encendido se controla con el pin PK. Para unir estas señales el usuario debe configurar el doble header, donde el zócalo marcado con el número 5 dispone de la mayor capacidad de personalización, por lo que se recomienda insertar el controlador del sistema en este zócalo.

(2) Conectores JST compatibles con el estándar Qwiic®

El estándar Qwiic® permite interconectar tarjetas a través de un cable utilizando el protocolo I2C (SDA, SCL), los XNODE compatibles con este estándar incluyen dos conectores marcados con la leyenda "qwiic".

Sistema con cables extensores Qwiic®
(3) Doble header para configuración de los pines de los conectores mikroBUS™

El doble header en el XBI01 - IIoTrainer permite configurar y acceder las señales de los zócalos mikroBUS™.

Los pines superiores corresponden a las señales de los primeros cuatro zócalos (1-5). Agrupadas por el tipo de señal: INTx(1), RSTx(2), PWMx(3), ANx(4) y CSx(5), en cada uno de estos grupos (excluyendo CSx) se encuentra además una señal CSn que puede utilizarse para el protocolo SPI (MISO, MOSI, SCK).

Los pines inferiores corresponden a las señales: INT(6), RST(7), PWM(8), AN(9) y CS(5) del zócalo 5. Esta distribución de pines permite unir las señales de este zócalo con cualquier señal de los otros 4 zócalos. Además, en cada señal (excepto la señal AN5), se encuentran dos pines marcados como PD (pull-down) y PU (pull-up), que se encuentran debajo de GND y 3.3V respectivamente, estos pines tienen una resistencia de 10kOhm para definir el estado lógico de la señal.

Para conectar las señales de los pines superiores con los inferiores se recomienda utilizar un puente de 2.54mm (incluidos con el XBI01 - IIoTrainer) como se muestra en el siguiente gráfico.

(6) Conectores de propósito general como expansor de señales

Estos bloques de conectores tipo clema se encuentran aislados del resto de señales de el XBI01 - IIoTrainer, su propósito es permitir el cableado de señales externas.

La tarjeta cuenta con 5 nodos aislados entre ellos: A, B, C, D y E, las clemas dentro de cada nodo se encuentran conectadas al mismo punto por lo que permite hacer empalmes de cables. El nodo A y el nodo B cuentan con cuatro clemas cada uno, los nodos C, D y E cuentan con solo dos clemas cada uno.

II. Configuración del entorno de desarrollo (Arduino® IDE)

Para programar el controlador del sistema se requiere un entorno de desarrollo, el XC01 R5-I es compatible con:

  1. Espressif-IDE: Entorno oficial de desarrollo para sistemas de Espressif Systems.

  2. Arduino® IDE: Entorno simplificado para pruebas de concepto compatible con sistemas de Espressif Systems.

Para usuarios avanzados es posible utilizar el conjunto de herramientas del SDK (ESP-IDF) en el editor de código de su preferencia.

Este manual se centrará en la plataforma Arduino®.

1.- Preparación del XC01 R5-I Arduino® IDE

Pasos para configurar el XC01 R5-I en Arduino® IDE
  1. Descarga e instala Arduino® IDE.

https://www.arduino.cc/en/software

  1. Ejecuta Arduino® IDE y da clic en "Gestor de tarjetas".

  1. En el buscador ingresa: esp32. Selecciona la opción esp32 by Espressif Systems y presiona el botón instalar. Espera hasta que se finalice la instalación, este proceso puede demorar unos cuantos minutos dependiendo de su velocidad de descarga.

  1. Posteriormente da clic en "Herramientas" > "Placa" > "esp32" > "ESP32S3 Dev Module".

  1. Por último, configura la tarjeta como se muestra en la imagen, selecciona el puerto asignado por el módulo y estará listo para usarse.

2. Uso de los pines mikroBUS del XC01 R5-I en el Arduino® IDE

El XC01 R5-I cuenta con 12 pines expuestos, 7 reservados para comunicaciones seriales (SCK, MISO, MOSI, TX, RX, SDA, SCL) y 5 para uso de propósito general. Además, dispone de 6 pines internos adicionales para controlar el LED integrado, leer el estado del botón BOOT, utilizar el lector de tarjeta SD, administrar el cargador e indicador de batería.

*Nota: Los pines EN1, EN2 y CE permiten controlar el comportamiento del cargador de batería integrado. La siguiente tabla ilustra el estado de los pines requeridos para habilitar los diferentes modos de funcionamiento.

EN2
EN1
CE
Corriente del sistema
Descripción

0

0

0

100 mA

Modo de carga lenta, útil para cargar baterías de baja capacidad menores a 500mAh. En este modo no es posible utilizar la comunicación WiFi sin una batería conectada al sistema.

0

1

0

500 mA

Modo de carga normal, útil para cargar baterías menores a 2000mAh. En éste modo no se recomienda utilizar las comunicaciones WiFi sin una batería conectada al sistema.

1

0

0

1500 mA

Modo de carga rápida (por defecto), útil para cargar baterías de hasta 8000mAh.

1

1

0

Standby

Modo de reposo, el sistema se alimentará exclusivamente desde la batería.

x

x

1

Charge disabled

Modo de carga de la batería deshabilitado.

3. Plantilla de Arduino® IDE

Plantilla para usar el XC01 R5-I en Arduino® IDE
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>

#define MIKROBUS_AN 4
#define MIKROBUS_RST 15
#define MIKROBUS_CS 6
#define MIKROBUS_SCK 8
#define MIKROBUS_MISO 18
#define MIKROBUS_MOSI 17
#define MIKROBUS_PWM 5
#define MIKROBUS_INT 7
#define MIKROBUS_RX 9
#define MIKROBUS_TX 10
#define MIKROBUS_SCL 13
#define MIKROBUS_SDA 12

#define BOARD_LED 16

void setup(){

  // mikroBUS GPIO
  pinMode( MIKROBUS_AN, OUTPUT );
  pinMode( MIKROBUS_RST, OUTPUT );
  pinMode( MIKROBUS_CS, OUTPUT );
  pinMode( MIKROBUS_PWM, OUTPUT );
  pinMode( MIKROBUS_INT, OUTPUT );
  pinMode( BOARD_LED, OUTPUT );

  digitalWrite( MIKROBUS_AN, HIGH );
  digitalWrite( MIKROBUS_RST, HIGH );
  digitalWrite( MIKROBUS_CS, HIGH );
  digitalWrite( MIKROBUS_PWM, HIGH );
  digitalWrite( MIKROBUS_INT, HIGH );
  digitalWrite( BOARD_LED, HIGH );

  // UART config
  Serial.begin( 115200 ); // USB/UART0
  Serial2.begin( 115200, SERIAL_8N1, MIKROBUS_RX, MIKROBUS_TX ); // mikroBUS
  
  // I2C config
  Wire.setPins( MIKROBUS_SDA, MIKROBUS_SCL ); // mikroBUS
  Wire.begin();

  // SPI config
  SPI.begin( MIKROBUS_SCK, MIKROBUS_MISO, MIKROBUS_MOSI ); // mikroBUS
}

void loop(){

  digitalWrite( MIKROBUS_AN, LOW );
  digitalWrite( MIKROBUS_RST, LOW );
  digitalWrite( MIKROBUS_CS, LOW );
  digitalWrite( MIKROBUS_PWM, LOW );
  digitalWrite( MIKROBUS_INT, LOW );

  delay( 1000 );

  digitalWrite( MIKROBUS_AN, HIGH );
  digitalWrite( MIKROBUS_RST, HIGH );
  digitalWrite( MIKROBUS_CS, HIGH );
  digitalWrite( MIKROBUS_PWM, HIGH );
  digitalWrite( MIKROBUS_INT, HIGH );

  delay( 1000 );

}

III. Uso del XN02 - Salidas digitales

El XN02 Digital Outputs es un expansor de salidas digitales que utiliza el protocolo I2C (SDA, SCL) para controlar el estado lógico de hasta 8 señales digitales.

El siguiente fragmento de código describe como utilizar el XN02 Digital Outputs en Arduino® IDE.

    // Inicia la comunicación con el XN(02)
    Wire.beginTransmission(2);
    // Selecciona el registro de las salidas
    Wire.write( 0x01 );
    // Escribe 1 en las 8 salidas
    Wire.write(0b11111111);
    // Finaliza la comunicación con el nodo
    Wire.endTransmission();

Para utilizar el XN02 Digital Outputs de forma programática se recomienda entender como manipular bits en el lenguaje C++.

Ejemplo de uso del XN02

Código de ejemplo con el XC01 R5-I
#include <Arduino.h>
#include <Wire.h>

// ************ CONFIGURACION DE PINOUT MIKROBUS ***************
#define MIKROBUS_AN 4
#define MIKROBUS_RST 15
#define MIKROBUS_CS 6
#define MIKROBUS_SCK 8
#define MIKROBUS_MISO 18
#define MIKROBUS_MOSI 17
#define MIKROBUS_PWM 5
#define MIKROBUS_INT 7
#define MIKROBUS_RX 9
#define MIKROBUS_TX 10
#define MIKROBUS_SCL 13
#define MIKROBUS_SDA 12

#define BOARD_LED 16

void writeXN02Binary( uint8_t stat ){

    // XN02
    Wire.beginTransmission( 2 );
    // Registro de salidas
    Wire.write( 0x01 );
    // Valor de salidas
    Wire.write( stat );
    Wire.endTransmission();

}

void writeXN02( bool o1 = LOW, bool o2 = LOW, bool o3 = LOW, bool o4 = LOW, bool o5 = LOW, bool o6 = LOW, bool o7 = LOW, bool o8 = LOW ){
    uint8_t data = 0;

    data |= o1;
    data |= o2 << 1;
    data |= o3 << 2;
    data |= o4 << 3;
    data |= o5 << 4;
    data |= o6 << 5;
    data |= o7 << 6;
    data |= o8 << 7;

    writeXN02Binary( data );
}

void setup() {

  // Configuración de comunicaciones seriales
  Serial.begin(115200);
  Wire.setPins( MIKROBUS_SDA, MIKROBUS_SCL );
  Wire.begin();

}

void loop() {

  // Secuencia de leds
  writeXN02( HIGH );
  delay( 1000UL );
  writeXN02( HIGH, HIGH );
  delay( 1000UL );
  writeXN02( HIGH, HIGH, HIGH );
  delay( 1000UL );
  writeXN02( HIGH, HIGH, HIGH, HIGH);
  delay( 1000UL );
  writeXN02( HIGH, HIGH, HIGH, HIGH, HIGH );
  delay( 1000UL );
  writeXN02( HIGH, HIGH, HIGH, HIGH, HIGH, HIGH );
  delay( 1000UL );
  writeXN02( HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH );
  delay( 1000UL );
  writeXN02( HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH );
  delay( 1000UL );

}

IV. Uso del XN04 - Sensores Temperatura/Humedad/Luminosidad

El XN04 Temp-Hum / Lum es un conjunto de sensores de variables ambientales, permite medir temperatura en °C, humedad relativa porcentual y luminosidad en luxes.

El siguiente fragmento de código describe como utilizar el XN04 Temp-Hum / Lum en Arduino® IDE.

    // Inicia la comunicación con el XN(04)
    Wire.beginTransmission(4);
    // Selecciona el registro
    // temperatura: 0x01
    // humedad: 0x02
    // luminosidad: 0x03
    Wire.write(0b01);
    Wire.endTransmission();

    // Lee 2 bytes del XN04
    Wire.requestFrom(0x04, 2);

    // La temperatura y humedad deben dividirse entre 100.0f
    // para obtener el valor en °C / %.
    float temperatura = ( (Wire.read() << 8) | Wire.read() )/100.0f;

    // La luminosidad no requiere esta operación y puede leerse como
    // un entero de 16 bits (uint16_t)
    // uint16_t luminosidad = ( (Wire.read() << 8) | Wire.read() );

Ejemplo de uso del XN04

Código de ejemplo con el XC01 R5-I
#include <Arduino.h>
#include <Wire.h>

// ************ CONFIGURACION DE PINOUT MIKROBUS ***************
#define MIKROBUS_AN 4
#define MIKROBUS_RST 15
#define MIKROBUS_CS 6
#define MIKROBUS_SCK 8
#define MIKROBUS_MISO 18
#define MIKROBUS_MOSI 17
#define MIKROBUS_PWM 5
#define MIKROBUS_INT 7
#define MIKROBUS_RX 9
#define MIKROBUS_TX 10
#define MIKROBUS_SCL 13
#define MIKROBUS_SDA 12

#define BOARD_LED 16

float readXN04Temperature( ){

    float temperature;
    uint16_t temperature_int;
    // XN04
    Wire.beginTransmission( 4 );
    // Registro de temperature
    Wire.write( 0x01 );
    Wire.endTransmission();

    Wire.requestFrom( 4, 2 );
    
    temperature_int = ( (Wire.read() << 8) | Wire.read() );
    temperature = temperature_int/100.0f;

    return temperature;
}

float readXN04Humidity( ){

    float humidity;
    uint16_t humidity_int;
    // XN04
    Wire.beginTransmission( 4 );
    // Registro de humidity
    Wire.write( 0x02 );
    Wire.endTransmission();

    Wire.requestFrom( 4, 2 );
    
    humidity_int = ( (Wire.read() << 8) | Wire.read() );
    humidity = humidity_int/100.0f;

    return humidity;

}

uint16_t readXN04Luminosity( ){

    uint16_t lux;
    // XN04
    Wire.beginTransmission( 4 );
    // Registro de lux
    Wire.write( 0x03 );
    Wire.endTransmission();

    Wire.requestFrom( 4, 2 );
    
    lux = ( (Wire.read() << 8) | Wire.read() );

    return lux;

}

void setup() {

  // Configuración de comunicaciones seriales
  Serial.begin(115200);
  Wire.setPins( MIKROBUS_SDA, MIKROBUS_SCL );
  Wire.begin();

}

void loop() {

  float temperatura, humedad;
  uint16_t lux;

  // Obtener temperatura
  temperatura = readXN04Temperature(  );
  // Obtener humedad
  humedad = readXN04Humidity(  );
  // Obtener luminosidad
  lux = readXN04Luminosity(  );

  Serial.print( "Temperatura: " );
  Serial.print( temperatura );
  Serial.println( " C" );

  Serial.print( "Humedad: " );
  Serial.print( humedad );
  Serial.println( " %" );

  Serial.print( "Luminosidad: " );
  Serial.print( lux );
  Serial.println( " lx" );
  
  delay( 2000UL );
}

V. Uso del XN11 - 2 x Relevadores

El XN11 2 x Relay es un módulo de dos relevadores para controlar cargas hasta 220VAC de hasta 5A*

Nota: Solo la revisión R2 puede controlar cargas de hasta 5A, la versión R1 solo permite conmutar cargas de hasta 0.5A.

El siguiente fragmento de código describe como utilizar el XN11 2 x Relay en Arduino® IDE.

    // Inicia la comunicación con el XN(04)
    Wire.beginTransmission(4);
    // Selecciona el relevador
    // 0x01 - relevador 1
    // 0x02 - relevador 2
    Wire.write( 0x01 );
    // Enciende (1) o apaga(0) el relevador
    Wire.write(0b01);
    Wire.endTransmission();

Ejemplo de uso del XN11

Código de ejemplo con el XC01 R5-I
#include <Arduino.h>
#include <Wire.h>

// ************ CONFIGURACION DE PINOUT MIKROBUS ***************
#define MIKROBUS_AN 4
#define MIKROBUS_RST 15
#define MIKROBUS_CS 6
#define MIKROBUS_SCK 8
#define MIKROBUS_MISO 18
#define MIKROBUS_MOSI 17
#define MIKROBUS_PWM 5
#define MIKROBUS_INT 7
#define MIKROBUS_RX 9
#define MIKROBUS_TX 10
#define MIKROBUS_SCL 13
#define MIKROBUS_SDA 12

#define BOARD_LED 16

void writeXN11(uint8_t relay, uint8_t stat)
{
  uint8_t reg = 0x00;
  uint8_t data = 0x00;

  if ( stat ){
    data = 0x01;
  } else {
    data = 0x00;
  }

  switch( relay ){
    case 1:
    case 2:
    reg = relay;
    break;
    default:
    return;
  }

  // XN11
  Wire.beginTransmission(11);
  // Valor de salidas
  Wire.write( reg );
  Wire.write(data);
  Wire.endTransmission();
}

void setup() {

  // Configuración de comunicaciones seriales
  Serial.begin(115200);
  Wire.setPins( MIKROBUS_SDA, MIKROBUS_SCL );
  Wire.begin();

  writeXN11( 1, LOW );
  writeXN11( 2, LOW );

}

void loop() {

  write( 1, HIGH );
  delay( 5000UL );
  write( 2, HIGH );
  delay( 5000UL );
  writeXN11( 1, LOW );
  writeXN11( 2, LOW );
  delay( 5000UL );

}

VI. Uso del XC03 - Red celular LTE y GNSS

El XC03 - Red celular LTE y GNSS es un módulo que permite establecer comunicación a internet u obtener posición global. Sin embargo, no puede hacer ambas cosas al mismo tiempo.

Este es un nodo considerablemente complejo, en Arduino® IDE se recomienda utilizar la librería TinyGSM para hacer el desarrollo más sencillo.

Nota: El XC03 - Red celular LTE y GNSS requiere el control de la señal PK para encenderse, en los ejemplos de código este pin se controla con la señal INT del XC01 R5-I. Asegúrese que está señal está conectada al pin PK del XC03 - Red celular LTE y GNSS para garantizar el funcionamiento del ejemplo.

Instalación de TinyGSM en Arduino® IDE
  1. Abrir el administrador de librerías de Arduino® IDE.

  1. En el buscador ingresa: TinyGSM. Selecciona la librería TinyGSM by Volodymyr Shymansky y presiona el botón instalar.

El siguiente fragmento de código es una plantilla para utilizar TinyGSM y explica cómo utilizar algunas de sus funciones.

Configuración inicial de TinyGSM y funciones básicas
// Selecciona el modelo de módem el XC03 utiliza SIM7080G
// esta instrucción debe ir antes de incluir la librería
#define TINY_GSM_MODEM_SIM7080

// Se incluye la librería TinyGSM
#include <Arduino.h>
#include <TinyGsmClient.h>

// La comunicación requiere un puerto UART para enviar comandos AT
#define SerialAT Serial2

// El encendido del módem requiere controlar el pin Power-Key (PK)
#define PIN_MODEM_PK 7

// Configuración de la tarjeta SIM
const char apn[]  = "";
const char user[] = "";
const char pass[] = "";
const char pin[] = "";

// Variables de geolocalización
float latitude;
float longitude;
float speed;
float alt;
int vsat;
int usat;
float accuracy;
int year;
int month;
int day;
int hour;
int minute;
int second;

void setup(){
    // Inicia la comunicación con el módem, la velocidad
    // de transmisión de datos es 115200
    SerialAT.begin(115200);

    pinMode( PIN_MODEM_PK, OUTPUT );
  
    // Para reiniciar el módem el pin PK debe
    // ser 1 por al menos 3 segundos
    digitalWrite( PIN_MODEM_PK, HIGH );
    delay(3000);
    digitalWrite( PIN_MODEM_PK, LOW );

    // Reinicia la configuración del módem
    // para garantizar un correcto funcionamiento
    modem.restart();

    // Si la SIM se encuentra bloqueada por número PIN
    // la desbloquea
    modem.simUnlock( GSM_PIN );

}

void loop(){

    // Regresa una variable String con el modelo del módem 
    modem.getModemInfo();

    // Habilita la geolocalización, requiere deshabilitar
    // la comunicación celular, regresa True en caso de éxito,
    // False en caso contrario
    modem.enableGPS();

    // Obtiene las variables calculadas por el GNSS, regresa True
    // si el GNSS está listo y obtuvo la posición, False si aún no
    // se ha obtenido una posición.
    modem.getGPS( &latitude, &longitude, &speed, &alt, &vsat,
    &usat, &accuracy, &year, &month, &day, &hour, &minute, &second );

    // La posición requiere mayor precisión que una variable tipo Float,
    // utiliza la promoción de float a doble:
    // (double) myFloatVar // Al usar el valor en funciones
    // (double) myFloatVar + (double) myFloatVar2 // Al realizar operaciones aritmeticas
    // para evitar perder precisión.
    Serial.print( "Latitud: " );
    Serial.println( (double)latitude, 5 );

    Serial.print( "Longitud: " );
    Serial.println( (double)longitude, 5 );

    // Deshabilita la geolocalización
    modem.disableGPS();

    // Habilita la comunicación celular, requiere deshabilitar
    // la geolocalización
    modem.gprsConnect( apn, user, pass );

    // Consulta el estado de conexión con la red celular
    // regresa True si hay una conexión activa,
    // False en caso contrario
    modem.isGprsConnected();

    // Deshabilita la geolocalización
    modem.gprsDisconnect();
}

Ejemplo para obtener la geolocalización con TinyGSM

Para que este ejemplo funcione correctamente se recomienda encarecidamente que la antena GNSS se encuentre a cielo abierto. Intentar obtener la posición dentro de edificios puede demorar mucho tiempo o no funcionar.

Código de ejemplo con el XC01 R5-I
#define TINY_GSM_MODEM_SIM7080

#include <Arduino.h>
#include <TinyGsmClient.h>

// ********** CONFIGURACION DE COMUNICACIONES SERIALES ********
#define SerialMon Serial
#define SerialAT Serial2
#define TINY_GSM_DEBUG SerialMon

// ************ CONFIGURACION DE PINOUT MIKROBUS ***************
#define MIKROBUS_AN 4
#define MIKROBUS_RST 15
#define MIKROBUS_CS 6
#define MIKROBUS_SCK 8
#define MIKROBUS_MISO 18
#define MIKROBUS_MOSI 17
#define MIKROBUS_PWM 5
#define MIKROBUS_INT 7
#define MIKROBUS_RX 9
#define MIKROBUS_TX 10
#define MIKROBUS_SCL 13
#define MIKROBUS_SDA 12

#define BOARD_LED 16

#define PIN_MODEM_PK MIKROBUS_INT

// *************** CONFIGURACION OPERADORA LTE ******************
const char apn[]  = "";
const char user[] = "";
const char pass[] = "";


// ******************* VARIABLES GLOBALES ***********************
static TinyGsm modem(SerialAT);


// ********************* FUNCIONES GNSS *************************
bool getGNSS();


void setup() {

  // Configuración de comunicaciones seriales
  SerialMon.begin(115200);
  SerialAT.begin(115200, SERIAL_8N1, MIKROBUS_RX, MIKROBUS_TX );

  // Inicialización de I/O
  pinMode( BOARD_LED, OUTPUT );
  digitalWrite( BOARD_LED, LOW );
  pinMode( PIN_MODEM_PK, OUTPUT );
  
  // Reinicio del modem LTE por hardware
  digitalWrite( PIN_MODEM_PK, HIGH );
  delay(3000);
  digitalWrite( PIN_MODEM_PK, LOW );

  // Configuración inicial del modem LTE
  SerialMon.println("Iniciando modem LTE...");
  modem.restart();
  String modemInfo = modem.getModemInfo();
  SerialMon.print("Modem: ");
  SerialMon.println(modemInfo);

  // Finaliza las comunicaciones LTE e inicia
  // GNSS
  modem.gprsDisconnect();
  if ( !modem.enableGPS() ) {
    Serial.println( "Error al iniciar GNSS" );
    while(1){
      delay( 1000 );
    }
  }

}

void loop() {

  // Obtener posición
  updateGNSS();
  delay( 1000UL );

}

bool updateGNSS() {
  // Colocamos un tiempo de espera máximo de 30 segundos y 90 para coldboot
  static bool coldboot = true;
  const unsigned long timeout_coldboot = 90000;
  const unsigned long timeout_run = 30000;

  float latitude;
  float longitude;
  float speed;
  float alt;
  int vsat;
  int usat;
  float accuracy;
  int year;
  int month;
  int day;
  int hour;
  int minute;
  int second;

  unsigned long timer = 0;
  unsigned long timeout = 0;
  bool success = false;

  if ( coldboot ){
    timeout = timeout_coldboot;
  } else {
    timeout = timeout_run;
  }

  // Comenzamos el temporizador
  timer = millis();

  // Mientras no se agote el tiempo de espera intentar obtener la posición
  while ( ( millis() - timer ) < timeout ) {

    success = modem.getGPS( &latitude, &longitude, &speed, &alt, &vsat, &usat, &accuracy,
                            &year, &month, &day, &hour, &minute, &second );

    // Si se obtiene la posición exitosamente entonces finalizar el bucle
    if ( success ) {
      break;
    }
  }

  // Retorna el resultado de la operación, si se obtuvo la posición
  // deshabilita el abanderamiento de Coldboot y muestra los datos
  if ( !success ) {
    return false;
  }

  // La posición requiere mayor precisión que una variable tipo Float,
  // utiliza la promoción de float a doble:
  // (double) myFloatVar // Al usar el valor en funciones
  // (double) myFloatVar + (double) myFloatVar2 // Al realizar operaciones aritmeticas
  // para evitar perder precisión.
  Serial.print( "Latitud: " );
  Serial.println( (double)latitude, 5 );

  Serial.print( "Longitud: " );
  Serial.println( (double)longitude, 5 );

  Serial.print( "Velocidad ( km/h ): " );
  Serial.println( speed );

  Serial.print( "Altitud (mts): " );
  Serial.println( alt );

  Serial.print( "Satelites (en vista): " );
  Serial.println( vsat );

  Serial.print( "Satelites (utilizados): " );
  Serial.println( usat );

  Serial.print( "Precision (mts): " );
  Serial.println( accuracy );

  Serial.print( "Fecha/Hora: " );
  Serial.print( day );
  Serial.print( "/" );
  Serial.print( month );
  Serial.print( "/" );
  Serial.print( year );
  Serial.print( " " );
  Serial.print( hour );
  Serial.print( ":" );
  Serial.print( minute );
  Serial.print( ":" );
  Serial.println( second );

  coldboot = false;
  return true;
}

Ejemplo de comunicación celular con TinyGSM y Blynk.Cloud

Este ejemplo explica como conectarse a una nube de internet para enviar y recibir información utilizando la red celular TinyGSM.

Es necesario instalar la librería de Blynk.

Instalación de Blynk en Arduino® IDE
  1. Abrir el administrador de librerías de Arduino® IDE.

  1. En el buscador ingresa: Blynk. Selecciona la librería Blynk by Volodymyr Shymansky y presiona el botón instalar.

También es necesario contar con una cuenta de Blynk.cloud y dar de alta un nuevo dispositivo para obtener un Template ID, Template Name y un Token de autorización. Es necesario reemplazar estos datos en el código de ejemplo.

Nota: Durante el Hackathon se te proporcionará una cuenta de Blynk, así como el Template ID, Template Name y el Token de autorización.

TinyGSM + Blynk.cloud con el XC01 R5-I
/*
 * Configuración del template en Blynk:
 * V0 - Control del led: 0 = apagado, 1 = encendido
 * V1 - Estado del botón BOOT
 */

// *************** TEMPLATE DE BLYNK **************************
#define BLYNK_TEMPLATE_ID "TMPxxxxxx"
#define BLYNK_TEMPLATE_NAME "Device"
#define BLYNK_AUTH_TOKEN "YourAuthToken"

#define BLYNK_PRINT Serial

// ******************* MODEM SIM7080 **************************
#define TINY_GSM_MODEM_SIM7080

#include <Arduino.h>
#include <Wire.h>
#include <TinyGsmClient.h>
#include <BlynkSimpleTinyGSM.h>

// ********** CONFIGURACION DE COMUNICACIONES SERIALES ********
#define SerialMon Serial
#define SerialAT Serial2
#define TINY_GSM_DEBUG SerialMon

// ************ CONFIGURACION DE PINOUT MIKROBUS ***************
#define MIKROBUS_AN 4
#define MIKROBUS_RST 15
#define MIKROBUS_CS 6
#define MIKROBUS_SCK 8
#define MIKROBUS_MISO 18
#define MIKROBUS_MOSI 17
#define MIKROBUS_PWM 5
#define MIKROBUS_INT 7
#define MIKROBUS_RX 9
#define MIKROBUS_TX 10
#define MIKROBUS_SCL 13
#define MIKROBUS_SDA 12

#define BOARD_LED 16
#define BOARD_BUTTON 0

#define PIN_MODEM_PK MIKROBUS_INT

// *************** CONFIGURACION OPERADORA LTE ******************
const char apn[] = "";
const char user[] = "";
const char pass[] = "";

// ************** CONFIGURACION SERVIDOR BLYNK ******************
const char domain[] = "ny3.blynk.cloud";
const char auth[] = BLYNK_AUTH_TOKEN;

// ******************* VARIABLES GLOBALES ***********************
static BlynkTimer scheduler;
static TinyGsm modem(SerialAT);

// Si el estado del botón ha cambiado actualizar el valor en Blynk
void updateButton(  )
{
    static int prev_status = HIGH;

    int current_status = digitalRead( BOARD_BUTTON );

    // Actualizar información a la nube solo si el
    // estado del botón ha cambiado, esto
    // disminuye la cantidad de datos utilizados
    if ( current_status == prev_status ){
        return;
    }

    prev_status = current_status;

    Blynk.virtualWrite(V1, current_status);
}

void setup()
{

    // Configuración de comunicaciones seriales
    SerialMon.begin(115200);
    SerialAT.begin(115200, SERIAL_8N1, MIKROBUS_RX, MIKROBUS_TX);
    Wire.setPins(MIKROBUS_SDA, MIKROBUS_SCL);
    Wire.begin();

    // Inicialización de I/O
    pinMode( BOARD_BUTTON, INPUT_PULLUP );
    pinMode(BOARD_LED, OUTPUT);
    digitalWrite(BOARD_LED, LOW);
    pinMode(PIN_MODEM_PK, OUTPUT);

    // Reinicio del modem LTE por hardware
    digitalWrite(PIN_MODEM_PK, HIGH);
    delay(3000);
    digitalWrite(PIN_MODEM_PK, LOW);

    // Configuración inicial del modem LTE
    SerialMon.println("Iniciando modem LTE...");
    modem.restart();
    String modemInfo = modem.getModemInfo();
    SerialMon.print("Modem: ");
    SerialMon.println(modemInfo);

    // Iniciar comunicación con Blynk.Cloud
    Blynk.begin(auth, modem, apn, user, pass, domain);

    // Revisa el valor del botón cada segundo
    scheduler.setInterval(1000UL, updateButton);
}

void loop()
{
    Blynk.run();
    scheduler.run();
}

// ****************** FUNCIONES DE BLYNK **********************

BLYNK_CONNECTED()
{
    Serial.println("Conectado");
    // Obtener últimos valores del servidor
    Blynk.syncVirtual(V0);
}

BLYNK_DISCONNECTED()
{
    Serial.println("Desconectado");
}

BLYNK_WRITE(V0)
{
    int led = param.asInt();

    if ( led ){
        digitalWrite( BOARD_LED, HIGH );
    } else {
        digitalWrite( BOARD_LED, LOW );
    }
}

VII. Demostración: Termómetro IoT sobre red celular LTE

Este ejemplo demuestra como combinar 3 nodos para crear un sistema IoT:

Apila los nodos como se muestra en la figura:

El sistema reporta el valor de temperatura cada 30 segundos, el usuario puede controlar un LED de manera remota y enviar valor que se comparará con la temperatura actual en el dispositivo, después mostrará en la terminal si el valor es mayor o menor.

Reemplaza los valores de Template ID, Template Name y un Token de autorización en el código y programa el XC01 R5-I.

TinyGSM + Blynk.cloud con el XC01 R5-I
/*
 * Configuración del template en Blynk:
 * V0 - Control del led: 0 = apagado, 1 = encendido
 * V1 - Estado del botón BOOT
 * V2 - Temperatura
 * V3 - Umbral de temperatura
 */

// *************** TEMPLATE DE BLYNK **************************
#define BLYNK_TEMPLATE_ID "TMPxxxxxx"
#define BLYNK_TEMPLATE_NAME "Device"
#define BLYNK_AUTH_TOKEN "YourAuthToken"

#define BLYNK_PRINT Serial

// ******************* MODEM SIM7080 **************************
#define TINY_GSM_MODEM_SIM7080

#include <Arduino.h>
#include <Wire.h>
#include <TinyGsmClient.h>
#include <BlynkSimpleTinyGSM.h>

// ********** CONFIGURACION DE COMUNICACIONES SERIALES ********
#define SerialMon Serial
#define SerialAT Serial2
#define TINY_GSM_DEBUG SerialMon

// ************ CONFIGURACION DE PINOUT MIKROBUS ***************
#define MIKROBUS_AN 4
#define MIKROBUS_RST 15
#define MIKROBUS_CS 6
#define MIKROBUS_SCK 8
#define MIKROBUS_MISO 18
#define MIKROBUS_MOSI 17
#define MIKROBUS_PWM 5
#define MIKROBUS_INT 7
#define MIKROBUS_RX 9
#define MIKROBUS_TX 10
#define MIKROBUS_SCL 13
#define MIKROBUS_SDA 12

#define BOARD_LED 16

#define UPDATE_BUTTON 0
#define PIN_MODEM_PK MIKROBUS_INT

// *************** CONFIGURACION OPERADORA LTE ******************
const char apn[] = "";
const char user[] = "";
const char pass[] = "";

// ************** CONFIGURACION SERVIDOR BLYNK ******************
const char domain[] = "ny3.blynk.cloud";
const char auth[] = BLYNK_AUTH_TOKEN;

// ******************* VARIABLES GLOBALES ***********************
static BlynkTimer scheduler;
static TinyGsm modem(SerialAT);

float readXN04Temperature();

void updateTemperature()
{
    Blynk.virtualWrite(V0, readXN04Temperature());
}

void setup()
{

    // Configuración de comunicaciones seriales
    SerialMon.begin(115200);
    SerialAT.begin(115200, SERIAL_8N1, MIKROBUS_RX, MIKROBUS_TX);
    Wire.setPins(MIKROBUS_SDA, MIKROBUS_SCL);
    Wire.begin();

    // Inicialización de I/O
    pinMode(BOARD_LED, OUTPUT);
    digitalWrite(BOARD_LED, LOW);
    pinMode(PIN_MODEM_PK, OUTPUT);

    // Reinicio del modem LTE por hardware
    digitalWrite(PIN_MODEM_PK, HIGH);
    delay(3000);
    digitalWrite(PIN_MODEM_PK, LOW);

    // Configuración inicial del modem LTE
    SerialMon.println("Iniciando modem LTE...");
    modem.restart();
    String modemInfo = modem.getModemInfo();
    SerialMon.print("Modem: ");
    SerialMon.println(modemInfo);

    // Iniciar comunicación con Blynk.Cloud
    Blynk.begin(auth, modem, apn, user, pass, domain);

    // Una vez inicializada la comunicación con el servidor
    // éste se puede interrumpir y reanudar utilizando las
    // funciones:

    // Interrumpir la conexión con el servidor de Blynk
    // Blynk.disconnect();

    // Reanudar la conexión con el servidor de Blynk
    // Blynk.connect();

    // Inicia los temporizadores
    scheduler.setInterval(30000UL, updateTemperature);
}

void loop()
{
    Blynk.run();
    scheduler.run();
}

// ****************** FUNCIONES DE XNODES **********************

float readXN04Temperature()
{

    float temperature;
    uint16_t temperature_int;
    // XN04
    Wire.beginTransmission(4);
    // Registro de temperature
    Wire.write(0x01);
    Wire.endTransmission();

    Wire.requestFrom(4, 2);

    temperature_int = ((Wire.read() << 8) | Wire.read());
    temperature = temperature_int / 100.0f;

    return temperature;
}

// ****************** FUNCIONES DE BLYNK **********************

BLYNK_CONNECTED()
{
    Serial.println("Conectado");
    // Obtener últimos valores del servidor
    Blynk.syncVirtual(V0, V4);
}

BLYNK_DISCONNECTED()
{
    Serial.println("Desconectado");
}

BLYNK_WRITE(V0)
{
    int led = param.asInt();

    if ( led ){
        digitalWrite( BOARD_LED, HIGH );
    } else {
        digitalWrite( BOARD_LED, LOW );
    }
}

BLYNK_WRITE(V4)
{
    double treshold = param.asDouble();

    if ( readXN04Temperature() < treshold ){
        Serial.println( "Temperatura actual menor al umbral" );
    } else {
        Serial.println( "Temperatura actual mayor al umbral" );
    }
}

VIII. Descargas

Última actualización

¿Te fue útil?