consultas@firtec.com.ar
Electrónica y programación para Microcontroladores.
Libros técnicos para electrónica programable.

Arduino Mega y la UART con interrupciones
La placa Arduino Mega 2560 tiene varios puertos UART, en este ejemplo vemos el uso de la UART2 (pin 17 para RX y pin 16 para TX).
Para hacer las cosas mas interesantes se muestra como recibir datos mediante la interrupción de la UART2.
Este enfoque es un tanto distinto de la clásica recepción mediante sondeo continuo del puerto.
if(Serial.available()){
if(Serial.read() == '1'){
// Hacer algo con el dato!!!
}
El código anterior es la forma clásica de recibir datos por la UART con Arduino, sin embargo en algunas circunstancias esto puede no ser eficiente.
En definitiva estamos siempre atentos a si hay nuevos datos en la UART, el uso de la interrupción elimina este problema.
El microcontrolador solo atiende a la UART cuando hay datos disponibles en el buffer del receptor y lo hace de manera automática.
Sin importar lo que estemos haciendo, cuando lleguen nuevos datos el control del programa pasará a la UART para procesar los nuevos datos.
El código del ejemplo es el siguiente.
/******************************************************************************
* Descripción: Capturando datos en la UART2
* Este programa utiliza la interrupción de la UART2
* cuando hay datos en el buffer de recepción se llama
* a la función ISR para procesar los datos recibidos.
* Los datos se muestran en una pantalla LCD y se ha
* decodificado el BackSpace (carácter 0x08) para
* borrar datos en pantalla.
* Placa Arduino: MEGA 2560
* Arduino IDE: 1.8.5
*
* www.firtec.com.ar
*******************************************************************************/
#include "LiquidCrystal.h"
LiquidCrystal lcd(8,9,4,5,6,7);
#define ledPin 13
#define F_CPU 16000000
#define USART_BAUDRATE 19200//9600
#define UBRR_VALUE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
char RX_Byte ;
volatile char base;
/********************************************************************
* Función para la configuración del Hardware
* Argumentos: NINGUNO
* Retorna: NADA
*
*********************************************************************/
void setup(){
pinMode(13, OUTPUT);
pinMode(16, OUTPUT);
pinMode(17, INPUT);
digitalWrite(13, LOW);
lcd.begin(20,4);
lcd.setCursor(2,0);
lcd.print("FIRTEC ARGENTINA");
lcd.setCursor(2,1);
lcd.print("Datos en la UART");
lcd.setCursor(0,2);
lcd.print("--------------------");
lcd.setCursor(1,3);
lcd.print("www.firtec.com.ar");
// Configura los baudios
UBRR2H = (uint8_t)(UBRR_VALUE >> 8);
UBRR2L = (uint8_t)UBRR_VALUE;
UCSR2C |= (1 << UCSZ20) | (1 << UCSZ21); // 8-bit para los datos recibidos
UCSR2B |= (1 << RXEN2) | (1 << TXEN2) | (1 << RXCIE2); // Interrupciones activas
UCSR2A = 0x00; // Limpia banderas
interrupts();
}
/********************************************************************
* Función pincipal del programa, solo cambia de estado el LED de la
* placa Mega (pin13) para indicar que es sistema está atento a las
* interrupciones del receptor UART.
********************************************************************/
void loop(){
delay(1000);
digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
}
/***************************************************************************
* Función ISR para la UART2.
* Procesa y muestra el caracter recibido. Si es 0x08 escribe "-"
* borrando el caracter en esa locación.
* La variable base se usa para mover el cursor al casillero que le
* corresponde en la línea del LCD.
* Argumentos: NINGUNO
* Retorna: NADA
*
****************************************************************************/
ISR(USART2_RX_vect){
RX_Byte = UDR2; // Leo el dato recibido
if(RX_Byte==0x08 & base >0){
base--;
lcd.setCursor(base,2);
lcd.print("-");
}
if(RX_Byte!=0x08){
lcd.setCursor(base,2);
lcd.print(RX_Byte);
UDR2 = RX_Byte;
base++;
}
}
//*********** FIN DE ARCHIVO FIRTEC ARGENTINA **************************************
El siguiente es el ejemplo funcionando.
Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.
Medición en cuatro canales con Arduino Mega.
El siguiente es un ejemplo de como hacer cuatro lecturas en cuatro canales analógicos distintos en una placa Arduino Mega.
Se toman cinco lecturas en cada canal (cinco interrupciones por canal), luego se busca el promedio de estas cinco lecturas, se escala el resultado para convertirlo a voltios y finalmente se muestra la información en una pantalla LCD hd 44780 tipo 2004.
Se leen los canales AN0, AN1, AN2 y AN3.
/*******************************************************************
* Descripción:Lectura de cuatro canales analógicos.
* Este programa utiliza la interrupción del
* conversor A/D.
* Placa Arduino: MEGA 2560
* Arduino IDE: 1.8.5
*
* www.firtec.com.ar
*******************************************************************/
#include "LiquidCrystal.h" // Biblioteca para el LCD
#define ledPin 13 // Pin del LED de la placa Mega
// -------- Variables del programa ---------------------------------
byte adc_Pin = 0;
volatile unsigned char muestras_0=0,muestras_1=0,muestras_2=0,muestras_3=0;
volatile unsigned int M0=0,M1=0,M2=0,M3=0;
volatile float conversion,conv_0,conv_1,conv_2,conv_3;
char buffer[10]=" ";
char* buffn="";
// RS E datos
LiquidCrystal lcd(8,9,4,5,6,7); // Pines del LCD
/********************************************************************
* Función para la configuración del Hardware
* Argumentos: NINGUNO
* Retorna: NADA
*
*********************************************************************/
void setup (){
lcd.begin(20,4);
pinMode(ledPin, OUTPUT); // Pin del LED de la placa
digitalWrite(13,LOW ); // LED inicia apagado
ADCSRA = bit (ADEN); // Inicia el ADC
ADCSRA |= bit (ADPS0) | bit (ADPS1) | bit (ADPS2); // Prescaler en 128
ADMUX = bit (REFS0) | (adc_Pin & 0x07); // Incia en el canal 0
//ADMUX = 0x40;
lcd.setCursor(0,0);
lcd.print("Voltaje A0: ");
lcd.setCursor(0,1);
lcd.print("Voltaje A1: ");
lcd.setCursor(0,2);
lcd.print("Voltaje A2: ");
lcd.setCursor(0,3);
lcd.print("Voltaje A3: ");
}
/********************************************************************
* Función ISR para la lectura de los canales analógicos.
* Interrumpe 5 veces en cada canal para leer y promediar la lectura
* de cada canal.
* Argumentos: NINGUNO
* Retorna: NADA
*
*********************************************************************/
ISR (ADC_vect){
switch(adc_Pin){
case 0:{
M0 += ADC; // Acumula los datos en M0
muestras_0++;
if(muestras_0 == 5){ // Se tomaron 5 muestras?
conv_0 = M0/5; // Promedia la muestras
muestras_0 =0; // Limpia registros
M0=0;
adc_Pin++; // Prepara el siguiente canal
ADMUX = bit (REFS0) | (adc_Pin & 0x07);
}
break;
}
case 1:{
M1 += ADC;
muestras_1++;
if(muestras_1 == 5){
conv_1 = M1/5;
muestras_1 =0;
M1=0;
adc_Pin++;
//adc_Pin = 0;
ADMUX = bit (REFS0) | (adc_Pin & 0x07);
}
break;
}
case 2:{
M2 += ADC;
muestras_2++;
if(muestras_2 == 5){
conv_2 = M2/5;
muestras_2 =0;
M2=0;
adc_Pin++;
ADMUX = bit (REFS0) | (adc_Pin & 0x07);
}
break;
}
case 3:{
M3 += ADC;
muestras_3++;
if(muestras_3 == 5){
conv_3 = M3/5;
muestras_3 =0;
M3=0;
adc_Pin = 0;
ADMUX = bit (REFS0) | (adc_Pin & 0x07);
}
break;
}
}
}
/********************************************************************
* Función pincipal del programa, escala y muestra los datos.
********************************************************************/
void loop (){
//------ Escala el canal 0 -------
conversion = (conv_0 *5.0)/1024;
dtostrf(conversion,2,2,buffn);
sprintf(buffer,"%s", buffn);
lcd.setCursor(11,0);
lcd.print(buffer);
//------ Escala el canal 1 -------
conversion = (conv_1 *5.0)/1024;
dtostrf(conversion,2,2,buffn);
sprintf(buffer,"%s", buffn);
lcd.setCursor(11,1);
lcd.print(buffer);
//------ Escala el canal 2 -------
conversion = (conv_2 *5.0)/1024;
dtostrf(conversion,2,2,buffn);
sprintf(buffer,"%s", buffn);
lcd.setCursor(11,2);
lcd.print(buffer);
//------ Escala el canal 3 -------
conversion = (conv_3 *5.0)/1024;
dtostrf(conversion,2,2,buffn);
sprintf(buffer,"%s", buffn);
lcd.setCursor(11,3);
lcd.print(buffer);
ADCSRA |= bit (ADSC) | bit (ADIE);
}
El resultado del ejemplo es el siguiente.
Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.
Cuando los enfoques informáticos clásicos (servidores web, socket de red, etc) resultan ser demasiado “pesados” por la cantidad de recursos necesarios para sostenerlos o resultan ser soluciones exageradas para resolver una simple comunicación de algunos Bytes, entran en juego protocolos como MQTT (Message Queue Telemetry Transport), ideado por IBM es un protocolo usado para la comunicación máquina a máquina (M2M).
Específico para Internet de las cosas, orientado a la comunicación de sensores y dispositivos con una tasa de transferencia de datos baja, necesita muy poco ancho de banda y puede ser utilizado en la mayoría de los dispositivos con escasos recursos (CPU, RAM, etc).
La arquitectura de MQTT sigue una topología de estrella, con un nodo central que hace de servidor o "broker" normalmente con una capacidad teórica de hasta 10000 clientes. El broker es el encargado de gestionar la red y de transmitir los mensajes, para mantener activo el canal, los clientes mandan periódicamente un paquete de datos y según el caso pueden esperar una confirmación del broker.
La comunicación se basa en "topics" o temas, y para que un cliente tenga acceso a la información debe estar subscrito al tema sin importar cuantos clientes estén siguiendo el tema.
Un cliente (cualquiera) puede publicar mensajes y los nodos, que deseen recibirlo deben estar subscrito a él. La comunicación puede ser de uno a uno, o de uno a muchos. Un "topic" se representa mediante una cadena y tiene una estructura jerárquica separada con '/'.
Por ejemplo, "firtec/sensor_1/temperatura" o "firtec/sensor_2/ruido". De esta forma se pueden crear jerarquías de clientes que publican y reciben datos.
El funcionamiento es sencillo y sumamente ágil. El servidor o broker, recopila los datos que los publishers, los clientes o nodos que publican los tópicos. Determinados datos recopilados por el broker se enviarán a determinados nodos que previamente así se lo hayan solicitado al broker.
El principio de intercambio se parece mucho al de Twitter donde los publishers envían los mensajes a un canal llamado topic. Los suscriptores pueden leer esos mensajes. Los topics (o canales de información) pueden estar distribuidos jerárquicamente de forma que se puedan seleccionar exactamente las informaciones que se desean. Los mensajes enviados por los nodos pueden ser de todo tipo pero no pueden superar los 256 Mbit.
Por ejemplo el tópico firtec/oficina_1/temperatura comunicará la temperatura de oficina_1 si se suscribe un nodo a ese tópico el sensor de temperatura presente en la oficina_1 publicará periódicamente en ese tópico la temperatura registrada.
Si un nodo se suscribe al topic firtec/oficina_1/#, recibirá todos los datos de la oficina (por ejemplo, luminosidad, humedad, temperatura, etc). Si se suscribe al topic firtec/#, recibirá todos los datos de los sensores de firtec.
En este ejemplo se ha conectado un sensor para medir la cantidad de luz visible al ojo humano, los datos son "publicados" en la red MQTT interna de tal forma que todos los subscritos al tema (tópico) pueden acceder a los datos del sensor.
Con esta tecnología podemos publicar datos en la red con cualquier microcontrolador (PIC, Atmel, ARM, etc) solo se necesita un broker MQTT y que los dispositivos accedan a la red por ejemplo a través de un puente ESP32 y su conexión Wi-Fi.
Tensilica es una compañía fundada en 1997 pero que en los últimos tiempos viene sorprendiendo con sus nuevos procesadores y en particular por el alto grado de integración de periféricos.
Tomando como ejemplo el Xtensa LX6 con dos núcleos de 32 bits y donde todo está a bordo. ESP32 tiene este procesador y es considerado una evolución del popular ESP8266 de amplio uso en el mundo de los microcontroladores.
Dos núcleos operando a 240 Mhz que pueden trabajar en forma cooperativa o independiente. Todo compatible con ARM y siguiendo la misma filosofía de programación como se puede ver en el siguiente código para leer un canal analógico.
Tener mas de una CPU lleva el trabajo con microcontroladores a otro nivel donde el concepto de multitarea se hace realidad.
En los ejemplos estuvimos probando la placa SparkFun ESP32 Thing con resultados realmente muy interesantes.
Para construir una aplicación completa no necesitamos agregar ningún microcontrolador. ES32 tiene todo lo necesario incluso conectividad WiFi y algo por demás interesante es que podemos trabajar directamente con el entorno de Arduino.
En este ejemplo se ha instalado un servidor MQTT en una placa Raspberry PI y el siguiente código en ESP32 programado mediante el IDE de Arduino, el ejemplo solo lee el sensor HDC1000 conectado al puerto I2C del ESP32 y publica los datos en una red MQTT.
A su vez ESP32 publica en la red el control de un LED que la propia placa trae a bordo, los clientes con acceso al tópico pueden controlar el estado del LED.
El resultado es el siguiente.