15 dicembre 2012

Orologio con Arduino e il DS1307

Orologio con DS1307


Questo progetto prevede la realizzazione di un orologio/datario, con la possibilità di impostare data e ora tramite 3 pulsanti (SET, +, -).

Il materiale occorrente per questo progetto è:
  • Modulo DS1307 (RTC Real time Clock)
  • Display LCD 16X2 tipo Displaytech 162B
  • 3 pulsanti 
  • 3 resistenze da 10Kohm 1/4w
  • 1 potenziometro da 10Kohm lineare
  • Arduino UNO
Descrizione dell'esperimento:

Vogliamo che Arduino  mostri data e ora, ma dobbiamo avere anche la possibilità di impostarle correttamente, perché riprogrammare ogni volta Arduino non è proprio il massimo della comodità.
 
Quindi è stato previsto che normalmente Arduino visualizzi sul display la data sulla prima riga e l'ora sulla seconda riga del display. Alla pressione del tasto SET entrerà nella fase di settaggio della data e ora. 

Più precisamente:

Con la pressione del tasto SET entreremo nell'impostazione dell'ora, con i tasti + e - incrementeremo o decrementeremo l'ora attuale. Con una nuova pressione del tasto SET andremo ad impostare i minuti, un'altra pressione per l'anno, poi il mese e il giorno. 
Alla fine si effettuerà il salvataggio delle impostazioni.

Per realizzare lo sketch, è necessario scaricare e installare nella cartella delle librerie di arduino, la libreria RTClib che potete trovare a questo indirizzo:

Nota: Per il momento esistono alcuni "bug" per quanto riguarda il settaggio dei giorni del mese (di default il programma pensa che siano di 31 giorni anche se è febbraio....) 

Lo sketch:

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


// inizializza la libreria con i Pin LCD
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
RTC_DS1307 RTC;
int P1=6;
int P2=7;
int P3=8;
int oraagg;
int minagg;
int annoagg;
int meseagg;
int dayagg;
int menu =0;

void setup()
{
  // Quante colonne e righe ha il display: 
  lcd.begin(16, 2);
  lcd.clear();
  // Inizializzazione dei pulsanti
  pinMode(P1,INPUT);
  pinMode(P2,INPUT);
  pinMode(P3,INPUT);
  //inizializzo la libreria
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  //RTC.sqw(1); 
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // settiamo la data e l'ora al momento della compilazione
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
    // di default il display visualizzerà data e ora
  int menu=0;
}
 
void loop()
// verifichiamo se viene premuto il pulsante SET e incrementiamo l'indice del menu
  if(digitalRead(P1))
  {
   menu=menu+1;
  }
// a quale subroutine dobbiamo andare?
  if (menu==0)
  {
    DisplayDateTime();
    delay (1000);
  }
  if (menu==1)
  {
    DisplaySetHour();
  }
  if (menu==2)
  {
    DisplaySetMinute();
  }
  if (menu==3)
  {
    DisplaySetYear();
  }
  if (menu==4)
  {
    DisplaySetMonth();
  }
  if (menu==5)
  {
    DisplaySetDay();
  }
  if (menu==6)
  {
    StoreAgg(); 
    delay(500);
    menu=0;
  }
  delay(100);
}

void DisplayDateTime ()
{
// mostriamo la data e l'ora correnti
  DateTime now = RTC.now();
  lcd.clear();
  lcd.setCursor(0, 1);
  lcd.print("Ora:");
  if (now.hour()<=9)
  {
    lcd.print("0");
  }
  lcd.print(now.hour(), DEC);
  oraagg=now.hour();
  lcd.print(":");
  if (now.minute()<=9)
  {
    lcd.print("0");
  }
  lcd.print(now.minute(), DEC);
  minagg=now.minute();
  lcd.print(":");
  if (now.second()<=9)
  {
    lcd.print("0");
  }
  lcd.print(now.second(), DEC);

  lcd.setCursor(0, 0);
  lcd.print("Data: ");
  if (now.day()<=9)
  {
    lcd.print("0");
  }
  lcd.print(now.day(), DEC);
  dayagg=now.day();
  lcd.print("/");
  if (now.month()<=9)
  {
    lcd.print("0");
  }
  lcd.print(now.month(), DEC);
  meseagg=now.month();
  lcd.print("/");
  lcd.print(now.year(), DEC);
  annoagg=now.year();
}

