miércoles, 9 de septiembre de 2026

Persistencia de datos por medio de la memoria AT24C256

El circuito integrado AT24C256 proporciona 262,144 bits de memoria (32.768 kilobyes) de solo lectura programable y borrable eléctricamente en serie (EEPROM), organizada en 32,768 palabras de 8 bits cada una. La función de conexión en cascada del dispositivo permite que hasta 4 dispositivos compartan un bus común de dos hilos. El dispositivo está optimizado para su uso en numerosas aplicaciones industriales y comerciales donde el bajo consumo de energía y el bajo voltaje son esenciales.

Los pines de esta memoria se muestran en la siguiente figura.


La especificación de pines se muestra en la siguiente tabla.


Direccionamiento del dispositivo 

La EEPROM de 256K requiere una palabra de dirección de dispositivo de 8 bits, seguida de una condición de inicio, para habilitar el chip para una operación de lectura o escritura (véase la siguiente figura). La palabra de dirección del dispositivo consta de una secuencia obligatoria de unos y ceros para los cinco bits más significativos, como se muestra. Esto es común a todas las EEPROM de dos hilos.


La EEPROM de 256K utiliza los bits de dirección de dispositivo A1 y A0 para permitir hasta cuatro dispositivos en el mismo bus. Estos bits deben compararse con sus pines de entrada cableados correspondientes. Los pines A1 y A0 utilizan un circuito interno propietario que los polariza a un nivel lógico bajo si se les permite flotar.

El octavo bit de la dirección del dispositivo es el bit de selección de operación de lectura/escritura. Se inicia una operación de lectura si este bit está en nivel alto y una operación de escritura si está en nivel bajo.

Tras una comparación de la dirección del dispositivo, la EEPROM emitirá un cero. Si no se realiza ninguna comparación, el dispositivo volverá al estado de espera.

Seguridad de datos 
El AT24C256 cuenta con un sistema de protección de datos por hardware que permite al usuario proteger contra escritura toda la memoria cuando el pin WP está conectado a VCC.

Operaciones de la memoria
Escritura de un byte
Una operación de escritura requiere dos direcciones de palabra de datos de 8 bits, seguidas de la palabra de dirección del dispositivo y una confirmación. Al recibir esta dirección, la EEPROM responderá con un cero y, a continuación, registrará la primera palabra de datos de 8 bits. Tras recibir la palabra de datos de 8 bits, la EEPROM emitirá un cero. El dispositivo de direccionamiento, como un microcontrolador, debe entonces finalizar la secuencia de escritura con una condición de parada. En ese momento, la EEPROM entra en un ciclo de escritura con temporización interna, tWR, en la memoria no volátil. Todas las entradas se deshabilitan durante este ciclo de escritura y la EEPROM no responderá hasta que la escritura se complete (véase la siguiente figura).



Escritura de página
La EEPROM de 256 KB admite escrituras de página de 64 bytes. La escritura de una página se inicia de la misma manera que la escritura de un byte, pero el microcontrolador no envía una condición de parada tras la recepción de la primera palabra de datos. En cambio, una vez que la EEPROM confirma la recepción de la primera palabra de datos, el microcontrolador puede transmitir hasta 63 palabras de datos adicionales. La EEPROM responderá con un cero tras cada palabra de datos recibida. El microcontrolador debe finalizar la secuencia de escritura de página con una condición de parada (véase la siguiente figura).


Los 6 bits inferiores de la dirección de la palabra de datos se incrementan internamente tras la recepción de cada palabra. Los bits superiores de la dirección de la palabra de datos no se incrementan, conservando la ubicación de la fila de la página de memoria. Cuando la dirección de la palabra, generada internamente, alcanza el límite de la página, el siguiente byte se coloca al principio de la misma página. Si se transmiten más de 64 palabras de datos a la EEPROM, la dirección de la palabra de datos se reiniciará y los datos anteriores se sobrescribirán. El reinicio de la dirección durante la escritura se produce desde el último byte de la página actual hasta el primer byte de la misma página.

Sondeo de confirmación
Una vez iniciado el ciclo de escritura con temporización interna y desactivadas las entradas de la EEPROM, se puede iniciar el sondeo de confirmación. Este proceso consiste en enviar una condición de inicio seguida de la palabra de dirección del dispositivo. El bit de lectura/escritura indica la operación deseada. Solo si el ciclo de escritura interno se ha completado, la EEPROM responderá con un cero, permitiendo que la secuencia de lectura o escritura continúe.

