RTC Tiny com chip DS1307 e Arduino UNO

 

Um RTC (Real Time Clock) é um relógio de precisão dedicado a registro de data e hora, utilizado em projetos que necessitam acuidade de tempo. Apesar de parecer um dispositivo especial, trata-se de um acessório comum a praticamente todo o equipamento microprocessado como smartphones, tablets, computadores desktop, notebooks, máquinas fotográficas, filmadoras, etc.

Se você chegou até esse post, a sorte é minha e não sua, porque é muito simples e comum a utilização desse popular dispositivo e você encontra facilmente tutoriais com uma simples busca no google. Ainda assim, eu não poderia deixar de ter uma referência e vou tentar ter algum diferencial em relação aos demais posts para que valha a pena para você utilizar o meu tutorial invés de outros.

Tenha paciência com a leitura, é bom saber exatamente o que você tem em suas mãos.

Características

O DS1307 é um relógio dedicado que exibe segundos, minutos, horas, dia do mês, mês, dia da semana e ano, incluindo ano bi-sexto.

Além da sua função especialista, ele oferece ainda um espaço extra de 56 bytes de NVRAM (Non Volatile Randomic Access Memory), que é mantida pela bateria com praticamente nenhum consumo. É um recurso bastante interessante, pois se você precisa armazenar dados de tempo inclusive para registrar startup e shutdown, não será necessário esmirilhar a EEPROM do Arduino.

Ele possui uma interface serial two-wire e para utilizá-lo com Arduino, uma das bibliotecas a ser utilizada é a Wire.

Ele possui uma saída de sinal de onda quadrada programável, de 1Hz a 32.768kHz.

Seu consumo é incrivelmente baixo; menos de 500 nA (nano Ampere).

Descrição

Essas informações que disponibilizo estão no datasheet, sinta-se à vontade para lê-lo (em inglês).

Sua pinagem oferece cascata para comunicação I2C; endereço e dados são transferidos via 2-wire bidirecional. Seu ajuste para meses de 31 dias e anos bisexto são feitos automaticamente, portanto você não precisará se preocupar em monitorá-lo. Outra característica importante é que ele oferece o modo 24h ou 12h com indicador AM/PM. Ele tem um circuito sensitivo que detecta falhas de alimentação e entra automaticamente em modo de bateria, consumindo menos de 500nA.

Operação

Esse RTC é um dispositivo passivo, ou seja, ele recebe comandos via barramento serial. O protocolo de comunicação tem uma condição de START e se encerra na condição de STOP.

Pinagem

Wiring
Wiring

VCC e GND – são conectados ao Arduino em 5v e ground.

Vbat – o slot recebe uma bateria de lithium de 3v, que é considerada em boas condições de uso quando entre 2v e 3.5v. Em baixa tensão, não é possível utilizar a NVRAM. Uma bateria de 48mAh teoricamente dá ao dispositivo uma capacidade de trabalho superior a 10 anos, trabalhando a 25 graus.

SCL – Serial Clock. Utilizado para sincronismo na interface serial.

SDA – Serial Data I/O. Comunicaçãoda interface 2-wire.

Precisão do relógio
A precisão é dependente do cristal e variação de temperaturas. Ruídos de circuito externo à MCU podem acelerar o relógio, mas podemos considerar um circuito de qualidade esse do Tiny RTC.

Endereçamentos
memory-rtc

Não é algo que tenhamos que nos preocupar, uma vez que utilizaremos um interface de alto nível para a comunicação, mas se tiver interesse em saber a estrutura dos dados. O relógio está na área de endereço de 00H (segundos) ao 07H (controle). De 08H até 3FH está toda a memória.

Você pode obter de forma independente cada um dos valores dos registros de memória, consultando-os diretamente. Os dados são armazenados no formato BCD (binary-coded decimal). O bit 6 do registrador de hora define o forma 12/24 (lembrando que cada registrador possui 8 bits).

Só descrevi alguns detalhes extras para se ter uma idéia de como o hardware funciona e de que não é trivial a comunicação, por isso as bibliotecas são muito bem-vindas.

RTCLib x DS1307new

Optei por utilizar a DS1307new porque apesar da suave diferença, me pareceu mais flexível para fazer uma função de ajuste do relógio a qualquer momento. Não vi algo do tipo em nenhum tutorial, então achei um diferencial legal, espero que goste tambem.

Criei a função de ajuste de relógio e um menu para exibir hora, data, data/hora e fazer o tal ajuste. Para ver o menu, apenas digite “ajuda” (sem aspas).

A biblioteca pode ser baixada nesse link. O código que utilizei já nesse primeiro momento no Arduino:

#include <Wire.h>
#include <DS1307new.h>
#include <string.h>

//dias da semana
#define SUNDAY    0
#define MONDAY    1
#define TUESDAY   2
#define WEDNESDAY 3
#define THURSDAY  4
#define FRIDAY    5
#define SATURDAY  6

