Arduino schéma - arduino.sk

hodiny DS1307 s korekciou

Programovanie arduina
Príspevky: 6
Registrovaný: Str 12. Jún 2013 19:42:18

hodiny DS1307 s korekciou

Poslaťod lubo_1 » Str 31. Júl 2013 21:31:07

Zdravím.
Možno to niekomu pomôže.
Hotový SW pre Arduino + hodiny DS1307 + displej s tlačítkami.
Keďže hodiny meškali - dorobil som aj automatickú korekciu času, kde sa do premennej adj_sec_day zadá, koľko sekúnd za 24 hod má pridať (kladná hodnota), alebo ubrať (záporná hodnota). Do nastavenia času sa vchadza šípkami. Šípka vpravo / vľavo presuva kurzor na nastavované hodnoty. Pri prechode "za roh" opušťa nastavenie, bez zapisu hodnoty. Šipka hore / dolu mení nastavovanú hodnotu. Tlačítko Select zapíše zmenu a ukončí nastavovanie. Je to soft, ktorý bude súčasťou riadenia kúrenia. Ak niekomu pomôže, budem rád.....
EEproma bude slúžiť na logovanie a zápisu konfigu .... ešte len tvorím ....
Ľubo
P.S. Datum a čas aktualizacie sa zapisuje do NVRAM v čipe, takže si to pametá aj po vypnutí napajania. Po zapnutí si vie prepocítať, kedy bol čas naposledy aktualizovaný a podľa toho si prepočíta o koľko treba skorigovať čas.....
Kód: Vybrať všetko
#include <LiquidCrystal.h>
#include <DS1307.h>
#include <Time.h>
//---------------------------------------------------------------------------
#define KBport_PIN     0    // PIN klavesnice
#define BACKLIGHT_PIN     10  //Pin podsvietenia
int lcd_key     = 0;      // kod klavesy - btnNONE=5, btnRIGHT=0.......
//int needsetup = 1;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

boolean rs1 =0;
boolean rs2 =0;
//------------------------
unsigned long timer = 0;       //timer refres hodin
unsigned long timer_kor = 0;       //timer posun hodin
unsigned long timer_BKL = 0;  // timer zhasnutia
unsigned long time_BKL=0 ;         // cas zhasnutia displeja -ms
//------------------------
byte adr_test=1;          // bajt testujuci pritomnos+t hodin a funkcnost aku
byte adr_hod=49;          // adresa RAM RTC, kde sa uklda zaznam o aktualizacii
byte adr_min=50;
byte adr_sek = 51;
byte adr_den=52;
byte adr_mes=53;
byte adr_rok_up=54;
byte adr_rok_low=55;
//--------------------------
#define LCD_WIDTH 16        // pocet stlpcov
#define LCD_HEIGHT 2        // pocet riadkov
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#define LCD_WIDTH 16        // pocet stlpcov
#define LCD_HEIGHT 2        // pocet riadkov
int adj_sec_day= 0;      // prida /uberie dany pocet sekund pocas 24 hod
//--------------------------
DS1307 rtc(20, 21);  // I2C zbernica
Time  t;
//-----------------------------------------------------------------------------
void setup()
{
//------------------------------------------------
// tu budu zalezitosti zo setupu
time_BKL= 600000;        //cas do zhasnutia v ms - 600000=10 min
adj_sec_day= 15;      // prida /uberie dany pocet sekund pocas 24 hod + prida/ - uberie
//------------------------------------------------
  rtc.halt(false);   // Set the clock to run-mode
  lcd.begin(LCD_WIDTH, LCD_HEIGHT);  //rezmer displeja
Serial.begin(9600);    //default seriovky
pinMode(BACKLIGHT_PIN, OUTPUT);   // nastav BKL pin ako vystup
digitalWrite(BACKLIGHT_PIN, HIGH);  // rozsviet displej
rtc.poke(adr_test,170);            // zapis test bajt 10101010 na adresu 1 v RAM
batrtc();
t = rtc.getTime();          // nacitanie casu
       kor_rtc();                        // funkcia korekcie casu
}
//---------------------------------------------------------------------------------
void loop()
{
t = rtc.getTime();          // nacitanie casu
lcd_key = read_LCD_RS_buttons();  // čita klavesu do premennej - necita viacnasobne
//--------------------------------------
   if (millis()- timer_BKL > time_BKL) {    //zhasne po 10 minutach
    digitalWrite(BACKLIGHT_PIN, LOW);       
      if (lcd_key != btnNONE){               // ak je disp zhasnuty a stlacena klavesa
      timer_BKL = millis();                  //reset timera podsvietenia
      lcd_key=btnNONE;}}                     // znuluj klavesu
    else digitalWrite(BACKLIGHT_PIN, HIGH);  //rozsviet displej ak je timer nulovany
//-------------------------------------
if (millis() - timer > 1000) {   // zobraz cas kazdu sekundu (1000ms)
      if(batrtc()) vypiscas();
      else {
        lcd.setCursor(0,0);             // vymaz LCD
        lcd.clear();
        lcd.setCursor(4,0);
        lcd.print("bateria RTC");        // vypis hlasku     
      }
        timer = millis(); }
//-------------------------------------       
if (lcd_key != btnNONE){    // nastavenie casu
nastavcas();}               //nastavenie hodin
//----------------------------
    if (millis() - timer_kor > 30000) {   // urob korekciu kazdych 5 min
        kor_rtc();                        // funkcia korekcie casu
        timer_kor = millis(); } 
//----------------------------
}                    // End loop