Operaciones de lectura
Las operaciones de lectura se inician de la misma manera que las de escritura, con la excepción de que el bit de selección de lectura/escritura en la palabra de dirección del dispositivo se establece en uno. Existen tres tipos de operaciones de lectura: lectura de la dirección actual, lectura de dirección aleatoria y lectura secuencial.

Lectura de la dirección actual 
El contador interno de la dirección de la palabra de datos mantiene la última dirección a la que se accedió durante la última operación de lectura o escritura, incrementada en uno. Esta dirección permanece válida entre operaciones mientras el chip esté alimentado. El "rollover" de la dirección durante la lectura se produce desde el último byte de la última página de memoria hasta el primer byte de la primera página.

Una vez que la dirección del dispositivo con el bit de selección de lectura/escritura establecido en uno se registra y la EEPROM la confirma, la palabra de datos de la dirección actual se envía en serie. El microcontrolador no responde con una entrada cero, pero sí genera una condición de parada (véase la siguiente figura).

Lectura aleatoria
Una lectura aleatoria requiere una secuencia de escritura de bytes ficticios para cargar la dirección de la palabra de datos. Una vez que la EEPROM recibe y confirma la palabra de dirección del dispositivo y la palabra de datos, el microcontrolador debe generar otra condición de inicio.

El microcontrolador inicia entonces una lectura de la dirección actual enviando la dirección del dispositivo con el bit de selección de lectura/escritura en alto. La EEPROM confirma la dirección del dispositivo y envía la palabra de datos en serie. El microcontrolador no responde con un cero, sino que genera una condición de parada (véase la siguiente figura).



Lectura secuencial
Las lecturas secuenciales se inician mediante la lectura de la dirección actual o de una dirección aleatoria. Tras recibir una palabra de datos, el microcontrolador responde con una confirmación. Mientras la EEPROM reciba una confirmación, seguirá incrementando la dirección de la palabra de datos y enviando secuencialmente palabras de datos en serie. Cuando se alcanza el límite de direcciones de memoria, la dirección de la palabra de datos se reinicia y la lectura secuencial continúa. La operación de lectura secuencial finaliza cuando el microcontrolador no responde con un cero, pero sí genera una condición de parada posterior (véase la siguiente figura).

Registro de temperaturas con placa ESP32 y Apps Script (Google Sheets)

Introducción

Este proyecto tiene como objetivo crear una base de datos de temperaturas en Google Sheets, para esto se va utilizar la placa de desarrollo ESP32 junto con el sensor LM35 para poder enviar las lecturas del sensor a la web y guardarlas en una hoja de cálculo.

Consideraciones teóricas

Sensor LM35

El LM35 es un sensor de temperatura, tiene un rango de medición que abarca desde -55 °C hasta 150 °C. La salida es lineal y cada grado Celsius equivale a 10 mV, por lo tanto: 1°C = 10 mV 2°C = 20 mV … 150°C = 1500 mV

Es decir, la salida del sensor es Vout =10mV/°C.

La siguiente imagen muestra los pines de conexión de este sensor.




ADC de la placa ESP32
La placa ESP32 de 38 pines tiene 16 entradas que se pueden usar como entradas analógicas, esto es posible debido a que la placa incorpora un conversor analógico a digital. Estas 16 entradas que pueden leer una señal analógica tienen una resolución de 12 bits, esto quiere decir que aquellos valores que se lean en los pines serán convertidos a valores entre 0 y 4095 (2^12=4096), sin embargo esta placa también se puede configurar otras resoluciones como 11, 10 y 9 bits.

Otra forma de ver la explicación anterior es: se está dividiendo el rango de 0 a 3.3V del ESP32 en 4096 partes (del 0 al 4095).

Otro aspecto relevante es que ESP32 divide el convertidor en 2 partes, ADC1_X y ADC2_X, cabe resaltar que ADC2 es usado por el controlador Wi-Fi de la placa, por tanto, solo se puede hacer uso de ADC2 cuando el controlador de Wi-Fi no se ha iniciado.

Arquitectura cliente-servidor

La arquitectura cliente-servidor es un modelo de diseño de software en el que las aplicaciones se dividen en dos componentes principales: clientes y servidores. Esta separación facilita la gestión de recursos y permite que ambos interactúen de manera eficiente. El cliente realiza solicitudes de servicios o datos, mientras que el servidor proporciona esos recursos. Este sistema se basa en una comunicación constante mediante protocolos de red, lo que permite un flujo de información bidireccional entre ambos.