void DisplaySetHour()
{
// Impostazione dell'ora
  lcd.clear();
  DateTime now = RTC.now();
  int ora=now.hour();
  if(digitalRead(P2)==HIGH)
  {
    if(oraagg==23)
    {
      oraagg=0;
    }
    else
    {
      oraagg=oraagg+1;
    }
  }
   if(digitalRead(P3)==HIGH)
  {
    if(oraagg==0)
    {
      oraagg=23;
    }
    else
    {
      oraagg=oraagg-1;
    }
  }
  lcd.setCursor(0,0);
  lcd.print("Imposta Ora:");
  lcd.setCursor(0,1);
  lcd.print(oraagg,DEC);
  delay(200);
}

void DisplaySetMinute()
{
// Impostazione dei minuti
  lcd.clear();
  if(digitalRead(P2)==HIGH)
  {
    if (minagg==59)
    {
      minagg=0;
    }
    else
    {
      minagg=minagg+1;
    }
  }
   if(digitalRead(P3)==HIGH)
  {
    if (minagg==0)
    {
      minagg=59;
    }
    else
    {
      minagg=minagg-1;
    }
  }
  lcd.setCursor(0,0);
  lcd.print("Imposta Minuti:");
  lcd.setCursor(0,1);
  lcd.print(minagg,DEC);
  delay(200);
}
  
void DisplaySetYear()
{
// Impostazione dell'anno
  lcd.clear();
  if(digitalRead(P2)==HIGH)
  {    
    annoagg=annoagg+1;
  }
   if(digitalRead(P3)==HIGH)
  {
    annoagg=annoagg-1;
  }
  lcd.setCursor(0,0);
  lcd.print("Imposta Anno:");
  lcd.setCursor(0,1);
  lcd.print(annoagg,DEC);
  delay(200);
}

void DisplaySetMonth()
{
// Impostazione del mese
  lcd.clear();
  if(digitalRead(P2)==HIGH)
  {
    if (meseagg==12)
    {
      meseagg=1;
    }
    else
    {
      meseagg=meseagg+1;
    }
  }
   if(digitalRead(P3)==HIGH)
  {
    if (meseagg==12)
    {
      meseagg=12;
    }
    else
    {
      meseagg=meseagg-1;
    }
  }
  lcd.setCursor(0,0);
  lcd.print("Imposta Mese:");
  lcd.setCursor(0,1);
  lcd.print(meseagg,DEC);
  delay(200);
}

void DisplaySetDay()
{
// Impostazione del giorno
  lcd.clear();
  if(digitalRead(P2)==HIGH)
  {
    if (dayagg==31)
    {
      dayagg=1;
    }
    else
    {
      dayagg=dayagg+1;
    }
  }
   if(digitalRead(P3)==HIGH)
  {
    if (dayagg==1)
    {
      dayagg=31;
    }
    else
    {
      dayagg=dayagg-1;
    }
  }
  lcd.setCursor(0,0);
  lcd.print("Imposta Giorno:");
  lcd.setCursor(0,1);
  lcd.print(dayagg,DEC);
  delay(200);
}

void StoreAgg()
{
// Salvataggio delle variabili
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("SALVATAGGIO IN");
  lcd.setCursor(0,1);
  lcd.print("CORSO");
  RTC.adjust(DateTime(annoagg,meseagg,dayagg,oraagg,minagg,0));
  delay(200);
}

Lo schema:

