Microcontrolerul atmega328 de pe placa de dezvoltare Arduino are un cronometru încorporat denumit millis(), care cu ajutorul unui soft aferen poate fi folosit pe post de ceas. În cazul acesta probabil vă puneţi următoarea întrebare, „Pentru ce mai avem nevoie de un ceas suplimentar?”. Răspunsul este foarte simplu. Folosind un program care să calculeze timpul bazat pe timer-ul millis() ar însemna ca de fiecare dată când Arduino este resetat sau reprogramat să fim nevoiţi să reintroducem data şi ora curentă. Problema este dată de faptul ca millis() reţine numărul de milisecunde de la pornirea plăcii de dezvoltare, ceea ce înseamnă că la fiecare repornire/reprogramare timerul va fi resetat. Pentru proiecte simple, în care acest lucru nu este un inconvenient, se poate merge pe ideea de a crea un ceas software, dar în cazul în care realizăm un „dataloger”, un ceas cu alarma etc. avem nevoie de o metoda coerentă de a înregistra timpul. În acest caz kitul DS1307 ne vine în ajutor deoarece integratul DS1307 reţine secunda/minut/ora/ziua/luna/anul, ţine cont de anii bisecţi, nu îşi pierde informaţia în momentul în care Arduino rămâne fără alimentare sau este reprogramat.
Necesar
-plăcuţă de dezvoltare Arduino
-bread board
-fire pentru conexiuni
-shield DS1307
-(opţional)shield LCD
Schema electrică
Acest schemă poate fi realizată în două moduri. În cazul în care deţineţi un kit ROROID LCD ceasul şi data va fi afişata şi pe display. În caz contrar pentru a citi ora şi data curentă va trebui să folosiți monitorul serial. În ambele cazuri programarea va fi făcută cu ajutorul meniului din monitorul serial. Schema de mai jos explică modul de legare al modulelor de Arduino:
S sau s – setarea datei
Pentru a seta data în monitorul serial se scrie o comanda de forma S(ora)(minut)(secunda)(zi săptămâna)(zi lună)(luna)(anul) cu următoarea structură S(00-23)(00-59)(00-59)(1-7)(01-31)(01-12)(00-99). Astfel dacă vrem să setăm data de 18/08/2012 21:41:00 iar ziua acestei date este sâmbătă comanda va fi următoarea: S2141006180812
C sau c -citirea datei pe serial
Data este afișată pe LCD, dar în cazul în care dorim să citim data pe serial sau nu avem un LCD această comandă este foarte utilă
//Se incarca libraria Wire #include "Wire.h" //Se defineste adresa ceasului DS1307 pe bus I2C #define ADRESA_RTC 0x68 //Se incarca libraria NewCrystalLCD #include <LiquidCrystal_SR_LCD3.h> //Se definesc pini de comunicare const int PIN_LCD_STROBE = 9;//pinul 9 de pe placa Arduino const int PIN_LCD_DATA = 8;//pinul 8 de pe placa Arduino const int PIN_LCD_CLOCK = 7;//pinul 7 de pe placa Arduino //Initializare librarie LiquidCrystal_SR_LCD3 lcd(PIN_LCD_DATA, PIN_LCD_CLOCK, PIN_LCD_STROBE); //variabila care retine mesajul afisat pe LCD String mesaj; //variabila care retine comanda primita pe serial int comanda; //variabila necesara pentru a sti cand afisam data pe serial int ser=0; byte secunda, minutul, ora, ziS, ziL, luna, anul; byte zero; char *zi[] = {"","Lun","Mar","Mie","Joi","Vin","Sam","Dum",}; byte bcdToDec(byte val) { // Functia converteste un nr binar in zecimal return ( (val/16*10) + (val%16) ); } byte decToBcd(byte val) { // inversul functiei bcdToDec return ( (val/10*16) + (val%10) ); } void setup(){ //Initializeaza libraria Wire Wire.begin(); //Initializeaza portul serial Serial.begin(9600); lcd.begin(16, 2);//Definim tipul de display folosit //in cazul nostru 16X2 lcd.print(F("Bine ati venit")); //Tiparim textul lcd.setCursor (0, 1);//sarim pe linia urmatoare lcd.print(F("pe www.roroid.ro"));//tiparim textul zero = 0x00; } void loop(){ if (Serial.available()) { // daca se detecteaza comanda = Serial.read(); if (comanda == 83 || comanda == 115) { //Ex. de comanda folosita pentru setare este setare_data(); //S1742306180812 - unde 17 este ora;42 este minutul;30 sunt secundele //6 este ziua din saptamana;18 este ziua din luna;08 este luna;12 este anul //Daca va grabiti eliminati randurile de mai jos lcd.clear(); lcd.print("Initializare..."); Serial.println("Initializare..."); delay(1000); lcd.setCursor(0,0); lcd.print("Noua data a fost"); lcd.setCursor(0,1); lcd.print("inregistrata!"); Serial.println("Noua data a fost"); Serial.print("inregistrata!"); delay(2000); Serial.println(" "); } else if (comanda == 67 || comanda == 99) { //cu C sau c se afiseaza data pe portul serial ser=1; citeste_data(); Serial.println(" "); ser=0; } } citeste_data(); delay(1000); } //Functia realizeaza citirea datei din DS1307 void citeste_data(){ // Reset the register pointer Wire.beginTransmission(ADRESA_RTC); Wire.write(zero); Wire.endTransmission(); Wire.requestFrom(ADRESA_RTC, 7); secunda = bcdToDec(Wire.read()&0x7f); minutul = bcdToDec(Wire.read()); ora = bcdToDec(Wire.read() & 0x3f); //mod 24 ore ziS = bcdToDec(Wire.read()); //1-7 -> luni - duminica ziL = bcdToDec(Wire.read()); luna = bcdToDec(Wire.read()); anul = bcdToDec(Wire.read()); mesaj=""; if (ora<10) { mesaj=mesaj+"0"; } mesaj=mesaj+ora; mesaj=mesaj+":"; if (minutul<10) { mesaj=mesaj+"0"; } mesaj=mesaj+minutul; mesaj=mesaj+":"; if (secunda<10) { mesaj=mesaj+"0"; } mesaj=mesaj+secunda; lcd.clear(); lcd.print(mesaj); if (ser==1){ Serial.println(mesaj); } lcd.setCursor (0, 1);//sarim pe linia urmatoare mesaj=""; mesaj=zi[ziS]; mesaj=mesaj+" "; if (ziL<10) { mesaj=mesaj+"0"; } mesaj=mesaj+ziL; mesaj=mesaj+"/"; if (luna<10) { mesaj=mesaj+"0"; } mesaj=mesaj+luna; mesaj=mesaj+"/20"; mesaj=mesaj+anul; lcd.print(mesaj); if (ser==1){ Serial.println(mesaj); } } void setare_data() { //se calculeaza valoarile receptionate pe portul serial ora = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48)); minutul = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48)); secunda = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48)); ziS = (byte) (Serial.read() - 48); ziL = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48)); luna = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48)); anul= (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48)); //se trimit noile valori pe I2C Wire.beginTransmission(ADRESA_RTC); Wire.write(zero); Wire.write(decToBcd(secunda) & 0x7f); Wire.write(decToBcd(minutul)); Wire.write(decToBcd(ora)); Wire.write(decToBcd(ziS)); Wire.write(decToBcd(ziL)); Wire.write(decToBcd(luna)); Wire.write(decToBcd(anul)); Wire.endTransmission(); }
Iar la final, rezultatul aplicaţiei:
Programul de mai jos este un exemplu de realizare a unei alarme cu ajutorul modulului DS1307.
#include "Wire.h" //in codul nostru vom folosi timer #include <Metro.h> //Se defineste adresa ceasului DS1307 pe bus I2C #define ADRESA_RTC 0x68 Metro background0 = Metro(5000); byte secunda, minutul, ora, ziS, ziL, luna, anul; byte zero; byte bcdToDec(byte val_n) { // Functia converteste un nr binar in zecimal return ( (val_n/16*10) + (val_n%16) ); } byte decToBcd(byte val_n) { // inversul functiei bcdToDec return ( (val_n/10*16) + (val_n%10) ); } //Functia realizeaza citirea datei din DS1307 void verifica_ora(){ // Reset the register pointer Wire.beginTransmission(ADRESA_RTC); Wire.write(zero); Wire.endTransmission(); Wire.requestFrom(ADRESA_RTC, 7); //citeste ceasul secunda = bcdToDec(Wire.read()&0x7f); minutul = bcdToDec(Wire.read()); ora = bcdToDec(Wire.read() & 0x3f); //mod 24 ore ziS = bcdToDec(Wire.read()); //1-7 -> luni - duminica ziL = bcdToDec(Wire.read()); luna = bcdToDec(Wire.read()); anul = bcdToDec(Wire.read()); //Serial.print(ora); Serial.print(minutul); Serial.println(secunda); if(ora==21 && minutul==0 && secunda>=0) { //alarma de la ora 21 } else if(ora==7 && minutul==0 && secunda>=0) { //alarma de la ora 7 } //reseteaza timer-ul background0.reset(); } void setup() { //Initializeaza libraria Wire Wire.begin(); Serial.begin(9600); zero = 0x00; } void loop() { if (background0.check() == 1) { // se verifica ora din 5 in 5 secunde. Timpul de verificare poate fi setat si mai mic verifica_ora(); } }
Spor la treaba!
De ce DS1307 trebuie sa fie conectat la 5V de la Arduino daca el deja este conectat la baterie?
pentru ca bateria este de backup
Salut.
Intrebarea e foarte buna. In momentul cand are cei 5V la Vcc dispozitivul poate fi citit si scris. Cand aceasta tensiune nu exista dispozitivul intra in modul „sleep”. Vezi mai jos textul preluat din data sheet.
„VCC, GND – DC power is provided to the device on these pins. VCC is the +5V input. When 5V is applied within normal limits, the device is fully accessible and data can be written and read. When a 3V battery is connected to the device and VCC is below 1.25 x VBAT, reads and writes are inhibited. However, the timekeeping function continues unaffected by the lower input voltage. As VCC falls below VBAT the RAM and timekeeper are switched over to the external power supply (nominal 3.0V DC) at VBAT.”
Un mod de a pune o alarma la codul asta
Am un chip TINY RTC cu memrie cu tot pe el. Nu reusesc sa-l initializez deloc. Afiseaza ore, ani, data aberante. Ce e de facut, va rog?
PS. Scuze pentru revenire. Am o placa ARDUINO MEGA 2560. M-am conecat cu SCL si SDA unde trebuie. RTC nu merge. Doar afiseaza abeatiil de care am pomenit (anul 2165, luna 65 etc.). Chiar asa aberante, nu o ia din loc (valorile la secunda nu cresc la fiecare secunda si nu transmite cresterea timpului cu o secunda catre serial, pt afi afisata). Multumesc anticipat pt. orice solutie
Salut,
Am patit acelasi lucru cand:
-libraria folosita nu era ok
-conexiunile nu erau ok
-alimentarea era 3v in loc de 5
-erau erori in program
Sper sa te ajute.
@lucian Am adaugat un nou cod care seteaza doua alarme
@adrian Mai adauga la lista de mai sus si initializarea din setup pentru libraria wire Wire.begin();
Va multumim pentru munca depusa. E minunat suportul tehnic pentru programarea acestor device-uri dar am totusi si o bila neagra pentru d-voastra. Pentru ca aceste tutoriale sunt citite de foarte multi oameni ei au tendinta sa ia de bun si scrisul prezent aici. Va rog sa corectati „v-a” cu „va” pentru simplu motiv ca nu se aplica. fara sa fie o jignire, vrem doar sa fie folosita limba romana corect ( atat ne-a mai ramas ). un link ajutatator http://scri.ro/va-sau-v-a-187.html
Multumesc pentru atentionare. Nu este nici o jgnire.
P.S. Recunosc ca am cam chiulit de la orele de LIMBA SI LITERATURA ROMANA!
Salut asi avea si eu o intrebare legata de placa de dezvoltare Arduino se poate sa fac ca pe un afisaj lcd in coltul din stanga sa fie afisat timpul si data si in cel din dreapta 2 temperaturi (interior si exterior)???Multumesc anticipat
Salut,
Ce fel de LCD?
Va salut. Am o plac Arduino Mega 2560 cu acel ceas în timp real DS1307 dar nu stiu care librarie este buna pentru el. pentru ca setez ceasul si nu il memoreaza dupa ce i scot alimentarea
Atata timp cat in momentul cand cititi ceasul datele sunt ok libraria functioneaza.
Totusi as dorii sa stiu daca:
1.E montajul legat la o baterie externa?
2.E functionala acea baterie?
Salutare. Cum as putea face si eu montajul dar fara arduino, as vrea sa folosesc doar atmega328, pentru a iesii montajul cat mai mic, trebuie modificat in program intrarile si iesirile?
Nu trebuie sa schimbi nimic. Pe atmega trebuie sa încarci bootloaderul de arduino(găsești pe site un articol despre cum se face acest lucru) si trebuie sa știi corespondenta intre pinii atmega si arduino(găsești cu un search pe Google).
Buna seara ,
Interesant programul si multumim pentru rabdarea de a ne asculta.
Cum se implementeaza cele 2 alarme in codul initial?
Multumesc!
Am facut montajul cu arduino uno si merge perfect, dar cand arduino nu este alimentat pierd data si ora. La realimentare afiseaza data si ora la care am incarcat programul in arduino. DS1307 are baterie conectata. Ce se poate face sa functioneze ceasul cand arduino nu este alimentat?
Multumesc.
Fie bateria nu e buna, fie nu e legata cum trebuie fie in programul arduino, de fiecare data cand il pornesti rescrii ora.
Buna ziua,
Mulțumesc pentru răspuns.
Montajul folosit este unul cumpărat de pe DX.com cu memorie 24C32N si DS1307 deci cred ca este ok, bateria am schimbat-o cu altele 3, și după ce am scos din program // RTC.adjust(DateTime(__DATE__, __TIME__));, pornește de fiecare data cu data 1/1/2000 00:00:00. Ce as putea sa mai încerc?
Mulțumesc.