Conectar un reloj de tiempo real al microcontrolador AVR 
Los microcontroladores AVR poseen una interface de bus I2C que permite conectarlos a EEPROMs, RTCs, DACs y muchos otros periféricos. El bus I2C es un estándar ampliamente utilizado para la interconexión de dispositivos a bajo nivel y en este post analizaré cómo conectar un microcontrolador AVR (presentes en la familia Arduino) con un chip RTC (Real Time Clock) utilizando este bus I2C.



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.



[ añadir comentario ] ( 1345 visualizaciones )   |  [ 0 trackbacks ]   |  enlace permanente  |   ( 3 / 1706 )

<< <Anterior | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Siguiente> >>