//------------------------------------------------------------------*/
/*int read_LCD_buttons()    //funkcia čitania klavesnice
{int adc_key_in  = 0;      // analogova hodnota tlacitka
adc_key_in = analogRead(KBport_PIN);      // read the value valies: 0, 144, 329, 504, 741
if (adc_key_in > 1000) return btnNONE;
    if (adc_key_in < 50)   return btnRIGHT; 
    if (adc_key_in < 250)  return btnUP;
    if (adc_key_in < 450)  return btnDOWN;
    if (adc_key_in < 650)  return btnLEFT;
    if (adc_key_in < 850)  return btnSELECT; 
    return btnNONE; } // when all others fail, return this...*/
//---------------------------------------------------------------
int read_LCD_RS_buttons()    //funkcia čitania klavesnice- cita tlacitko iba raz pri naslednom priechode vrati btmNONE
// nove citanie sa prevedie az po uvolneni a novom stlaceni tlacitka ak sa bude drzat klavesa - vykona sa iba raz
{int adc_key_in  = 0;      // analogova hodnota tlacitka
   adc_key_in = analogRead(KBport_PIN);      // read the value valies: 0, 144, 329, 504, 741
if (adc_key_in > 950) {
     rs1=0;                      //reset tlacitka
     return btnNONE; }
if (rs1==0){
    rs1=1;          //  set RS1 klopaku tlacitka- nastaveny, kym sa tlacitko nepusti
    if (adc_key_in < 50) return btnRIGHT; 
    if (adc_key_in < 250) return btnUP;
    if (adc_key_in < 450) return btnDOWN;
    if (adc_key_in < 650) return btnLEFT;
    if (adc_key_in < 850) return btnSELECT; }
    return btnNONE; }  // when all others fail, return this... 
//---------------------------------------------------------------
void nastavcas() {   //samotne nastavenie casu
int poscursor=0;     // pozicia kurzora nastavenia hodín
int hod, minuty, sek; //premenna pre nacitanie hodin
int dev, datum, mes, rok; // premenne datumu
int pozznak []={4,7,10,0,6,9,12};  //pozicia stlpcov premennych
int pozriadok [] = {0,0,0,1,1,1,1};  // pozicia riadkov premennych
boolean utek = 0;    // ukoncenie setu bez ulozenia udajov
//------------
lcd.clear();           
t = rtc.getTime();     //precitanie z DS1307
hod=t.hour;            // naplnenie premennych
minuty= t.min;
sek=t.sec;
dev= t.dow;
datum= t.date;
mes= t.mon;
rok=t.year;

//----------------
  while (lcd_key != btnSELECT && utek !=1) {         // kym sa nestlaci btn_SELECT, alebo neprejde za roh
//------------
lcd_key = read_LCD_RS_buttons();                    // čita klavesu do premennej lcd_key
if (lcd_key == btnRIGHT && poscursor ==7) utek=1 ;  // ak je stlacene tlac vpravo a je pozicia vpravo dole- opust bez ulozenia
if (lcd_key == btnLEFT && poscursor ==0)utek= 1;   // ak je tlac vlavo hore a sipka vlavu - opust bez ulozenia
if (lcd_key == btnRIGHT && poscursor <7)poscursor ++; // ak je stlacene tlac vpravo presun kurzor na masl. premennu
if (lcd_key == btnLEFT && poscursor >0) poscursor --; // ak je tlac vlavo presun na predoslu premennu
//--------------------------
if(rs1){                                            // ak bolo stlacene tlacitko - zvyrazni LCD_blink
  lcd.setCursor(pozznak[0], pozriadok[0]);          // zobraz aktualizovane hodiny
    printDigits(hod);                               // zobrazi hodiny
   lcd.print(":");
  lcd.setCursor(pozznak[1],pozriadok[1]);            // zobrazi minuty
    printDigits(minuty);
  lcd.print(":");
  lcd.setCursor(pozznak[2],pozriadok[2]);            // zobrazi sekundy
    printDigits(sek);
//----------------------            druhy riadok
lcd.setCursor(pozznak[3],pozriadok[3]);               // den v tyzdni
    print_denv(dev);
  lcd.setCursor(pozznak[4],pozriadok[4]);              // datum
    printDigits(datum);
  lcd.print(".");
  lcd.setCursor(pozznak[5],pozriadok[5]);              // mesiac
    printDigits(mes);
  lcd.print(".");
  lcd.setCursor(pozznak[6],pozriadok[6]);              // rok
  lcd.print(rok);
}
//--------------------------
switch(poscursor){                                    // citaj poziciu kurzora
     case 0:lcd.setCursor(pozznak[0]+1, pozriadok[0]);  // ak je hodiny
         if(lcd_key == btnUP) if(hod <23) hod++; else hod=0;  //ak je tl hore- ak je menej ako 23 - pripocitaj hodinu, inak 0
         if(lcd_key == btnDOWN) if(hod >0) hod--; else hod=23;   // ak je tl dole -ak je viac ako 0 hod potom zmensi o 1, ak je 0 - nastav 23
        break;
     case 1:lcd.setCursor(pozznak[1]+1, pozriadok[1]);  //ak su minuty
         if(lcd_key == btnUP) if(minuty <59) minuty++; else minuty=0;             
         if(lcd_key == btnDOWN) if(minuty >0) minuty--; else minuty=59;
        break;
     case 2:lcd.setCursor(pozznak[2]+1, pozriadok[2]);    // ak su sekundy
         if(lcd_key == btnUP) if(sek <59) sek++; else sek=0;
         if(lcd_key == btnDOWN) if(sek >0) sek--; else sek=59;
        break;
      case 3:lcd.setCursor(pozznak[3]+2, pozriadok[3]);    // den v tyzdni bude preskakovat
         if (lcd_key == btnRIGHT) poscursor ++;            // ak je stlacene tlac vpravo presun kurzor na den
         if (lcd_key == btnLEFT) poscursor --;             // vlavo na sekundy
        break;
      case 4:lcd.setCursor(pozznak[4]+1, pozriadok[4]);    // ak je den
         if(lcd_key == btnUP) if(datum <31) datum++; else datum=1;
         if(lcd_key == btnDOWN) if(datum >1) datum--; else datum=31;
        break;
      case 5:lcd.setCursor(pozznak[5]+1, pozriadok[5]);      // ak je mesiac
         if(lcd_key == btnUP) if(mes <12) mes++; else mes=1;
         if(lcd_key == btnDOWN) if(mes >1) mes--; else mes=12;
        break;
      case 6:lcd.setCursor(pozznak[6]+3, pozriadok[6]);      // ak je rok
         if(lcd_key == btnUP) if(rok <2100) rok++; else rok=2010;
         if(lcd_key == btnDOWN) if(rok >2010) rok--; else rok=2100;
        break;
     }
//------------------------                // zistenie dna v tyzdni z datumu
if(poscursor >=4 && poscursor <=6){       // ak sa meni datum
setTime(hod,minuty,sek,datum,mes,rok);    // nacitaj hodnoty do setTime a vrat denv
if (weekday()==1) dev=(weekday()+6);      // problem kniznice - nedela DOV()=1,po2 ut3 u DS1307 je to ne7, po1, ut2
else dev= (weekday()-1);                  // nastavenie dna v tyzdni
}
//------------------------

  lcd.blink();                                                 // blika kurzor
}                                        // koniec while
//-------------------------       // koniec nastavcas a ukladanie
lcd.noCursor();                            //vypni kurzor
lcd.noBlink();                              // vypni blikanie
//--------------------------
//Nastavenie casu a zapis do RAM zaznam o oprave
if (utek==0){                              // utek =1 bez ulozenia utek=0 nastavenie casu a zapis korekcie
  rtc.setTime(hod,minuty,sek);                // nastavenie casu
  rtc.setDOW(dev);                           // nastavenie dna v tyzdni
  rtc.setDate(datum,mes,rok);                // nastavenie datumu
//--------------------------
rtc.poke(adr_hod,hod);                        // do RAM v RTC zapise cas a datum zmeny
rtc.poke(adr_min,minuty);                    // dalej sa tu bude ukladat cas korekcie hodin
rtc.poke(adr_sek,sek);
rtc.poke(adr_den,datum);
rtc.poke(adr_mes,mes);
rtc.poke(adr_rok_up,highByte(rok));            // uklada sa horny bajt roku v hexa
rtc.poke(adr_rok_low,lowByte(rok));}            // dolny bajt roku
}                                      // koniec nastavcas
//---------------------------------------------------------------
void vypiscas()
{
  t = rtc.getTime();          // nacitanie casu
    lcd.setCursor(4, 0);
    printDigits(t.hour);
    lcd.print(":");
    printDigits(t.min);
    lcd.print(":");
    printDigits(t.sec);
    lcd.setCursor(0, 1); 
    print_denv(t.dow);
    lcd.setCursor(6, 1);
    printDigits(t.date);
    lcd.print(".");
    printDigits(t.mon);
    lcd.print(".");
    lcd.print(t.year);
    }
