Saludos!!!
Pretendo con el siguiente POST, entregar una solución a cientos de personas que han pasado por el problema de realizar el envío de más de 32 BIT's desde el Maestro al Esclavo usando el protocolo I2C y apoyandome en la librería ARDUINOJSON, y por supuesto enviar datos desde el Esclavo con más de 32 BIT'S.
La dinámica de trabajo fue concebida gracias a tutoriales en la RED y desde este propio espacio.
No creo en lo absoluto que sea mi propuesta la solución definitiva, pero como no he encontrado en ninguna publicación los aspectos aquí tratados, me tomo el tiempo de realizarlo esperando sea de beneficio para muchos.
Espero también los aportes de los tan prestigiosos miembros con el fin de generar alguna especia de ESTANDAR para solucionar el requerimiento.
Este proyecto esta concebido entre dos ARDUINO MEGA, El Maestro posea un escudo CS3231 con el que obtengo los parámetros de DIA Y MES.
Sin más, le dejo mis códigos.
Código del Arduino Maestro:
#include "Wire.h"
#include <ArduinoJson.hpp>
#include <ArduinoJson.h>
#include <DS3231.h>
DS3231 rtc;
boolean century = false; // Control para el Siglo XXII
boolean h12Flag; // Variable para distinguir formato de 12 horas
boolean pmFlag; // Variable para saber si es am o pm
const byte I2C_SLAVE_ADDR = 0x20;
const char SEND_LENGTH = 'R';
const char ASK_FOR_LENGTH = 'L';
const char ASK_FOR_DATA = 'D';
String response;
String jsonA;
String jsonB;
StaticJsonDocument<300> doc;
StaticJsonDocument<300> doc_env;
int veces = 1;
void setup() {
Serial.begin(9600);
Wire.begin();
}
void loop() {
Serial.print("Proceso número: ");Serial.println(veces);
askSlave();
if(response != "") DeserializeResponse();
veces ++;
}
void askSlave() {
response = "";
paqueteEnvio(veces, 0);
unsigned int envioTamPaq = envioInicio();
if (envioTamPaq != 1) return;
envioLargoPaq();
Serial.println("Continua proceso normal ");
Serial.println(" ");
unsigned int responseLenght = askForLength();
if (responseLenght == 0) return;
askForData(responseLenght);
delay(2000);
}
unsigned int envioInicio(){
Wire.beginTransmission(I2C_SLAVE_ADDR);
Wire.write(SEND_LENGTH);
Wire.endTransmission();
Wire.requestFrom(I2C_SLAVE_ADDR, 1);
unsigned int respuesta = Wire.read();
return respuesta;
}
void envioLargoPaq(){
Serial.print("Se va a enviar ");Serial.println(jsonB.length());
Wire.beginTransmission(I2C_SLAVE_ADDR);
Wire.write(jsonB.length());
Wire.endTransmission();
int acumulaLargo = 0;
Wire.requestFrom(I2C_SLAVE_ADDR, 1);
unsigned int respuesta = Wire.read();
Serial.print("Inicio de envío de Paquete ");Serial.println(jsonB);
if (jsonB.length() > 32) {
Serial.println("Paquete > a 32 bit");
int tot_iter = jsonB.length() / 32;
int inicio = 0;
int final = 31;
for (int iter = 0; iter <= tot_iter; iter++) {
String sub_S = jsonB.substring(inicio, final);
Serial.print("Paquete dividido. Acción: -> ");Serial.println(iter);
Serial.print("Paquete -> ");Serial.println(sub_S);
Wire.beginTransmission(I2C_SLAVE_ADDR);
Wire.write(sub_S.c_str(), sub_S.length());
Wire.endTransmission();
inicio = final;
final = final + 31;
acumulaLargo ++;
Wire.requestFrom(I2C_SLAVE_ADDR, 1);
unsigned int listo = Wire.read();
Serial.print("Respuesta de pasos -> ");Serial.println(listo);
}
} else {
Serial.println("Paquete < a 32 bit");
Wire.beginTransmission(I2C_SLAVE_ADDR);
Wire.write(jsonB.c_str() + acumulaLargo * 32, (jsonB.length() % 32));
Wire.endTransmission();
acumulaLargo = 0;
}
Serial.println("termino el envío de Paquete ");
}
unsigned int askForLength()
{
Wire.beginTransmission(I2C_SLAVE_ADDR);
Wire.write(ASK_FOR_LENGTH);
Wire.endTransmission();
Wire.requestFrom(I2C_SLAVE_ADDR, 1);
unsigned int responseLenght = Wire.read();
return responseLenght;
}
void askForData(unsigned int responseLenght) {
Wire.beginTransmission(I2C_SLAVE_ADDR);
Wire.write(ASK_FOR_DATA);
Wire.endTransmission();
for (int requestIndex = 0; requestIndex <= (responseLenght / 32); requestIndex++) {
Wire.requestFrom(I2C_SLAVE_ADDR, requestIndex < (responseLenght / 32) ? 32 : responseLenght % 32);
while (Wire.available())
{
response += (char)Wire.read();
}
}
}
char* text;
int id;
bool stat;
float value;
void DeserializeResponse() {
DeserializationError error = deserializeJson(doc, response);
if (error) { return; }
text = doc["text"];
id = doc["id"];
stat = doc["status"];
value = doc["value"];
Serial.print("Text ");Serial.print(text);
Serial.print(" - id ");Serial.print(id);
Serial.print(" - status ");Serial.print(stat);
Serial.print(" - value ");Serial.println(value);
Serial.println(" ");
}
void paqueteEnvio(int var_08, int accion) {
String tabla;
jsonB = "";
doc_env.clear();
if (esPar(var_08) == true) {
tabla = "0";
} else {
tabla = "1";
}
doc_env["tabla"] = tabla;
switch (tabla.toInt()) {
case 0: // - Datos Generales
doc_env["accion"] = accion;
break;
case 1: // - Datos de DUMP (Archivo diario)
doc_env["accion"] = accion;
switch (accion) {
case 0: // - Datos Generales
int v01__mes = rtc.getMonth(century);
int v01__dia = rtc.getDate();
doc_env["v_mes"] = v01__mes;
doc_env["v_dia"] = v01__dia;
break;
}
break;
case 2: // - Datos de Temperatura y Humedad
break;
case 3: // - Datos de Eventos Especiales
break;
}
serializeJson(doc_env, jsonB);
}
boolean esPar(int param_01){
if (param_01 & 0x01) {
return false;
} else {
return true;
}
}
Código del Arduino Esclavo
#include "Wire.h"
#include <ArduinoJson.hpp>
#include <ArduinoJson.h>
String json;
String response = "";
int acto = 1;
unsigned int largoRequerimiento;
StaticJsonDocument<300> doc;
const byte I2C_SLAVE_ADDR = 0x20;
const char SEND_LENGTH = 'R';
const char ASK_FOR_LENGTH = 'L';
const char ASK_FOR_DATA = 'D';
char request = ' ';
char requestIndex = 0;
int canIter = 1;
int pasos = 0;
void setup() {
Serial.begin(9600);
SerializeObject();
Wire.begin(I2C_SLAVE_ADDR);
Wire.onRequest(requestEvent);
Wire.onReceive(receiveEvent);
}
void receiveEvent(int bytes) {
switch (acto) {
case 1:
while (Wire.available()) {
request = (char)Wire.read();
}
break;
case 2:
largoRequerimiento = Wire.read();
if (largoRequerimiento > 32) {
int positivo;
int decimal;
float tot_div = (float)largoRequerimiento / 32;
positivo = int(tot_div);
decimal = int((tot_div - int(tot_div)) * 100);
if (decimal > 0){
canIter = positivo + 1;
pasos = canIter;
} else {
canIter = positivo;
}
} else {
canIter = 1;
}
request = 'Z';
break;
case 3:
if (canIter == 1) {
while (Wire.available()) {
response += (char)Wire.read();
}
Serial.print("Respuesta ");Serial.println(response);
acto = 1;
request = ' ';
} else {
String paquete;
paquete = "";
while (Wire.available()) {
paquete += (char)Wire.read();
// char paquete = Wire.read();
}
response = response + paquete;
request = 'X';
pasos = pasos -1;
}
break;
}
}
void requestEvent() {
if(request == SEND_LENGTH) {
Wire.write(1);
acto = 2;
}
if(request == 'Z') {
Wire.write(1);
acto = 3;
response = "";
}
if(request == 'X') {
Wire.write(pasos);
if (pasos == 0){
Serial.print("Respuesta ");Serial.println(response);
acto = 1;
} else {
acto = 3;
}
}
if(request == ASK_FOR_LENGTH) {
Wire.write(json.length());
char requestIndex = 0;
}
if(request == ASK_FOR_DATA) {
if(requestIndex < (json.length() / 32)) {
Wire.write(json.c_str() + requestIndex * 32, 32);
requestIndex ++;
} else {
Wire.write(json.c_str() + requestIndex * 32, (json.length() % 32));
requestIndex = 0;
}
}
}
void loop() {
}
void SerializeObject() {
doc["text"] = "myText";
doc["id"] = 10;
doc["status"] = true;
doc["value"] = 3.14;
serializeJson(doc, json);
}
Luego de obtener el requerimiento del maestro, en el código del Arduino Esclavo en "Serial.print("Respuesta ");Serial.println(response);" se puede descomponer dicho valor para realizar las tareas pertinentes.
El paquete desde el Maestro se arma de la siguiente manera:
Primera posición (Identificación de Archivo) Posición [0]
0 - Datos Generales
1 - Datos de DUMP (Archivo diario)
2 - Datos de Temperatura y Humedad
3 - Datos de Eventos Especiales
Segunda posición (Acción) Posición [2] (Para CONSULTA varia dependiendo la posición a ubicar desde 2 a N)
0 - Verifica existencia de archivo. (Si no existe, lo crea)
1 - Update (Actualización de registro) Para Datos Generales actualiza todos los registros
2 - Crea un nuevo registro
3 - Consulta (L-ULTIMO, F-PRIMERO, UN NUMERO ES POSICION)
Las posiciones siguientes corresponden a los datos en los casos de UPDATE, CREACION y CONSULTA.
Espero les sea de provecho.
Gracias por su tiempo en valorar este aporte.