Chisme 142 · El reloj maestro del casco del Lince: RTC DS1302

Practica aquí antes de tocar la placa. Vas a conectar un reloj de tiempo real (RTC) DS1302 a la ESP32 Plus, ponerlo en hora, comprobar qué le pasa si se corta la corriente con y sin pila, medir cuánto se desvía y completar el programa que lo lee. Cada paso se desbloquea al completar el anterior.

Prototipo educativo. El simulador usa tu propio reloj como «hora del ordenador» y una deriva configurable; la de tu módulo real puede ser distinta.

El casco y su reloj

--:--:-- --/--/----

Monitor serie
cables sin conectar

1Conecta los cables

El módulo reloj tiene cinco pines. Lee los rótulos de la placa: VCC, GND, CLK, DAT (o I/O) y RST (o CE). Hazlo con el USB desenchufado y con la pila puesta en el módulo.

Reloj · VCC → pin
Reloj · GND → pin
Reloj · CLK → pin
Reloj · DAT → pin
Reloj · RST → pin

2Qué es un reloj de tiempo real

3Ponlo en hora y ponlo a prueba

Usa los botones de arriba, en este orden: 1) pulsa Ajustar con la hora del ordenador; 2) con la pila puesta, pulsa Quitar el USB 1 minuto; 3) cambia a sin pila y repite; 4) vuelve a poner la pila, ajusta la hora otra vez y pulsa Avanzar 30 días.

PruebaResultadoHecha
Ajustar la hora—no
Cortar el USB con pila—no
Cortar el USB sin pila—no
Avanzar 30 días—no

4Completa el programa

El programa lee los registros del chip, que guardan los números en BCD (cada cifra decimal en 4 bits). Completa las líneas importantes:

5Piensa como un científico

Lee y predice

La hora del reloj sale 12:35:59 y 1 segundo después sale 12:36:00. ¿Qué ocurre en los registros?Los segundos pasan de 0x59 a 0x00 y los minutos de 0x35 a 0x36. Como están en BCD, 0x59 significa «cincuenta y nueve» y no 89.
El reloj dice RELOJ PARADO al arrancar. ¿Qué ha pasado?El bit 7 del registro de segundos (CH) está a 1: el chip no cuenta. Pasa con una pila nueva o tras quedarse sin ella. Poniendo la hora, el chip arranca.
Pones la hora una vez y 3 meses después va 2 minutos adelantado. ¿Es un fallo?No necesariamente: es la deriva normal de un cristal barato, que además cambia con la temperatura. Por eso se vuelve a ajustar cada cierto tiempo.
El programa completo en Arduino (sin librerías)
// Chisme 142 - Prueba del reloj DS1302 con la ESP32 Plus de Acebott
// Sin librerias: hablamos con el chip "a mano" (protocolo de 3 hilos).
// Placa en Arduino IDE: ESP32 Dev Module. Monitor serie a 115200.

const int PIN_CLK = 14;   // CLK (reloj de la comunicacion)
const int PIN_DAT = 13;   // DAT / I/O (datos, entra y sale por aqui)
const int PIN_RST = 25;   // RST / CE (activa el chip)

// Pon true SOLO la primera vez: ajusta la hora del chip con la hora del ordenador
// en el momento de compilar. Despues ponlo en false y vuelve a subir el programa:
// el chip mantiene la hora gracias a su pila.
const bool PONER_HORA = true;

byte aBCD(int v)  { return ((v / 10) << 4) | (v % 10); }
int  deBCD(byte b) { return ((b >> 4) * 10) + (b & 0x0F); }

byte leerRegistro(byte reg) {
  byte cmd = 0x81 | (reg << 1);          // orden de LECTURA del registro
  byte v = 0;
  digitalWrite(PIN_RST, HIGH); delayMicroseconds(4);
  pinMode(PIN_DAT, OUTPUT);
  for (int i = 0; i < 8; i++) {          // enviamos la orden, bit a bit (el bit 0 primero)
    digitalWrite(PIN_DAT, (cmd >> i) & 1);
    digitalWrite(PIN_CLK, HIGH); delayMicroseconds(2);
    if (i == 7) pinMode(PIN_DAT, INPUT); // ahora el chip es quien habla
    digitalWrite(PIN_CLK, LOW);  delayMicroseconds(2);
  }
  for (int i = 0; i < 8; i++) {          // recibimos el dato, bit a bit
    if (digitalRead(PIN_DAT)) v |= (1 << i);
    digitalWrite(PIN_CLK, HIGH); delayMicroseconds(2);
    digitalWrite(PIN_CLK, LOW);  delayMicroseconds(2);
  }
  digitalWrite(PIN_RST, LOW); delayMicroseconds(4);
  return v;
}