//---------------------------------------------------------------
boolean batrtc()          // hodiny po resete bez aku maju datum 01/01/2000
{
boolean stavbat=1;
if( rtc.peek(adr_test)!= 170) {        // ak nieje na adr_test 170 - potom je stavbat 0
  stavbat=0;}
else{
//---------------- pri prve spusteni zapise do RAM datum a cas ako zaznam poslednej aktualizacie
if (rtc.peek(adr_mes)+rtc.peek(adr_den) == 0) {  //ak s=u nulove bajty dna a mesiaca v RAM
t = rtc.getTime();
rtc.poke(adr_hod,t.hour);                        // do RAM v RTC zapise cas a datum zmeny
rtc.poke(adr_min,t.min);                    // dalej sa tu bude ukladat cas korekcie hodin
rtc.poke(adr_sek,t.sec);
rtc.poke(adr_den,t.date);
rtc.poke(adr_mes,t.mon);
rtc.poke(adr_rok_up,highByte(t.year));            // uklada sa horny bajt roku v hexa
rtc.poke(adr_rok_low,lowByte(t.year));}            // dolny bajt roku
}
return stavbat;}
//-----------------------------------------------------------------------------
void kor_rtc()
{
long cas_rozdiel=0;                  // rozdiel casu v sekundach od poslednej aktualizacie
long aktual_time_kor= 0;              // aktualny cas
long last_time_kor= 0;                // cas poslednej akt.
float nasobok = 0;                  // pocet pridavanych sekund
int kor_rtc_konst = 0;                  // pocet sekund, po ich uplynuti sa prida /uberie sekunda
//------------------------------        Nastaví cas na hodnotu zapisu casu poslednej korekcie
setTime(rtc.peek(adr_hod),rtc.peek(adr_min),rtc.peek(adr_sek),rtc.peek(adr_den),rtc.peek(adr_mes),(rtc.peek(adr_rok_up)*256)+ rtc.peek(adr_rok_low));
last_time_kor=now();                                    // pocet sekud poslednej kor od 01.01.1970
setTime(t.hour, t.min, t.sec, t.date, t.mon, t.year);    // nastav aktualny cas z DS1307
aktual_time_kor= now();                                  // vypocitaj pocet sekund od 01.01.1970
cas_rozdiel= aktual_time_kor - last_time_kor;            // vypocíta pocet sekun medzi poslednou aktualizaciou a aktualnym casom
//--------------------------------
/*ne1 7
po2 1
ut3 2
str4 3
stv5 4
pia6 5
sob7 6*/
//------------------
kor_rtc_konst= 86400/adj_sec_day;              // vypocet po kolkych sekundach sa bude upravovat cas - 24h/adj_sec
if (cas_rozdiel > abs(kor_rtc_konst)){    // tu sa bude korigovat cas, ak je rozdiel od posled. aktual vecsi ako kor_rtc_konst
//---------                           zisti nasobok korekcie- pocet sekund
      nasobok = int(cas_rozdiel/kor_rtc_konst);    // vypocita nasobok
//------------------
         if (nasobok >0){                                       // ak je co upravovat
            adjustTime(nasobok);                               // nastav cas
//-----------------------
            rtc.setTime(hour(),minute(),second());                // nastav DS1307  cas
              if (weekday()==1) rtc.setDOW(weekday()+6);      // problem kniznice - nedela DOV()=1,po2 ut3 u DS1307 je to ne7, po1, ut2
              else rtc.setDOW(weekday()-1);            // nastavenie dna v tyzdni
              rtc.setDate(day(),month(),year());                // nastavenie datumu
//------------------------    zaznam o korekcii casu
          rtc.poke(adr_hod,hour());                        // do RAM v RTC zapise cas a datum zmeny
          rtc.poke(adr_min,minute());                    // dalej sa tu bude ukladat cas korekcie hodin
          rtc.poke(adr_sek,second());
          rtc.poke(adr_den,day());
          rtc.poke(adr_mes,month());
          rtc.poke(adr_rok_up,highByte(year()));            // uklada sa horny bajt roku v hexa
          rtc.poke(adr_rok_low,lowByte(year()));
        }
/*Serial.print("nasobok:");
Serial.println(nasobok) ;   
Serial.println(hour()) ; 
Serial.println(minute()) ;
//----------------------------             
Serial.println(hour()) ;
Serial.println(minute()) ;
Serial.println("Added a minute."); // send confirmation to the PC.*/
}
}
//-----------------------------------------------------
void printDigits(int digits) {
  // utility function for digital clock display: prints preceding colon and leading 0
  if(digits < 10) lcd.print('0');
  lcd.print(digits);
}
//------------------------------------------------------
void print_denv(int digits)
{
char* chr_denv[] = {"xXx","Pon","Uto","Str","Stv","Pia","Sob","Ned"}; // zobrazovane udaje dow
if (digits>=1 && digits<=7) lcd.print(chr_denv[digits]);      //ak je dow v rozsahu 1-7 zobraz pon- ned
else lcd.print(chr_denv[0]);                                  // inak zobraz xXx
}
//------------------------------------------------------