9 commenti:

  1. tanto di cappello al realizzatore dello sketch.
    ho apportato una mia modifica da neofita per il corretto aggiornamento dei giorni nei vari mesi, di seguito la parte di codice da modificare:
    void DisplaySetDay()
    {
    lcd.clear();
    if (digitalRead(P2) == HIGH)
    {
    if (meseagg == 2 && dayagg == 28)
    {
    dayagg = 1;
    }
    if ((meseagg == 4 && dayagg == 30)|| (meseagg == 6 && dayagg == 30) || (meseagg == 9 && dayagg == 30) || (meseagg == 11 && dayagg == 30))
    {
    dayagg = 1;
    }
    if ((meseagg == 1 && dayagg == 31) || (meseagg == 3 && dayagg == 31) || (meseagg == 5 && dayagg == 31) || (meseagg == 7 && dayagg == 31) || (meseagg == 8 && dayagg == 31) || (meseagg == 10 && dayagg == 31) || (meseagg == 12 && dayagg == 31))
    {
    dayagg = 1;
    }
    else
    { tone (pinbip, freq), delay(150), noTone(12),
    dayagg = dayagg + 1;
    }
    }
    if (digitalRead(P3) == HIGH)
    {
    if (meseagg == 2 && dayagg == 1)
    {
    dayagg = 28;
    }
    if ((meseagg == 4 && dayagg == 1)|| (meseagg == 6 && dayagg == 1) || (meseagg == 9 && dayagg == 1) || (meseagg == 11 && dayagg == 1))
    {
    dayagg = 30;
    }
    if ((meseagg == 1 && dayagg == 1) || (meseagg == 3 && dayagg == 1) || (meseagg == 5 && dayagg == 1) || (meseagg == 7 && dayagg == 1) || (meseagg == 8 && dayagg == 1) || (meseagg == 10 && dayagg == 1) || (meseagg == 12 && dayagg == 1))
    {
    dayagg = 31;
    }
    else
    { tone (pinbip, freq), delay(150), noTone(12),
    dayagg = dayagg - 1;
    }
    }
    lcd.setCursor(0, 0);
    lcd.print("Imposta Giorno:");
    lcd.setCursor(0, 1);
    lcd.print(dayagg, DEC);
    delay(200);
    }

    RispondiElimina
    Risposte
    1. chiedo scusa, ho visto solo ora che avevo implementato il bip nel mio sketch, a seguire la parte di codice ricorretta senza bip:


      void DisplaySetDay()
      {
      lcd.clear();
      if (digitalRead(P2) == HIGH)
      {
      if (meseagg == 2 && dayagg == 28)
      {
      dayagg = 1;
      }
      if ((meseagg == 4 && dayagg == 30)|| (meseagg == 6 && dayagg == 30) || (meseagg == 9 && dayagg == 30) || (meseagg == 11 && dayagg == 30))
      {
      dayagg = 1;
      }
      if ((meseagg == 1 && dayagg == 31) || (meseagg == 3 && dayagg == 31) || (meseagg == 5 && dayagg == 31) || (meseagg == 7 && dayagg == 31) || (meseagg == 8 && dayagg == 31) || (meseagg == 10 && dayagg == 31) || (meseagg == 12 && dayagg == 31))
      {
      dayagg = 1;
      }
      else
      {
      dayagg = dayagg + 1;
      }
      }
      if (digitalRead(P3) == HIGH)
      {
      if (meseagg == 2 && dayagg == 1)
      {
      dayagg = 28;
      }
      if ((meseagg == 4 && dayagg == 1)|| (meseagg == 6 && dayagg == 1) || (meseagg == 9 && dayagg == 1) || (meseagg == 11 && dayagg == 1))
      {
      dayagg = 30;
      }
      if ((meseagg == 1 && dayagg == 1) || (meseagg == 3 && dayagg == 1) || (meseagg == 5 && dayagg == 1) || (meseagg == 7 && dayagg == 1) || (meseagg == 8 && dayagg == 1) || (meseagg == 10 && dayagg == 1) || (meseagg == 12 && dayagg == 1))
      {
      dayagg = 31;
      }
      else
      {
      dayagg = dayagg - 1;
      }
      }
      lcd.setCursor(0, 0);
      lcd.print("Imposta Giorno:");
      lcd.setCursor(0, 1);
      lcd.print(dayagg, DEC);
      delay(200);
      }

      Elimina
    2. Grazie mille giorgio giorgio.

      Elimina
    3. Cosa e come migliorarlo per funzionare con DS3231

      Elimina
  2. Questo commento è stato eliminato dall'autore.

    RispondiElimina
  3. Ciao, scusa ma ho visto solo ora il tuo messaggio.
    per funzionare con il DS3231? sinceramente non so se esiste una libreria apposita. Eventualmente è da vedere di cambiare le funzioni proprie del DS1307 con quelle nuove del DS3231. Non avendolo a disposizione questo integrato, non so come aiutarti, ma se qualcuno che legge questo (ormai vetusto) post, e ha soluzioni o proposte da postare, ben venga!

    Ciao e buone feste.
    Flavio

    RispondiElimina
    Risposte
    1. Un grande peccato. O forse aiuterai a cambiare in modo da poter cambiare tutti i dati a turno. Significa anno e cambia anno e non come ora che solo alla fine delle impostazioni. Saluti. Krzysztof

      Elimina
    2. Non so come cambiarlo "RTC_DS1307 RTC;" con DS3231 in modo che l'errore non compaia. E se riesco, allora ho un errore qui "RTC.begin (); e se (! RTC.isrunning (....."

      Elimina
  4. Mi vergogno, ma a 2 anni di distanza cerco di darti una mano... per quanto posso... guarda qui https://github.com/NorthernWidget/DS3231.
    Perdona il ritardo e spero possa essere utile per il tuo problema...
    Ciao

    RispondiElimina

Nota. Solo i membri di questo blog possono postare un commento.