El cliente es una aplicación informática o un ordenador que consume un servicio remoto en otro ordenador conocido como servidor, normalmente a través de una red de telecomunicaciones.

Un servidor es un conjunto de computadoras capaces de atender las peticiones de un cliente y devolverle una respuesta en concordancia, además, un servidor almacena y gestiona diversos recursos, que pueden incluir bases de datos, archivos y aplicaciones. La capacidad de procesamiento del servidor es crucial, ya que debe manejar múltiples peticiones simultáneamente y devolver respuestas de manera eficiente.

Una placa ESP32 se puede configurar en modo cliente para realizar solicitudes a un servidor que esté en la web, para esto se puede utilizar la biblioteca HttpClient del IDE de Arduino.

Protocolo HTTP

El Protocolo de Transferencia de Hipertexto (HTTP) es un protocolo de capa de aplicación para la transmisión de documentos, como HTML. Fue diseñado para la comunicación entre navegadores web y servidores web, pero también puede utilizarse para otros fines, como la comunicación máquina a máquina, el acceso a APIs, etc.

HTTP sigue un modelo clásico cliente-servidor: el cliente abre una conexión para realizar una solicitud y espera hasta recibir una respuesta del servidor. HTTP es un protocolo sin estado, lo que significa que el servidor no conserva datos de sesión entre dos solicitudes, aunque la posterior incorporación de cookies añade estado a algunas interacciones cliente-servidor.

Métodos de solicitud HTTP

HTTP define un conjunto de métodos de solicitud para indicar el propósito de la solicitud y qué se espera si esta se realiza correctamente. Aunque también pueden ser sustantivos, estos métodos de solicitud a veces se denominan verbos HTTP.

A continuación se describen los diferentes métodos HTTP.

  • GET: El método GET solicita una representación de un recurso específico. Las peticiones que usan el método GET sólo deben recuperar datos.
  • POST: El método POST se utiliza para enviar una entidad a un recurso en específico, causando a menudo un cambio en el estado o efectos secundarios en el servidor.
  • PUT: El modo PUT reemplaza todas las representaciones actuales del recurso de destino de acuerdo con la petición enviada.
  • DELETE: El método DELETE borra un recurso en específico.

La biblioteca Wi-Fi de Arduino

Esta biblioteca permite la conexión de red (local e Internet) mediante una placa de Arduino. Con esta biblioteca, se pueden instanciar servidores y clientes, y enviar y recibir paquetes UDP a través de WiFi. La placa de desarrollo puede conectarse a redes abiertas o cifradas (WEP, WPA). La dirección IP se puede asignar estáticamente o mediante DHCP.

La biblioteca HTTPClient de Arduino

Esta biblioteca permite realizar fácilmente solicitudes HTTP GET, POST y PUT desde Arduino a un servidor web.

JSON

JSON (JavaScript Object Notation) es un formato basado en texto para almacenar e intercambiar datos de una manera que es legible por humanos y analizable por máquina.

Ventajas:

  • JSON es utilizado a menudo por los desarrolladores web para transferir datos entre un servidor y una aplicación web.
  • La naturaleza independiente del lenguaje de JSON lo convierte en un formato ideal para intercambiar datos a través de diferentes lenguajes de programación y plataformas.

Apps Script 

Google Apps Script es un lenguaje de programación basado en JavaScript que permite ampliar las funcionalidades de las aplicaciones de Google, entre ellas, Google Sheets.

Desarrollo del proyecto

Diagrama de conexiones

La siguiente imagen muestra el diagrama de conexiones necesario para la implementación de este proyecto.


La placa de desarrollo utilizada ESP tiene 38 pines en este caso.

Código de programación para la placa

El código de programación necesario para la placa ESP32 se puede observar a continuación.

#include <HTTPClient.h>

#include <WiFi.h>

#define adcVrefmV 3300.0

#define resolucionADC 4096.0 // entrada analógica = 12 bits = rango de lectura 0-4095.

#define LM35 36 // El pin GPIO36 (ADC1_0) del ESP32 está conectado al LM35

int lecturaAnalogica = 0;

const char* ssid = "SSID";

const char* password = "Contrasenia_SSID";

const char* serverName = "URL_Google_Sheets";

float milliVolts;

float tempC;

float tempF;

unsigned long timeRead = 0;