Príspevky: 6
Registrovaný: Str 12. Jún 2013 19:42:18

Re: hodiny DS1307 s korekciou

Poslaťod lubo_1 » Str 21. Aug 2013 21:08:35

Takže SW odmietal pracovať s 18B20..... Mlátili sa knižnice. Tak som zlátal druhú verziu bez knižnice DS1307. Je to funkčné.....
Kód: Vybrať všetko
#include <LiquidCrystal.h>
#include <Wire.h>
#include <Time.h>

#define DS1307 0x68
#define adr_24c32 0x50 
#define RAM_OFFSET 8         //map logical ram addresses (0-55) to physical addresses (8-63)

//---------------------------------------------------------------------------
#define KBport_PIN     0    // PIN klavesnice
#define BACKLIGHT_PIN     10  //Pin podsvietenia
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

//------------------------
// adresy uloženia premennych   
#define adr_test     1      // bajt testujuci pritomnos+t hodin a funkcnost aku
#define adr_hod     49      // adresa RAM RTC, kde sa uklda zaznam o aktualizacii
#define adr_min     50
#define adr_sek     51
#define adr_den     52
#define adr_mes     53
#define adr_rok     54
//#define adr_rok_low 55
#define adr_last_log_hod     42  // adresa RAM RTC kde sa uklada zaznam o logu
#define adr_last_log_min     43  // hod/min/den/mes/rok
#define adr_last_log_dan     44
#define adr_last_log_mes     45
#define adr_last_log_rok     46
#define adr_log_next_up      47     // adresa dalsieho zapisu UP
#define adr_log_next_low     48    // LOW byte
#define log_start_up       0x08     // adresa v EEprom od ktorej sa bude logovat UP #define
#define log_start_low      0x00    // LOW byte
#define log_end_up         0x7f        // koniec EEprom UP #define
#define log_end_low        0xff      // LOW byte
#define adr_ee_log_start   0x00   // adresa EEprom na ktorej je adresa logu start
#define adr_ee_log_end     0x02    // adresa EEprom na ktorej je adresa konca EEprom
#define adr_ee_adj_sec_day 0x04  // adresa EEprom, kde je hodnota INT adj_sec_day 
#define adr_ee_time_BKL    0x06
#define adr_ee_min_log     0x08  // adresa na ktorej interval logu - min - max 256
//--------------------------


