La inicialización del bus I2C la podemos encapsular dentro de una clase estática:
#include "I2C.h" #include <stdint.h> #include <avr/io.h> using namespace avelino; using namespace std; void I2C::init() { TWSR = 0x00; // TWBR = 12; // 400KHz TWBR = 72; // 100KHz TWCR = (1 << TWEN); } void I2C::start() { TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); while ((TWCR & (1 << TWINT)) == 0) ; } void I2C::stop() { TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN); } void I2C::write(uint8_t v) { TWDR = v; TWCR = (1 << TWINT) | (1 << TWEN); while ((TWCR & (1<<TWINT)) == 0) ; } uint8_t I2C::readACK() { TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA); while ((TWCR & (1 << TWINT)) == 0) ; return TWDR; } uint8_t I2C::readNACK() { TWCR = (1 << TWINT) | (1 << TWEN); while ((TWCR & (1 << TWINT)) == 0) ; return TWDR; } uint8_t I2C::getStatus() { return (TWSR & 0xF8); }
En este caso configuramos la velocidad I2C a 100KHz ya que es la velocidad a la que trabaja el chip RTC DS1307.
A continuación podemos definir otra clase estática para acceder al RTC:
#include "RTC.h" #include "I2C.h" using namespace avelino; using namespace std; void RTC::init() { I2C::init(); // read halt bit I2C::start(); I2C::write(0xD0); I2C::write(0x00); I2C::start(); I2C::write(0xD1); uint8_t v = I2C::readNACK(); I2C::stop(); if ((v & 0x80) != 0) { // clock is disabled, enabling I2C::start(); I2C::write(0xD0); I2C::write(0x00); I2C::write(v & 0x7F); I2C::stop(); } } void RTC::read(uint8_t &hour, uint8_t &minute, uint8_t &second) { I2C::start(); I2C::write(0xD0); I2C::write(0x00); I2C::start(); I2C::write(0xD1); second = I2C::readACK(); minute = I2C::readACK(); hour = I2C::readNACK(); I2C::stop(); }
El método init, tras inicializar el bus I2C, consulta la dirección de memoria 0 del RTC que, además del secundero del reloj, también almacena el halt bit (bit 7). Este bit se encuentra a 1 de fábrica y debe ser puesto a 0 para que el RTC arranque. En el if se comprueba si este bit está a 1, si es así, se pone a 0.
Por ahora no nos estamos preocupando de la hora real. Cuando el DS1307 se activa comienza a contar como si fuesen las 0:00 horas de 1 de enero de 2000.
A continuación, para ver que el RTC funciona bien, podemos hacer un sencillo programa que cambie el estado del led de la placa Arduino por cada segundo que pasa:
#include <stdint.h> #include "Led.h" #include "RTC.h" using namespace avelino; using namespace std; uint8_t hour, minute, second, prevSecond; int main() { RTC::init(); Led::init(); while (1) { RTC::read(hour, minute, second); if (second != prevSecond) { Led::change(); prevSecond = second; } } }
Voilà, ya tenemos nuestro microcontrolador conectado al reloj de tiempo real.
Lo sentimos. No se permiten nuevos comentarios después de 90 días.