uint16_t TimeIsSet = 0xaa55; 
uint16_t startAddr = 0x0000;           
uint16_t lastAddr;                      

DS1307new rtc;
/* 
 *  https://www.dobitaobyte.com.br
 */

String adjustment; //string para fazer os ajustes do relogio
char option = 0;
void getRequired(String thisValue){
    if (thisValue.equals("ajudan")){
        Serial.println("Opcoes:");
        Serial.println("ajuda    - Este menu");
        Serial.println("ajustar  - Ajuste da data e hora");
        Serial.println("dataHora - Exibe data e hora");
        Serial.println("data     - Exibe apenas data");
        Serial.println("hora     - Exibe apenas horario");
        return;
    }
    rtc.getTime();
    if (thisValue.equals("horan")){
        //Serial.println(rtc.time2000,DEC);
        adjustment = String(rtc.hour) + ":" + String(rtc.minute) + ":" + String(rtc.second);
        Serial.print("Hora: ");
        Serial.println(adjustment);
    }
    else if (thisValue.equals("dataHoran")){
        Serial.print("Data e Hora: ");
        adjustment  = String(rtc.day) + "/" + String(rtc.month) + "/" + String(rtc.year-48); //data...
        adjustment += " - " + String(rtc.hour) + ":" + String(rtc.minute) + ":" + String(rtc.second); //...e hora
        Serial.println(adjustment);
    }
    else if(thisValue.equals("datan")){
        adjustment  = String(rtc.day) + "/" + String(rtc.month) + "/" + String(rtc.year-48); 
        Serial.print("Data: ");
        Serial.println(adjustment);
    }
    else{
        Serial.println("Digite 'ajuda' se tiver duvidas");
    }
}

void clockAdjustment(){
    TimeIsSet = 0xffff; 
    rtc.setRAM(54, (uint8_t *)&TimeIsSet, sizeof(uint16_t));

    rtc.getRAM(54, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
    if (TimeIsSet == 0xaa55){    
         Serial.println("Impossivel configurar: 0xaa55");
         return;
    }
    rtc.stopClock();
    
    char inChar = 0;
    adjustment = "";

    Serial.println("");
    Serial.print("Defina o horario (HH:MM:SS (nesse formato)): ");
    while (inChar != 'n'){
      if (Serial.available()){
        inChar = Serial.read();
        adjustment += inChar;
      }
    }
    rtc.hour   = adjustment.substring(0,2).toInt(); //0 e 1. 
    rtc.minute = adjustment.substring(3,5).toInt(); //3 e 4.
    rtc.second = adjustment.substring(7).toInt();   //7 e 8.
    adjustment =  "";
    
    Serial.println(" ");
    Serial.print("Entre com a data no formato DD/MM/AAAA (nesse formato):");
    inChar = 0;
    while (inChar != 'n'){
      if (Serial.available()){
        inChar = Serial.read();
        adjustment += inChar;
      }
    }
    rtc.day    = adjustment.substring(0,2).toInt();
    rtc.month  = adjustment.substring(3,5).toInt();
    rtc.year   = adjustment.substring(7).toInt(); //7 ao fim

    adjustment = "";

    rtc.fillByYMD(rtc.year,rtc.month,rtc.day);
    rtc.fillByHMS(rtc.hour,rtc.minute,rtc.second); //redundante, se vc ler a lib...but
    //rtc.fillByYMD(2015,11,18);
    //rtc.fillByHMS(3,25,0);
    rtc.setTime();
    TimeIsSet = 0xaa55;
    rtc.setRAM(54, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
    rtc.startClock();
    rtc.ctrl = 0x00; //SQW pode ser usado como interrupcao
    rtc.setCTRL();
    
    Serial.println("");
    if (TimeIsSet == 0xaa55){
        Serial.println("Configurado.");
        asm volatile("  jmp 0"); //reset automatico
    }
    Serial.println("Nao configurado");
}

void setup() {
  pinMode(2, INPUT);                   
  digitalWrite(2, HIGH); 
  Serial.begin(9600);
}

void loop() {
  while (option != 'n'){
      if (Serial.available()){
          option      = Serial.read();
          adjustment += option;
      }
  }
  option = 0;
  if (adjustment.equals("ajustarn")){
    clockAdjustment();
  }
  else if (adjustment.equals("horan")|| adjustment.equals("dataHoran")|| adjustment.equals("datan") || adjustment.equals("ajudan")){
    getRequired(adjustment);
  }
  adjustment = "";
}

 

Menu de Opções
Menu de Opções

O terminal serial precisa estar com a opção newline selecionada porque 0x0D (ou “LF” (Line Feed), ou ‘n’) está sendo usado como delimitador na leitura serial.

Resta uma etapa; utilizar essa memoria sobressalente do RTC, que além de tudo é NVRAM e pode ser escrita à vontade. Mas essa deixarei para um próximo post porque preciso escrever mais dois que estão na fila.

Se gostou, acompanhe-nos no Do bit Ao Byte no facebook e até o próximo!

Deixe uma resposta