//int needsetup = 1;
int lcd_key     = 0;      // kod klavesy - btnNONE=5, btnRIGHT=0.......
boolean rs1 =0;
boolean rs2 =0;
//------------------------
unsigned long timer = 0;       //timer refres hodin
unsigned long timer_kor = 0;       //timer posun hodin
unsigned long timer_BKL = 0;  // timer zhasnutia
unsigned long timer_ee_write = millis(); // timer oneskorenia po zapise do EEprom
unsigned long time_BKL=0 ;         // cas zhasnutia displeja -ms
int adj_sec_day= 0;            // prida /uberie dany pocet sekund pocas 24 hod
byte ds_second, ds_minute, ds_hour, ds_weekday, ds_day, ds_month, ds_year;
byte log_second, log_minute, log_hour, log_day, log_month, log_year, log_period_min;
boolean bat_state =0;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#define LCD_WIDTH 16        // pocet stlpcov
#define LCD_HEIGHT 2        // pocet riadkov
//--------------------------------------------------------------

void setup() {
  Wire.begin();
Serial.begin(9600);    //default seriovky

lcd.begin(LCD_WIDTH, LCD_HEIGHT);  //rezmer displeja
pinMode(BACKLIGHT_PIN, OUTPUT);   // nastav BKL pin ako vystup
digitalWrite(BACKLIGHT_PIN, HIGH);  // rozsviet displej

getTimeDs();        // nacitanie casu
  if (!testimer()){
      hlas_bat();
       delay(2000);
       rs1=1;
      nastavcas();
       }     
//------------------------------------------------
// tu budu zalezitosti zo setupu
time_BKL= 600000;        //cas do zhasnutia v ms - 600000=10 min
adj_sec_day= 0;      // prida /uberie dany pocet sekund pocas 24 hod + prida/ - uberie
//------------------------------------------------
}            // end Setup
//---------------------------------------------------------------------
void loop() {
//----------------------------
lcd_key = read_LCD_RS_buttons();  // čita klavesu do premennej - necita viacnasobne
    vypiscas();// zobraz cas kazdu sekundu (1000ms)
    lcd_off();
    test_kor_time();           // urob korekciu kazdych 5 min
if (lcd_key != btnNONE){    // nastavenie casu
nastavcas();}               //nastavenie hodin
//----------------------------

}                    // End loop
//------------------------------------------------------------------
boolean testimer() {
boolean rtc_state = false; 
   test_ram();
  if (!dsIsRunning()) initTimeDs();      //dsIsRunning vrati true, ak hodiny bezia- spusti initTimeDS{}
                                         // nastavi sekundy a mali by sa rozbehnut hodiny 
if (dsSramRead(0) == 0xAA) dsSramWrite(0x00, 0xAA);  // Ak nieje v RAM, poz0 0xAA - zapis
if (dsIsRunning() && batrtc() && dsSramRead(0) == 0xAA) return true;
if (batrtc()) return true ;                // zisti stav aku ak je datum 01/01/2000 - vrati False, inak true
Serial.print( "BATERIA RTC ");
Serial.print( dsSramRead(0));
return rtc_state;
}
//---------------------------------------------------------------------
void hlas_bat(){
  lcd.setCursor(0,0);             // vymaz LCD
        lcd.clear();
        lcd.setCursor(2,0);
        lcd.print("bateria RTC");       // vypis hlasku     
}
//---------------------------------------------------------------------       
void lcd_off() {
  if (millis()- timer_BKL > time_BKL) {    //zhasne po 10 minutach
    digitalWrite(BACKLIGHT_PIN, LOW);       
      if (lcd_key != btnNONE){               // ak je disp zhasnuty a stlacena klavesa
      timer_BKL = millis();                  //reset timera podsvietenia
      lcd_key=btnNONE;}}                     // znuluj klavesu
    else digitalWrite(BACKLIGHT_PIN, HIGH);  //rozsviet displej ak je timer nulovany
}
//------------------------------------------------------
void test_kor_time(){
    if (millis() - timer_kor > 30000) {   // urob korekciu kazdych 5 min
       if (adj_sec_day !=0) kor_rtc();    // funkcia korekcie casu
        timer_kor = millis(); } }
// ----------------------- FUNKCIE ----------------------
byte bcd2dec(byte val){
  return ((val/16*10) + (val%16));
}

byte dec2bcd(byte val){
  return ((val/10*16) + (val%10));
}
//--------------------------------------
void getTimeDs(){            // citanie datumu a casu z DS1307
  Wire.beginTransmission(DS1307);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(DS1307, 7);
  ds_second = bcd2dec(Wire.read() & 0x7f);
  ds_minute = bcd2dec(Wire.read());
  ds_hour = bcd2dec(Wire.read() & 0x3f);
  ds_weekday = bcd2dec(Wire.read());
  ds_day = bcd2dec(Wire.read());
  ds_month = bcd2dec(Wire.read());
  ds_year = bcd2dec(Wire.read());
}
//----------------------------
void setTimeDs(){            // zapis datumu a casu do DS1307
     Wire.beginTransmission(DS1307);  // posli novy cas do DS1307
      Wire.write(0x00);
      Wire.write(dec2bcd(ds_second) & 0x7f);
      Wire.write(dec2bcd(ds_minute));
      Wire.write(dec2bcd(ds_hour));
      Wire.write(dec2bcd(ds_weekday));
      Wire.write(dec2bcd(ds_day));
      Wire.write(dec2bcd(ds_month));
      Wire.write(dec2bcd(ds_year));
      Wire.endTransmission();
     // delay(300);
    }