void escribirRegistro(byte reg, byte valor) {
  byte cmd = 0x80 | (reg << 1);          // orden de ESCRITURA del registro
  digitalWrite(PIN_RST, HIGH); delayMicroseconds(4);
  pinMode(PIN_DAT, OUTPUT);
  for (int i = 0; i < 8; i++) {
    digitalWrite(PIN_DAT, (cmd >> i) & 1);
    digitalWrite(PIN_CLK, HIGH); delayMicroseconds(2);
    digitalWrite(PIN_CLK, LOW);  delayMicroseconds(2);
  }
  for (int i = 0; i < 8; i++) {
    digitalWrite(PIN_DAT, (valor >> i) & 1);
    digitalWrite(PIN_CLK, HIGH); delayMicroseconds(2);
    digitalWrite(PIN_CLK, LOW);  delayMicroseconds(2);
  }
  digitalWrite(PIN_RST, LOW); delayMicroseconds(4);
}

void ponerHoraDelOrdenador() {
  // __TIME__ es "HH:MM:SS" y __DATE__ es "Oct 22 2026" (el momento de compilar)
  int h = (__TIME__[0] - '0') * 10 + (__TIME__[1] - '0');
  int mi = (__TIME__[3] - '0') * 10 + (__TIME__[4] - '0');
  int s = (__TIME__[6] - '0') * 10 + (__TIME__[7] - '0');
  char mm[4] = { __DATE__[0], __DATE__[1], __DATE__[2], 0 };
  const char* meses = "JanFebMarAprMayJunJulAugSepOctNovDec";
  int mes = (strstr(meses, mm) - meses) / 3 + 1;
  int dia = (__DATE__[4] == ' ' ? 0 : __DATE__[4] - '0') * 10 + (__DATE__[5] - '0');
  int anio = (__DATE__[9] - '0') * 10 + (__DATE__[10] - '0');   // solo las dos ultimas cifras

  escribirRegistro(7, 0x00);             // quitamos la proteccion contra escritura
  escribirRegistro(1, aBCD(mi));
  escribirRegistro(2, aBCD(h));          // formato de 24 horas
  escribirRegistro(3, aBCD(dia));
  escribirRegistro(4, aBCD(mes));
  escribirRegistro(5, 1);                // dia de la semana (no lo usamos)
  escribirRegistro(6, aBCD(anio));
  escribirRegistro(0, aBCD(s));          // segundos al final: pone el reloj en marcha
}

void setup() {
  Serial.begin(115200);
  pinMode(PIN_CLK, OUTPUT); digitalWrite(PIN_CLK, LOW);
  pinMode(PIN_RST, OUTPUT); digitalWrite(PIN_RST, LOW);
  pinMode(PIN_DAT, INPUT);
  delay(500);
  if (PONER_HORA) {
    ponerHoraDelOrdenador();
    Serial.println("Hora ajustada con la del ordenador");
  }
}

void loop() {
  byte rs = leerRegistro(0);             // segundos (el bit 7 = reloj parado)
  byte seg = deBCD(rs & 0x7F);
  byte mi  = deBCD(leerRegistro(1));
  byte h   = deBCD(leerRegistro(2) & 0x3F);
  byte dia = deBCD(leerRegistro(3));
  byte mes = deBCD(leerRegistro(4));
  byte an  = deBCD(leerRegistro(6));

  Serial.print("H:");
  if (h < 10) Serial.print('0');   Serial.print(h);   Serial.print(':');
  if (mi < 10) Serial.print('0');  Serial.print(mi);  Serial.print(':');
  if (seg < 10) Serial.print('0'); Serial.print(seg);
  Serial.print("  F:");
  Serial.print(dia); Serial.print('/'); Serial.print(mes); Serial.print("/20"); Serial.print(an);
  Serial.print("  segundos(raw)=0x"); Serial.print(rs, HEX);
  if (rs & 0x80) Serial.print("  RELOJ PARADO");
  Serial.println();
  delay(1000);
}

Placa ESP32 Plus de Acebott, programada con Arduino IDE (ESP32 Dev Module). Módulo: kit avanzado de robótica.