void setup() {

  // put your setup code here, to run once:

  initWifi(); // Inicialización de Wi-fi

  Serial.begin(9600);

  analogSetAttenuation(ADC_11db);// Se establece la atenuación del      ADC a 11 dB (hasta una entrada de ~3,3 V)

}

void loop() {

  // put your main code here, to run repeatedly:

   if (millis() - timeRead > 2000) { // millis devuelve el número de    milisegundos transcurridos desde que la placa Arduino comenzó a       ejecutar el programa actual

    lecturaAnalogica = analogRead(LM35);

    milliVolts = lecturaAnalogica * (adcVrefmV / resolucionADC);

    tempC = milliVolts / 10;

    tempF = tempC * 9 / 5 + 32;

    Serial.print("Temperatura - ");

    Serial.print(tempC);

    Serial.write("\xC2\xB0");  // Simbolo de grado

    Serial.println("C");

    Serial.print(" - ");

    Serial.print(tempF);

    Serial.println("\xC2\xB0"); // Simbolo de grado

    Serial.println("F");

    enviarAGoogleSheets();

    timeRead = millis();

  }

}

void initWifi() {

  Serial.print("Conectando a: ");

  Serial.print(ssid);

  WiFi.begin(ssid, password); // Inicializa la configuración de red 

  int timeout = 10 * 4;  // Se configura un tiempo de 10 segundos de   conexión

  while (WiFi.status() != WL_CONNECTED && (timeout-- > 0)) {

    delay(250); // 250 milisegundos; 1 segundo = 1000 ms // se            necesita un total de 40 iteraciones de este ciclo while para        esperar la conexión Wi-Fi

    Serial.print(".");

  }

  Serial.println("");

  if (WiFi.status() != WL_CONNECTED) { // Si después de los 10             segundos no se realiza la conexión

    Serial.println("Ha fallado la conexión al Wi-Fi"); // entonces se     muestra un mensaje de fallo

  }

  Serial.print("WiFi conectado a la siguiente dirección IP: ");

  Serial.println(WiFi.localIP()); // se muestra la IP que tiene la      placa ESP32

}


void enviarAGoogleSheets() {

  if (WiFi.status() == WL_CONNECTED) { // Si la conexión Wi-Fi se        realizó correctamente

    HTTPClient http;

    http.begin(serverName); // Analiza una url a la cual se debe         conectar

    http.addHeader("Content-Type", "application/json"); // Se agrega     una cabecera para compartir información adicional entre el            cliente y el servidor, en este caso se indica que se va enviar        información en formato JSON

    String jsonData = "{\"tempC\":\"" + String(tempC) + "\",            \"tempF\":\"" + String(tempF) + "\"}"; // Cadena JSON a enviar al     servidor


    int httpResponseCode = http.POST(jsonData); //  Envía una            solicitud de tipo POST (realiza modificaciones en un recurso) al     servidor (Proyecto de Google Sheets)

    if (httpResponseCode > 0) {

      String response = http.getString(); // Se obtiene el conjunto       de los datos transmitidos útiles (excluyendo otros datos o          metadatos que son enviados para facilitar la entrega del              mensaje) em forma de cadena

      Serial.println(httpResponseCode);

      Serial.println(response); // Se imprime el conjunto de los         datos transmitidos útiles (respuesta del servidor)

    } else {

      Serial.print("Wrong request POST: ");

      Serial.println(httpResponseCode);

    }

    http.end(); // Cuando el conjunto de los datos transmitidos        útiles (carga útil) se ha obtenido, entonces esta función se debe     llamar.

  }

}

Código de programación para Google Sheets
El código de programación requerido para Apps Script (Google Sheets) se puede observar en seguida.

function doPost(e) { // doPost se ejecuta cuando un programa envía         una solicitud HTTP POST a una app web (Aplicación de Google         Sheets en este caso)
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); // Se muestra la hoja de cálculo activa actualmente y luego se obtiene     esa hoja que está activa
var data = JSON.parse(e.postData.contents); // Con parse() se       convierten los datos de la solicitud en un objeto de JavaScript,    primero se obtiene el texto del contenido en la solicitud POST       con e.postData.contents
sheet.appendRow([new Date(), data.tempC, data.tempF]); // Agrega    una nueva fila a la hoja de cálculo con los datos enviados       en la solicitud y la fecha actual
}

Pruebas de implementación
Las siguientes imagen muestran un fragmento del monitor serie de Arduino IDE y de una hoja de cálculo con las temperaturas (en grados Celsius y Fahrenheit) obtenidas por medio de la placa ESP32 y el sensor LM35.





Referencias