//---------------------------------------------------------------
boolean batrtc() {         // hodiny po resete bez aku maju datum 01/01/2000
boolean bat_rtc_state = true;
if (ds_month==1 && ds_day ==1 && ds_year ==0) bat_rtc_state = false;
return bat_rtc_state;
}
//--------------------------------------
void initTimeDs(){      // vykoná time start
byte result;
  Wire.beginTransmission(DS1307);
Wire.write(0);        // Start address
Wire.write(dec2bcd(ds_second));     // Second
  Wire.endTransmission();
}

//---------------- pri prve spusteni zapise do RAM datum a cas ako zaznam poslednej aktualizacie
void test_ram(){      // spusti log%change%time, ak nieje rok v rozmedzi 10-100
if (dsSramRead(adr_rok) <10 || dsSramRead(adr_rok) >100) log_change_time();  //ak je rok v RAM vecsi ako 100, alebo mensi ako 10
}
//-----------------------------------------------------------------------------------------

//write to DS1307 RAM where addr>=0 and addr<56
void dsSramWrite(byte addr, byte values)    // zapis bajt na adresu
{
    Wire.beginTransmission(DS1307);
    Wire.write(addr + RAM_OFFSET);
    Wire.write(values);
    Wire.endTransmission();   
}

//read from DS1307 RAM where addr>=0 and addr<56
byte dsSramRead(byte addr)        // cita bajt z adresy
{
byte read_values =0; 
Wire.beginTransmission(DS1307);
Wire.write(addr+RAM_OFFSET);
Wire.endTransmission();
Wire.requestFrom(DS1307, 1);
    read_values = Wire.read();
return read_values;
}
//----------------------------------------------------------------------------
//is the DS1307 oscillator running?
boolean dsIsRunning(void)      // je spusteny oscilator
{
    byte secRegister;        //seconds register, bit 7 is clock halt (CH) bit
   
    Wire.beginTransmission(DS1307);
    Wire.write(0x00);        //seconds register is address zero
    Wire.endTransmission(); 
    Wire.requestFrom( DS1307, 1 );  // citanie
    secRegister = Wire.read();     
      return !(secRegister & 0x80);    //vrati bit spusteneho oscilatora
}
//---------------------------------------------------------------
int read_LCD_RS_buttons()    //funkcia čitania klavesnice- cita tlacitko iba raz pri naslednom priechode vrati btmNONE
// nove citanie sa prevedie az po uvolneni a novom stlaceni tlacitka ak sa bude drzat klavesa - vykona sa iba raz
{int adc_key_in  = 0;      // analogova hodnota tlacitka
   adc_key_in = analogRead(KBport_PIN);      // read the value valies: 0, 144, 329, 504, 741
if (adc_key_in > 950) {
     rs1=0;                      //reset tlacitka
     return btnNONE; }
if (rs1==0){
    rs1=1;          //  set RS1 klopaku tlacitka- nastaveny, kym sa tlacitko nepusti
    if (adc_key_in < 50) return btnRIGHT; 
    if (adc_key_in < 250) return btnUP;
    if (adc_key_in < 450) return btnDOWN;
    if (adc_key_in < 650) return btnLEFT;
    if (adc_key_in < 850) return btnSELECT; }
    return btnNONE; }  // when all others fail, return this... 
