sábado, 11 de dezembro de 2010

Demo: DS1307

O DS1307 é um circuito integrado com um relógio (RTC) que fornece uma solução simples para circuitos que precisem marcar a passagem de tempo ou mostrar as horas. De baixíssimo consumo, permite manter a contagem do tempo mesmo com o circuito principal desligado através de uma bateria de backup. A comunicação com o circuito é feita através de I2C.

O único componente externo necessário é um cristal de 32.768kHz para o oscilador. Caso não consiga encontrá-lo à venda, ele existe em praticamente qualquer circuito que tenha um relógio, desde relógios de pulso baratos até placas-mãe de computadores. Não é difícil encontrá-los em sucata. O cristal deve ser soldado o mais próximo possível do circuito integrado, com o invólucro metálico eletricamente ligado ao terra.

O DS1307 também tem um pino de saída que fornece um sinal de onda quadrada ajustável para várias frequências. Pode ser útil no caso de um relógio, por exemplo, quando desejamos piscar um led a cada segundo.



#include <Wire.h>
// endereço I2C do DS1307
#define DS1307_I2C_ADDRESS 0x68

// cria as variáveis para armazenar os valores
// SS[0-60], MM[0-60], HH[0-24], D[1-7], DD[1-31], MM[1-12], YY[00-99]
byte second, minute, hour, dayweek, day, month, year; 

char buffer[50]; // buffer para armazenar entrada serial
 
 
void setup() {
  Wire.begin(); // inicializa interface I2C
  Serial.begin(9600); // inicializa serial
  
}

void loop() {
  if (Serial.available()) {
    fillBuffer();
    setDateDS1307();
  }
   
  getDateDS1307(); // pega a hora atual e armazena
  writeSerial(); // envia a hora pela serial

  delay(500);
} 
  
// converte binário para BCD
byte dec2bcd(byte val){
  return ((val/0xA*0x10)+(val%0xA));
}

// converte BCD para binário
byte bcd2dec(byte val){
  return ((val/0x10*0xA)+(val%0x10));
}

// converte dois dígitos ASCII da entrada em um único byte
byte digitToByte(int x,int y){
  return (byte) ((buffer[x]&0x0F)*10+(buffer[y]&0x0F));
}

// converte caracteres ASCII da entrada em um byte com o dia da semana
byte dayToByte(int x,int y, int z){
  int temp = buffer[x]+buffer[y]+buffer[z];
  switch(temp){
    case 0x12A: return (byte) 1; break; // Mon
    case 0x12E: return (byte) 2; break; // Tue
    case 0x120: return (byte) 3; break; // Wed
    case 0x131: return (byte) 4; break; // Thu
    case 0x121: return (byte) 5; break; // Fri
    case 0x128: return (byte) 6; break; // Sat
    case 0x136: return (byte) 7; break; // Sun
    default: return (byte) 0;
    }
}

// converte caracteres ASCII da entrada em um byte com o mês
byte monthToByte(int x,int y, int z){
  int temp = buffer[x]+buffer[y]+buffer[z];
  switch(temp){
    case 0x119: return (byte) 1; break; // Jan
    case 0x10D: return (byte) 2; break; // Feb
    case 0x120: return (byte) 3; break; // Mar
    case 0x123: return (byte) 4; break; // Apr
    case 0x127: return (byte) 5; break; // May
    case 0x12D: return (byte) 6; break; // Jun
    case 0x12B: return (byte) 7; break; // Jul
    case 0x11D: return (byte) 8; break; // Aug
    case 0x128: return (byte) 9; break; // Sep
    case 0x126: return (byte) 10; break; // Oct
    case 0x133: return (byte) 11; break; // Nov
    case 0x10C: return (byte) 12; break; // Dec
    default: return (byte) 0;
    }
}

// lê dados da serial para o buffer de entrada
void fillBuffer(){
  delay(500); 
  int ptr =0;
  buffer[ptr++]=Serial.read();
  while(Serial.available() > 0) {
    buffer[ptr++]=Serial.read();
    if(buffer[ptr]=='/n'){
      break;
    }
  }
} 

// acerta a hora do DS1307 usando como entrada um pipe do comando date.
// Sat Dec 11 12:04:12 BRST 2010
void setDateDS1307(){
   second=digitToByte(17,18);
   minute=digitToByte(14,15);
   hour=digitToByte(11,12);
   dayweek=dayToByte(0,1,2);
   day=digitToByte(8,9);
   month=monthToByte(4,5,6);
   year=digitToByte(27,28);
   
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   Wire.send(0x00);
   Wire.send(dec2bcd(second));
   Wire.send(dec2bcd(minute));
   Wire.send(dec2bcd(hour));
   Wire.send(dec2bcd(dayweek));
   Wire.send(dec2bcd(day));
   Wire.send(dec2bcd(month));
   Wire.send(dec2bcd(year));
   Wire.endTransmission();
}

// pega a data e hora do DS1307
void getDateDS1307(){
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0x00);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
  second=bcd2dec(Wire.receive() & 0x7f);
  minute=bcd2dec(Wire.receive());
  hour=bcd2dec(Wire.receive() & 0x3f);
  dayweek=bcd2dec(Wire.receive());
  day=bcd2dec(Wire.receive());
  month=bcd2dec(Wire.receive());
  year=bcd2dec(Wire.receive());
}


// envia a data e hora para a portal serial
void writeSerial(){
  Serial.print(hour, DEC);
  Serial.print(":");
  Serial.print(minute, DEC);
  Serial.print(":");
  Serial.print(second, DEC);
  Serial.print("  ");
  Serial.print(day, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  Serial.println();
}


Datasheet: http://pdfserv.maxim-ic.com/en/ds/DS1307.pdf