MeteoDuino

Modulo RTC

Per poter sincronizzarsi con un contatore più preciso ecco che viene in aiuto il modulo RTC.

Ma cosa vuol dire RTC?

Wikipedia da questa spiegazione che è sufficiente al nostro scopo:

Un real-time clock (RTC), orologio in tempo reale, è un dispositivo con funzione di orologio, solitamente costituito da un processore a circuito integrato specializzato per questa funzione, il quale conteggia il tempo reale (anno, mese, giorno, ore, minuti e secondi) anche quando l'utilizzatore viene spento.[1] Viene usato in molti tipi di computer ed è presente in tutti i moderni PC.

Quello che si può trovare in commercio si presenta nella seguente forma:

Tiny-RTC-I2C-DS1307-Real-Time-Clock-Module-ARM-PIC-for-Arduino-1 10-89Tiny-RTC-I2C-DS1307-Real-Time-Clock-Module-ARM-PIC-for-Arduino-1 10-more-3

Girando nel web se ne possono vedere di vari tipi.

Lo schema di collegamento è il seguente:

rtc

Notiamo che comunica anche lui con il protocollo I2C come il sensore di pressione quindi non c'è cosa più semplice del suo collegamento tramite SCL e SDA nei rispettivi ingrassi analogici 5 e 4.

Ho usato questo sketch preso dagli esempi della libreria RTClib.h per imparare ad usarlo:

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib

#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 RTC;

 

void setup () {
  Serial.begin(57600);
  Wire.begin();
  RTC.begin();

  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
}

 

void loop () {

  DateTime now = RTC.now();

  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(' ');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();

  Serial.print(" since midnight 1/1/1970 = ");
  Serial.print(now.unixtime());
  Serial.print("s = ");
  Serial.print(now.unixtime() / 86400L);
  Serial.println("d");

  // calculate a date which is 7 days and 30 seconds into the future
  DateTime future (now.unixtime() + 7 * 86400L + 30);

  Serial.print(" now + 7d + 30s: ");
  Serial.print(future.year(), DEC);
  Serial.print('/');
  Serial.print(future.month(), DEC);
  Serial.print('/');
  Serial.print(future.day(), DEC);
  Serial.print(' ');
  Serial.print(future.hour(), DEC);
  Serial.print(':');
  Serial.print(future.minute(), DEC);
  Serial.print(':');
  Serial.print(future.second(), DEC);
  Serial.println();

  Serial.println();
  delay(3000);
}

Se vogliamo poi regolare solamente l'ora basterà caricare questo sketch e farlo girare una volta solamente per poi ricaricare un altro sketch:

 

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib

#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 RTC;

void setup () {
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  // following line sets the RTC to the date & time this sketch was compiled
  RTC.adjust(DateTime(__DATE__, __TIME__));

}

void loop () {

}

Mi sono accorto però che anche questo non tiene un orario costante. Sbaglia di qualche secondo nel giro della giornata. Così allora ho cercato un modo per farlo sincronizzare in automatico con i server che stabiliscono l'ora RTC. Per fare questo è necessaria una Ethernet Shield.
Di server ce ne sono vari. Ne ho presi 4 tra quelli proposti dal web:

 

#include <Wire.h>
#include "RTClib.h"
#include <Ethernet.h> //LIBRERIA PER ETHERNET SHIELD
#include <EthernetUdp.h> //LIBRERIA PER COMUNICAZIONE UDP
#include <SPI.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x4D, 0xAF}; // Mac address shield Ethernet, si trova su di un adesivo sotto lo shield
byte ip[] = { 192, 168, 1, 1 };

RTC_DS1307 RTC;

// IMPOSTAZIONI PER LETTURA ORA DA NTP
unsigned int LocalPort = 8888; // local port to listen for UDP packets

//IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov NTP server
//IPAddress timeServer(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov NTP server
//IPAddress timeServer(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov NTP server
IPAddress timeServer(194, 116, 87, 4); // 0.it.pool.ntp.org

//se il server non funziona momentaneamente è necessario cambiarlo


const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
EthernetClient client; //dichiaro una variabile globale per il client ethernet

void setup () {
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();

  Serial.println("Configuro la connessione con DHCP..."); // start the Ethernet connection
  Ethernet.begin(mac,ip);
  Serial.println("Connessione Configurata.");

}

void loop () {
  delay(10000);
  DateTime now = RTC.now();
  RTC.adjust(RegOra());
  data(); //stampa attraverso la seriale l'ora attuale per verificare la lettura dei dati
  delay (10000);
}

E le funzioni richiamate sono:

 

unsigned long RegOra(){ //REGOLAZIONE AUTOMATICA ORA RTC
  Udp.begin(LocalPort);
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  unsigned long epoch;
  // wait to see if a reply is available
  delay(1000);
  if ( Udp.parsePacket() ) {
    // We've received a packet, read the data from it
    Udp.read(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer
    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    //Serial.print("Seconds since Jan 1 1900 = " );
    //Serial.println(secsSince1900);
    // now convert NTP time into everyday time:
    //Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    epoch = secsSince1900 - seventyYears;// + 1; //aggiunto 1 per ritardo in sincronizzazione
    // print Unix time: from 2000
    //Serial.println(epoch);

    // print the hour, minute and second:
    Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
    Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
    Serial.print(':');
    if ( ((epoch % 3600) / 60) < 10 )
      Serial.print('0'); // In the first 10 minutes of each hour, we'll want a leading '0'

    Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
    Serial.print(':');
    if ( (epoch % 60) < 10 )
      Serial.print('0'); // In the first 10 seconds of each minute, we'll want a leading '0'

    Serial.println(epoch %60); // print the second
  }
  return(epoch);
}

 

 

void data(){

DateTime now = RTC.now();
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
Serial.println();

/*Serial.print(" since 1970 = ");
Serial.print(now.unixtime());
Serial.print("s = ");
Serial.print(now.unixtime() / 86400L);
Serial.println("d");
Serial.println();*/
}

 

 

// send an NTP request to the time server at the given address

unsigned long sendNTPpacket(IPAddress& address) {
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011; // LI, Version, Mode
  packetBuffer[1] = 0; // Stratum, or type of clock
  packetBuffer[2] = 6; // Polling Interval
  packetBuffer[3] = 0xEC; // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket();
}

 

La rete è stata di aiuto per fare questo anche se non è stato facile trovare le informazioni necessarie per implementare questo codice.