//---------------------------------------------------------------
void nastavcas() {   //samotne nastavenie casu
int poscursor=0;     // pozicia kurzora nastavenia hodín
//int hod, minuty, sek; //premenna pre nacitanie hodin
//int dev, datum, mes, rok; // premenne datumu
int pozznak []={4,7,10,0,6,9,12};  //pozicia stlpcov premennych
int pozriadok [] = {0,0,0,1,1,1,1};  // pozicia riadkov premennych
boolean utek = 0;    // ukoncenie setu bez ulozenia udajov
//------------
lcd.clear();           
getTimeDs();
//----------------
  while (lcd_key != btnSELECT && utek !=1) {         // kym sa nestlaci btn_SELECT, alebo neprejde za roh
//------------
if(rs1){                                            // ak bolo stlacene tlacitko - zvyrazni LCD_blink
  lcd.setCursor(pozznak[0], pozriadok[0]);          // zobraz aktualizovane hodiny
    printDigits(ds_hour);                               // zobrazi hodiny
   lcd.print(":");
  lcd.setCursor(pozznak[1],pozriadok[1]);            // zobrazi minuty
    printDigits(ds_minute);
  lcd.print(":");
  lcd.setCursor(pozznak[2],pozriadok[2]);            // zobrazi sekundy
    printDigits(ds_second);
//----------------------            druhy riadok
lcd.setCursor(pozznak[3],pozriadok[3]);               // den v tyzdni
    print_denv(ds_weekday);
  lcd.setCursor(pozznak[4],pozriadok[4]);              // datum
    printDigits(ds_day);
  lcd.print(".");
  lcd.setCursor(pozznak[5],pozriadok[5]);              // mesiac
    printDigits(ds_month);
  lcd.print(".");
  lcd.setCursor(pozznak[6],pozriadok[6]);              // rok
  lcd.print(ds_year+2000);
}
//--------------------------
lcd_key = read_LCD_RS_buttons();                    // čita klavesu do premennej lcd_key
if (lcd_key == btnRIGHT && poscursor ==6) utek=1 ;  // ak je stlacene tlac vpravo a je pozicia vpravo dole- opust bez ulozenia
if (lcd_key == btnLEFT && poscursor ==0)utek= 1;   // ak je tlac vlavo hore a sipka vlavu - opust bez ulozenia
if (lcd_key == btnRIGHT && poscursor <7)poscursor ++; // ak je stlacene tlac vpravo presun kurzor na masl. premennu
if (lcd_key == btnLEFT && poscursor >0) poscursor --; // ak je tlac vlavo presun na predoslu premennu

//--------------------------
switch(poscursor){                                    // citaj poziciu kurzora
     case 0:lcd.setCursor(pozznak[0]+1, pozriadok[0]);  // ak je hodiny
         if(lcd_key == btnUP) if(ds_hour <23) ds_hour++; else ds_hour=0;  //ak je tl hore- ak je menej ako 23 - pripocitaj hodinu, inak 0
         if(lcd_key == btnDOWN) if(ds_hour >0) ds_hour--; else ds_hour=23;   // ak je tl dole -ak je viac ako 0 hod potom zmensi o 1, ak je 0 - nastav 23
        break;
     case 1:lcd.setCursor(pozznak[1]+1, pozriadok[1]);  //ak su minuty
         if(lcd_key == btnUP) if(ds_minute <59) ds_minute++; else ds_minute=0;             
         if(lcd_key == btnDOWN) if(ds_minute >0) ds_minute--; else ds_minute=59;
        break;
     case 2:lcd.setCursor(pozznak[2]+1, pozriadok[2]);    // ak su sekundy
         if(lcd_key == btnUP) if(ds_second <59) ds_second++; else ds_second=0;
         if(lcd_key == btnDOWN) if(ds_second >0) ds_second--; else ds_second=59;
        break;
      case 3:lcd.setCursor(pozznak[3]+2, pozriadok[3]);    // den v tyzdni bude preskakovat
         if (lcd_key == btnRIGHT) poscursor ++;            // ak je stlacene tlac vpravo presun kurzor na den
         if (lcd_key == btnLEFT) poscursor --;             // vlavo na sekundy
        break;
      case 4:lcd.setCursor(pozznak[4]+1, pozriadok[4]);    // ak je den
         if(lcd_key == btnUP) if(ds_day <31) ds_day++; else ds_day=1;
         if(lcd_key == btnDOWN) if(ds_day >1) ds_day--; else ds_day=31;
        break;
      case 5:lcd.setCursor(pozznak[5]+1, pozriadok[5]);      // ak je mesiac
         if(lcd_key == btnUP) if(ds_month <12) ds_month++; else ds_month=1;
         if(lcd_key == btnDOWN) if(ds_month >1) ds_month--; else ds_month=12;
        break;
      case 6:lcd.setCursor(pozznak[6]+3, pozriadok[6]);      // ak je rok
         if(lcd_key == btnUP) if(ds_year <100) ds_year++; else ds_year=10;
         if(lcd_key == btnDOWN) if(ds_year >10) ds_year--; else ds_year=100;
        break;
     }
//------------------------                // zistenie dna v tyzdni z datumu
if(poscursor >=4 && poscursor <=6){       // ak sa meni datum
setTime(ds_hour,ds_minute,ds_second,ds_day,ds_month,ds_year+2000);    // nacitaj hodnoty do setTime a vrat denv
if (weekday()==1) ds_weekday=(weekday()+6);      // problem kniznice - nedela DOV()=1,po2 ut3 u DS1307 je to ne7, po1, ut2
else ds_weekday= (weekday()-1);                  // nastavenie dna v tyzdni
}
//------------------------

  lcd.blink();                                                 // blika kurzor
}                                        // koniec while
//-------------------------       // koniec nastavcas a ukladanie
lcd.noCursor();                            //vypni kurzor
lcd.noBlink();                              // vypni blikanie
//--------------------------
//Nastavenie casu a zapis do RAM zaznam o oprave
if (utek==0){                              // utek =1 bez ulozenia utek=0 nastavenie casu a zapis korekcie
setTimeDs();
log_change_time();}                                              // uklada sa rok
}                                      // koniec nastavcas
//-----------------------------------------------------
void printDigits(int digits) {      // doplna nulu pred cislo, ak je menej ako 10
  if(digits < 10) lcd.print('0');
  lcd.print(digits);
}
//---------------------------------------------------------------
void print_denv(int digits)
{
char* chr_denv[] = {"xXx","Pon","Uto","Str","Stv","Pia","Sob","Ned"}; // zobrazovane udaje dow
if (digits>=1 && digits<=7) lcd.print(chr_denv[digits]);      //ak je dow v rozsahu 1-7 zobraz pon- ned
else lcd.print(chr_denv[0]);                                  // inak zobraz xXx
}
//------------------------------------------------------
void vypiscas()
{
if (millis() - timer > 1000) {   // zobraz cas kazdu sekundu (1000ms)
    getTimeDs();          // nacitanie casu
    lcd.setCursor(4, 0);
    printDigits(ds_hour);
    lcd.print(":");
    printDigits(ds_minute);
    lcd.print(":");
    printDigits(ds_second);
    lcd.setCursor(0, 1); 
    print_denv(ds_weekday);
    lcd.setCursor(6, 1);
    printDigits(ds_day);
    lcd.print(".");
    printDigits(ds_month);
    lcd.print(".");
    lcd.print(ds_year+2000);
   timer = millis();}
    }
