Buenas a todos,
Estoy realizando con una Arduino Nano clon (Clon NANO Compatible 100% con Arduino ATMega328P CH340G) y un ESP8266 (Placa WeMos D1 Mini 4Mb WiFi ESP8266 CH340 Wireless IoT NodeMCU v2 3,3v 3.3) clon una "estación meteorológica" casera. El Nano tiene conectado una pantalla OLED (Display OLED 0,96 pulgadas I2C 128x64 BLANCO 0.96” ARDUINO SSD1306) y un sensor de temperatura, humedad y presión a través del puerto I2C (AHT20 + BMP280 Sensor Presión de Atmosférica, Temperatura y Humedad) y funcionan correctamente.
Después he conectado el Nano con el ESP8266 a través de un conversor (Modulo Conversor Bidireccional 3,3v 5v 4 canales nivel logico i2c SPI) a través de los pines que indican que pertenecen a sus puertos serial para realizar la comunicación de temperatura, humedad y presión de uno a otro, con la idea final de que el ESP8266 pueda mostrarlos a través de una página web que esté programada en él.
En este punto es en el que me encuentro y es dónde necesito ayuda al respecto. Mis conocimientos son superficiales y por ahí es donde me aparecen los problemas.
Desde el Nano tengo el programa para recibir los datos del sensor y enviarlos a la pantalla OLED y tengo que recurrir a la librería de comunicación "SoftwareSerial.h" para realizar la comunicación por el puerto serial (si no utilizo ésta y lo hago con "Serial", la pantalla OLED no muestra nada). En este punto, creo que lo tengo bien desarrollado para realizar la comunicación de salida por el puerto Serial. Os dejo el código desarrollado. Pido disculpas por el caos que pueda parecer y por la cantidad de código comentado, son otras pruebas realizadas para intentar conseguir la comunicación.
#include <Wire.h> //libreria para comunicacion I2C
#include <Adafruit_GFX.h> //libreria para gráficos en OLED
#include <Adafruit_SSD1306.h> //libreria control OLED
#include <AHT20.h> //libreria control sensor AHT20 temperatura y humedad
#include <BMP280.h> //libreria control sensor BMP280 presion y temperatura
#include <SoftwareSerial.h> //libreria para comunicación puerto serie
#define ANCHO_PANTALLA 128 // 128 bits ancho OLED
#define ALTO_PANTALLA 64 // 64 bits alto OLED
#define OLED_RESET -1
#define DIRECCION_PANTALLA 0x3C //dirección I2C de la pantalla
Adafruit_SSD1306 miPantalla(ANCHO_PANTALLA, ALTO_PANTALLA, &Wire, OLED_RESET); //defino objeto para manejar OLED
AHT20 aht20; //defino objeto para manejar sensor AHT20
BMP280 bmp280; //defino objeto para manejar sensor BMP280
SoftwareSerial D1(0,1); //RX=0 TX=1
const int muestras = 47, offset = 81;
const unsigned long INTERVALO_LECTURA1 = 3000UL; // tiempo para ejecutar el evento LECTURA1
unsigned long evento_lectura1 = 0; // posición evento lectura1 en el tiempo
int temperatura[muestras];
// byte receiveData[16];
// byte octeto1[1];
// byte octeto2[1];
// byte octeto3[1];
// byte octeto4[1];
byte sendData[16];
// byte sentTemp[5];
// byte sendHum[5];
// byte sendPres[4];
uint32_t pressure;
float temperature;
float humidity;
int valor;
void setup() {
// put your setup code here, to run once:
miPantalla.begin(SSD1306_SWITCHCAPVCC, DIRECCION_PANTALLA);
miPantalla.clearDisplay();
miPantalla.setTextSize(1);
miPantalla.setTextColor(SSD1306_WHITE);
miPantalla.setCursor(0, 0);
miPantalla.print("Inicializando Arduino");
miPantalla.display(); //inicializamos pantalla y mostramos primer mensaje
delay(2000);
Wire.begin(); //inicializamos la comunicación I2C
D1.begin(9600); //inicializamos la comunicación serie
bmp280.begin();
miPantalla.clearDisplay();
miPantalla.setCursor(0,0);
miPantalla.print("BMP280 inicializado");
miPantalla.display();
delay(500); //inicializamos sensor BMP280 y mostramos mensaje
if (aht20.begin() == false)
{
miPantalla.clearDisplay();
miPantalla.setCursor(0,0);
miPantalla.print("AHT20 no detectado. Comprobar cableado.");
miPantalla.display();
while (1);
}
miPantalla.clearDisplay();
miPantalla.setCursor(0,0);
miPantalla.print("AHT20 inicializado");
miPantalla.display();
delay(500); //inicializamos sensor AHT20 y mostramos mensaje
miPantalla.clearDisplay();
miPantalla.setCursor(0,0);
miPantalla.print("Inicializado");
miPantalla.display(); //monstramos mensaje de sistema listo
for (int i = 0; i < muestras; i++) {
temperatura[i] = 44;
} //dejamos el array con los valores 0 de la gráfica
delay(2000);
// receiveData[16]=D1.read();
// miPantalla.clearDisplay();
// miPantalla.setCursor(0,0);
// miPantalla.println("Conectar a la IP:");
// miPantalla.print(receiveData);
// delay(10000);
miPantalla.clearDisplay();
}
void loop() {
// put your main code here, to run repeatedly:
unsigned long actual = millis(); //valor actual de tiempo
if (actual > evento_lectura1) { //el valor de tiempo llegó al valor de inicio de lectura?
if (aht20.available() == true) { //Sensor AHT20 listo para dar medida?
//Get the new temperature and humidity value
temperature = aht20.getTemperature();
humidity = aht20.getHumidity();
pressure = bmp280.getPressure() / 100; //obtenemos los valores de los sensores
for (int i = 0; i < muestras; i++) { // i=81
temperatura[i - 1] = temperatura[i];
} //movemos los valores del array una posición a la izquierda
temperatura[muestras - 1] = map(temperature, -10.0, 40.0, 55, 0); //mapeamos los valores de temperatura para que entren en la gráfica y guardamos el último valor en la última posicion
}
// if (D1.available()) {
// valor = D1.read();
// }
miPantalla.clearDisplay();
miPantalla.setCursor(0,0);
miPantalla.println("AZUL");
miPantalla.print("T: ");
miPantalla.print(temperature);
miPantalla.println(" C");
miPantalla.print("H: ");
miPantalla.print(humidity);
miPantalla.println(" %");
miPantalla.print("P: ");
miPantalla.print(pressure);
miPantalla.println(" hPa"); //mostramos en pantalla los valores obtenidos
miPantalla.setCursor(0,44);
miPantalla.println("IP:");
miPantalla.println(temperature);
miPantalla.setCursor(64,0);
miPantalla.print("40");
miPantalla.setCursor(64,11);
miPantalla.print("30");
miPantalla.setCursor(64,22);
miPantalla.print("20");
miPantalla.setCursor(64,33);
miPantalla.print("10");
miPantalla.setCursor(70,44);
miPantalla.print("0");
miPantalla.setCursor(58,55);
miPantalla.print("-10"); //dibujamos la escala de la gráfica
miPantalla.drawLine(77,0,80,0,WHITE);
miPantalla.drawLine(77,11,80,11,WHITE);
miPantalla.drawLine(77,22,80,22,WHITE);
miPantalla.drawLine(77,33,80,33,WHITE);
miPantalla.drawLine(77,44,80,44,WHITE); //dibujamos las lineas que marcan la escala
miPantalla.drawLine(77,55,127,55,WHITE);
miPantalla.drawLine(80,0,80,55,WHITE); //dibujamos los ejes límites del gráfico.
for (int i = 0; i <= muestras - 1; i++){ // i = 81
miPantalla.drawPixel(i + offset, temperatura[i], WHITE);
} //dibujamos cada pixel de la temperatura
evento_lectura1 += INTERVALO_LECTURA1;
byte btemperature[5];
byte bhumidity[5];
byte bpressure[4];
desmantelarNumeroFloat(btemperature, temperature);
desmantelarNumeroFloat(bhumidity, humidity);
desmantelarNumeroEnteroLargo(bpressure, pressure);
// int tem = temperature * 100.0;
// byte temA = tem / 100;
// byte temB = tem % 100;
// int hum = humidity *100.0;
// byte humA = hum / 100;
// byte humB = hum % 100;
// byte preA = pressure / 100;
// byte preB = pressure % 100;
sendData[0] = 'i';
sendData[1] = btemperature[0];
sendData[2] = btemperature[1];
sendData[3] = btemperature[2];
sendData[4] = btemperature[3];
sendData[5] = btemperature[4];
sendData[6] = bhumidity[0];
sendData[7] = bhumidity[1];
sendData[8] = bhumidity[2];
sendData[9] = bhumidity[3];
sendData[10] = bhumidity[4];
sendData[11] = bpressure[0];
sendData[12] = bpressure[1];
sendData[13] = bpressure[2];
sendData[14] = bpressure[3];
sendData[15] = 'f';
D1.write(sendData[16]);
// miPantalla.setCursor(0,33);
// miPantalla.print(sendData[1]); // 1
// miPantalla.print(" ");
// miPantalla.print(sendData[2]); // 2
// miPantalla.print(" ");
// miPantalla.print(sendData[3]); // 3
// miPantalla.print(" ");
// miPantalla.print(sendData[4]); // 4
// miPantalla.print(" ");
// miPantalla.print(sendData[5]); // 5
}
miPantalla.display();
}
void desmantelarNumeroFloat(byte* matriz, float dato){
byte centena = dato / 100;
byte decena = (dato - (centena * 100)) / 10;
byte unidad = (dato - (centena * 100) - (decena * 10)) / 1;
byte decimal = (dato - (centena * 100) - (decena * 10) - unidad) / 0.1;
byte centesimal = (dato - (centena * 100) - (decena * 10) - unidad - (decimal * 0.1)) / 0.01;
matriz[0] = centena;
matriz[1] = decena;
matriz[2] = unidad;
matriz[3] = decimal;
matriz[4] = centesimal;
// matriz[1] = centesimal;
// matriz[2] = decimal;
// matriz[3] = unidad;
// matriz[4] = decena;
// matriz[5] = centena;
}
void desmantelarNumeroEnteroLargo(byte* matriz, uint32_t dato){
byte mil = dato / 1000;
byte centena = (dato - (mil * 1000)) / 100;
byte decena = (dato - (mil * 1000) - (centena * 100)) / 10;
byte unidad = (dato - (mil * 1000) - (centena * 100) - (decena * 10));
matriz[0] = mil;
matriz[1] = centena;
matriz[2] = decena;
matriz[3] = unidad;
// matriz[1] = unidad;
// matriz[2] = decena;
// matriz[3] = centena;
// matriz[4] = mil;
}
Desde el ESP8266 tengo el siguiente código, que es el encargado de recibir los datos que envío desde Nano y que al final mostraré en la página web. La comunicación la realiza a través de serial. Este código es más caótico que el anterior y tiene más código comentado del montón de pruebas realizadas que no han funcionado. Piso disculpas por cómo ha quedado de antemano.
#include <ESP8266WiFi.h>
// #include <SoftwareSerial.h>
const char* ssid = "MiRed";
const char* password = "MiContraseña";
// float temperature;
byte receiveData[16];
WiFiServer server(80);
// SoftwareSerial D1(3,1); //RX=GPIO3 TX=GPIO1
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
delay(10);
// D1.begin(9600); //inicializando la comunicacion serie
Serial.println();
Serial.println();
Serial.print("Conectandose a red : ");
Serial.println(ssid);
WiFi.begin(ssid, password); //Conexión a la red
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi conectado");
Serial.print("Conectado a la red WiFi: ");
Serial.println(WiFi.SSID());
Serial.print("IP: ");
Serial.println(WiFi.localIP());
Serial.print("MAC address: ");
Serial.println(WiFi.macAddress());
server.begin(); //Iniciamos el servidor
Serial.println("Servidor Iniciado");
Serial.println("Ingrese desde un navegador web usando la siguiente IP:");
Serial.println(WiFi.localIP()); //Obtenemos la IP
// D1.println(WiFi.localIP());
}
void loop() {
// put your main code here, to run repeatedly:
if (Serial.available()) {
// char x = D1
Serial.read(receiveData, 15);
byte tamano = sizeof(receiveData);
// if (receiveData[0] != 2 && receiveData[1] != 0){
// Serial.println("NO LLEGO BIEN EL PRIMER DATO, RECOMPONIENDO");
// for (byte i = 13; i >= 1; i--){
// receiveData[i] = receiveData[i - 1];
// }
// receiveData[0] = 2;
// }
// if (receiveData[10] != 2){}
// Serial.println(receiveData[0]);
// if (receiveData[0] >= 0){
// byte primero = receiveData[13];
// for (byte i = 13; i <= 1; i--){
// receiveData[i] = receiveData[i - 1];
// }
// receiveData[0] = primero;
// }
// Serial.println(receiveData[0]);
if ((receiveData[0] = 'i') && (receiveData[15] = 'f')){
float temp_rec = construirNumeroFloat(receiveData, 1);
float hum_rec = construirNumeroFloat(receiveData, 6);
uint32_t pres_rec = construirNumeroEntero(receiveData, 11);
// byte temA = receiveData[1];
// int TemA = (int) temA * 100;
// byte temB = receiveData[2];
// int TemB = (int) temB;
// float temp_rec = (TemA + TemB) / 100.0;
Serial.print(temp_rec);
Serial.print(" ºC, ");
// byte humA = receiveData[3];
// int HumA = (int) humA * 100;
// byte humB = receiveData[4];
// int HumB = (int) humB;
// float hum_rec = (HumA + HumB) / 100.0;
Serial.print(hum_rec);
Serial.print(" %, ");
// byte preA = receiveData[5];
// int PreA = (int) preA * 100;
// byte preB = receiveData[6];
// int PreB = (int) preB;
// float pres_rec = (PreA + PreB);
Serial.print(pres_rec);
Serial.println( " hPa");
}
else{
Serial.println("DATO ERRÓNEO");
}
// float temp_rec = construirNumeroFloat(receiveData, 1); //1
// float hum_rec = construirNumeroFloat(receiveData, 6); //6
// uint32_t pres_rec = contruirNumeroEntero(receiveData, 11); //12
// Serial.println(tamano);
// Serial.print(receiveData[0]);
// Serial.print(" ");
// Serial.print(receiveData[1]);
// Serial.print(" ");
// Serial.print(receiveData[2]);
// Serial.print(" ");
// Serial.print(receiveData[3]);
// Serial.print(" ");
// Serial.print(receiveData[4]);
// Serial.print(" ºC, ");
// Serial.print(" "); //no
// Serial.print(receiveData[5]);
// Serial.print(" ");
// Serial.print(" ºC, "); //no
// Serial.print(receiveData[6]);
// Serial.print(" ");
// Serial.print(receiveData[7]);
// Serial.print(" ");
// Serial.print(receiveData[8]);
// Serial.print(" ");
// Serial.print(receiveData[9]);
// Serial.print(" % ");
// Serial.print(" "); //no
// Serial.print(receiveData[10]);
// Serial.print(" ");
// Serial.print(" % "); //no
// Serial.print(receiveData[11]);
// Serial.print(" ");
// Serial.print(receiveData[12]);
// Serial.print(" ");
// Serial.print(receiveData[13]);
// Serial.println(" hPa ");
// Serial.print(" "); //no
// Serial.print(receiveData[14]); //no
// Serial.println(" hPa "); //no
// Serial.println(receiveData[15]); //no
// Serial.print(temp_rec);
// Serial.print(" ºC, ");
// Serial.print(hum_rec);
// Serial.print(" %, ");
// Serial.print(pres_rec);
// Serial.println( " hPa");
delay(6000);
}
// Serial.println(WiFi.localIP());
// WiFiClient client = server.available();
// if (client) //Si hay un cliente presente
// {
// Serial.println("Nuevo Cliente");
// //esperamos hasta que hayan datos disponibles
// while(!client.available()&&client.connected())
// {
// delay(1);
// }
// temperature = Serial.read();
// // Leemos la primera línea de la petición del cliente.
// String linea1 = client.readStringUntil('r');
// Serial.println(linea1);
// if (linea1.indexOf("LED=ON")>0) //Buscamos un LED=ON en la 1°Linea
// {
// digitalWrite(2,HIGH);
// }
// if (linea1.indexOf("LED=OFF")>0)//Buscamos un LED=OFF en la 1°Linea
// {
// digitalWrite(2,LOW);
// }
// client.flush();
// Serial.println("Enviando respuesta...");
// //Encabesado http
// client.println("HTTP/1.1 200 OK");
// client.println("Content-Type: text/html");
// client.println("Connection: close");// La conexión se cierra después de finalizar de la respuesta
// client.println();
// //Pagina html para en el navegador
// client.println("<!DOCTYPE HTML>");
// client.println("<html>");
// client.println("<head><title>Naylam Mechatronics</title>");
// client.println("<body>");
// client.println("<h1 align='center'>Test ESP8266</h1>");
// client.println("<div style='text-align:center;'>");
// client.println("<br />");
// client.println("<button onClick=location.href='./?LED=ON'>LED ON</button>");
// client.println("<button onClick=location.href='./?LED=OFF'>LED OFF</button>");
// client.println("<br />");
// client.println("</div>");
// client.println("</body>");
// client.println("</html>");
// delay(1);
// Serial.println("respuesta enviada");
// Serial.println();
// }
}
float construirNumeroFloat(byte* matriz, byte i){
float valor = 0.0;
// if (receiveData[i] > 1){}
valor = receiveData[i] * 100 + receiveData[i + 1] * 10 + receiveData[i + 2] + receiveData[i + 3] * 0.1 + receiveData[i + 4] * 0.01;
// valor = receiveData[i] * 0.01 + receiveData[i + 1] * 0.1 + receiveData[i + 2] + receiveData[i + 3] * 10 + receiveData[i + 4] * 100;
return valor;
}
uint32_t construirNumeroEntero(byte* matriz, byte i){
uint32_t valor = 0;
valor = receiveData[1] * 1000 + receiveData[i + 1] * 100 + receiveData[i + 2] * 10 + receiveData[i + 3];
// valor = receiveData[1] + receiveData[i + 1] * 10 + receiveData[i + 2] * 100 + receiveData[i + 3] * 100;
return valor;
}
El problema que he tenido hasta el momento ha sido que los datos "emitidos" por el Nano no han llegado bien al ESP8266. No son los mismos datos que envié. En algún caso que utilicé in "print" del valor enviado por el Nano, en el receptor ESP8266, sí he ma mostrado los valores que salieron y los imprimió correctamente.
Necesito que me aporten algo de luz al respecto. Sospecho que la parte del Nano puede estar bien (al 80%) y que el problema principal esté en el ESP8266, que esté utilizando incorrectamente la instrucción "read" del puerto serial o que me falte codificación para obtener los valores que llegan por el puerto serial para que no sean valores ASCII (creo que la instrucción "write" los envía así.
Actualmente, con los códigos que están aquí mostrados, tengo los siguientes valores en el monitor serial. (Los valores que aparecen el el OLED son 22.82 ºC, 62.30 % y 949 hPa).
17:07:06.797 -> -493.28 ºC, -5333.28 %, 4294957968 hPa
17:07:12.708 -> -493.28 ºC, -5333.28 %, 4294957968 hPa
17:07:18.840 -> -493.28 ºC, -5333.28 %, 4294957968 hPa
17:07:24.709 -> -493.28 ºC, -5333.28 %, 4294957968 hPa
17:07:30.749 -> -493.28 ºC, -5333.28 %, 4294957968 hPa
17:07:36.723 -> -493.28 ºC, -5333.28 %, 4294957968 hPa
17:07:42.748 -> -493.28 ºC, -5333.28 %, 4294957968 hPa
17:07:48.730 -> -493.28 ºC, -5333.28 %, 4294957968 hPa
17:07:54.750 -> -493.28 ºC, -5333.28 %, 4294957968 hPa
17:08:00.726 -> -493.28 ºC, -5333.28 %, 4294957968 hPa