//-----------------------------------------------------------------------------
void kor_rtc()
{
long cas_rozdiel=0;                  // rozdiel casu v sekundach od poslednej aktualizacie
long aktual_time_kor= 0;              // aktualny cas
long last_time_kor= 0;                // cas poslednej akt.
float nasobok = 0;                  // pocet pridavanych sekund
int kor_rtc_konst = 0;                  // pocet sekund, po ich uplynuti sa prida /uberie sekunda
//------------------------------        Nastaví cas na hodnotu zapisu casu poslednej korekcie
if (adj_sec_day !=0){
setTime(dsSramRead(adr_hod),dsSramRead(adr_min),dsSramRead(adr_sek),dsSramRead(adr_den),dsSramRead(adr_mes),dsSramRead(adr_rok)+2000);
last_time_kor=now();                                    // pocet sekud poslednej kor od 01.01.1970
setTime(ds_hour, ds_minute, ds_second, ds_day, ds_month, ds_year+2000);    // nastav aktualny cas z DS1307
aktual_time_kor= now();                                  // vypocitaj pocet sekund od 01.01.1970
cas_rozdiel= aktual_time_kor - last_time_kor;            // vypocíta pocet sekun medzi poslednou aktualizaciou a aktualnym casom

//------------------
kor_rtc_konst= 86400/adj_sec_day;              // vypocet po kolkych sekundach sa bude upravovat cas - 24h/adj_sec
if (cas_rozdiel > abs(kor_rtc_konst)){    // tu sa bude korigovat cas, ak je rozdiel od posled. aktual vecsi ako kor_rtc_konst
//---------                           zisti nasobok korekcie- pocet sekund
      nasobok = int(cas_rozdiel/kor_rtc_konst);    // vypocita nasobok
//------------------
         if (nasobok >0){                                       // ak je co upravovat
            adjustTime(nasobok);                               // nastav cas
//-----------------------
             ds_hour =hour(),                // nastav DS1307  cas
             ds_minute= minute();
              ds_second= second();
              if (weekday()==1) ds_weekday= weekday()+6;      // problem kniznice - nedela DOV()=1,po2 ut3 u DS1307 je to ne7, po1, ut2
              else ds_weekday= weekday()-1;            // nastavenie dna v tyzdni
              ds_day= day();
              ds_month= month();
              ds_year= year()-2000;
                setTimeDs();
//------------------------    zaznam o korekcii casu
         log_change_time();
        }
Serial.print("nasobok:");
Serial.println(nasobok) ;   
Serial.println(hour()) ; 
Serial.println(minute()) ;
//----------------------------             
Serial.println(hour()) ;
Serial.println(minute()) ;
Serial.println("Added a minute."); // send confirmation to the PC.
}
}              // EBD IF adj_sec_day....
}

//------------------------------------------------------
void log_change_time(){                      // zapise log do ram
          getTimeDs();
          dsSramWrite(adr_hod, ds_hour);                    // do RAM v RTC zapise cas a datum zmeny
          dsSramWrite(adr_min,ds_minute);                    // dalej sa tu bude ukladat cas korekcie hodin
          dsSramWrite(adr_sek,ds_second);
          dsSramWrite(adr_den,ds_day);
          dsSramWrite(adr_mes,ds_month);
          dsSramWrite(adr_rok,ds_year);
}
//------------------------------------------------------

//---------------------------------------------------------------------
void zapisreal(float real_val,int real_adress)    // prevedie real na pole[4] a zapise de eeprom na danu adresu
{
byte  *ArrayOfFourBytes;        // definicia pola
ArrayOfFourBytes = (byte*) & real_val;  // prevod real cisla na 4 bajty... 3 je najvyssi
i2c_eeprom_write_page( adr_24c32, real_adress, ArrayOfFourBytes, 4 );    // volanie zapisu
}
//---------------------------------------------------------------------
float citajreal(int real_adress){          // nacita pole[4] z eeprom a prevedie na real
byte  ArrayOfFourBytes[4];        // definicia pola
float real_val;
byte *bytPtr;
i2c_eeprom_read_buffer( adr_24c32, real_adress, ArrayOfFourBytes, 4); //citanie z eeprom
bytPtr = ( byte* ) &real_val;
  for ( byte i = 0; i < 4; i++ ) {
    *bytPtr = ArrayOfFourBytes[ i ];
    bytPtr++;}
return real_val;                // vrat real
}
//---------------------------------------------------------------------
  void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
    int rdata = data;
    do{delay(1);} while (millis()- timer_ee_write < 10);  // cakacka 10 ms, ak je treba
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddress >> 8)); // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.write(rdata);
    Wire.endTransmission();
    timer_ee_write = millis();     //znulovanie casovaca
  }
//---------------------------------------------------------------------
  // WARNING: address is a page address, 6-bit end will wrap around
  // also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
  void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
    do{delay(1);} while (millis()- timer_ee_write < 10);      // cakacka 10 ms, ak je treba
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddresspage >> 8)); // MSB
    Wire.write((int)(eeaddresspage & 0xFF)); // LSB
    byte c;
    for ( c = 0; c < length; c++) Wire.write(data[c]);
    Wire.endTransmission();
    timer_ee_write = millis();       //znulovanie casovaca
  }
//---------------------------------------------------------------------
  byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
    byte rdata = 0xFF;
    do{delay(1);} while (millis()- timer_ee_write < 10);   // cakacka 10 ms, ak je treba
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddress >> 8)); // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress,1);
    if (Wire.available()) rdata = Wire.read();
    return rdata;                  //vrati data
  }
//---------------------------------------------------------------------
    // maybe let's not read more than 30 or 32 bytes at a time!
  void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
    do{delay(1);} while (millis()- timer_ee_write < 10);   // cakacka 10 ms, ak je treba
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddress >> 8)); // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress,length);
    int c = 0;
    for ( c = 0; c < length; c++ ) if (Wire.available()) buffer[c] = Wire.read();
   }
//---------------------------------------------------------------------


Späť na Software