#include // komunikace pres I2C na pinech A4 a A5 char ridicikod; // prvni znak z prikazu zaslaneho z PC do Arduina byte pole[6]; // pole, do ktereho se pripravi 6 bajtu prectenych pres I2C byte rtc0; byte rtc1; byte rtc2; byte rtc3; byte rtc4; byte i2c_addr_eeprom; byte i2c_addr_rtc= 0x68; unsigned long adresa_eeprom; byte hodnota; void zapis_cas(byte hodnota0, byte hodnota1, byte hodnota2, byte hodnota3 ) { Wire.beginTransmission(i2c_addr_rtc); // I2C adresa sekundoveho citace Wire.write(0); // zacina se od nulteho registru Wire.write(hodnota0); // LSB Wire.write(hodnota1); Wire.write(hodnota2); Wire.write(hodnota3); // MSB Wire.write(0); // spusteni generatoru Wire.endTransmission(); } void precti_cas(void) { Wire.beginTransmission(i2c_addr_rtc); Wire.write(0); // zacina se od nulteho registru Wire.endTransmission(); Wire.requestFrom(i2c_addr_rtc,5); // precte 5 bajtu - pocinaje nultym registrem delay(10); pole[0] = Wire.read(); // LSB pole[1] = Wire.read(); pole[2] = Wire.read(); pole[3] = Wire.read(); // MSB pole[4] = Wire.read(); // test, jestli RTC bezi } void zapis_bajt(unsigned long adr, byte hodnota ) { if (adr <= 0xFFFF) // pro nizke adresy se pouziva prvni banka (block select bit = 0) { Wire.beginTransmission(0x50); // I2C adresa s obema adresovacimi vstupy v LOW } else // pro vysoke adresy se pouziva druha banka (block select bit = 1) { Wire.beginTransmission(0x51); // I2C adresa s obema adresovacimi vstupy v LOW adr = adr & 0xFFFF ; // odseknuti block select bitu (17.bit) } byte half_high = adr >> 8; byte half_low = adr & 0xff; Wire.write(half_high); // vysoky bajt ze 16-bitove adresy Wire.write(half_low); // nizky bajt ze 16-bitove adresy Wire.write(hodnota); Wire.endTransmission(); } byte precti_bajt(unsigned long adr) { if (adr <= 65535) // pro nizke adresy se pouziva prvni banka (block select bit = 0) { i2c_addr_eeprom = 0x50; // I2C adresa s obema adresovacimi vstupy v LOW Wire.beginTransmission(i2c_addr_eeprom); } else // pro vysoke adresy se pouziva druha banka (block select bit = 1) { i2c_addr_eeprom = 0x51; // I2C adresa s obema adresovacimi vstupy v LOW Wire.beginTransmission(i2c_addr_eeprom); // I2C adresa s obema adresovacimi vstupy v LOW adr = adr & 0xffff ; // odseknuti block select bitu (17.bit) } byte half_high = adr >> 8; byte half_low = adr & 0xff; Wire.write(half_high); // vysoky bajt ze 16-bitove adresy Wire.write(half_low); // nizky bajt ze 16-bitove adresy Wire.endTransmission(); Wire.requestFrom(i2c_addr_eeprom,1); // precte 1 bajt ze zadane adresy byte timeout = 100; while (Wire.available() == false and timeout > 0) { delay(2); timeout --; } if (timeout > 0) { hodnota = Wire.read(); } else { hodnota = NULL; } return hodnota; } // prepnuti do servisniho rezimu void prepni_servis(void) { pinMode(5,OUTPUT); // reset do ATtiny85 (pin c.1 v ATtiny) digitalWrite(5,LOW); // nejdriv se ATtiny zresetuje delay(200); digitalWrite(5,HIGH); pinMode(5,INPUT_PULLUP); pinMode(2,OUTPUT); // tlacitko 1 do ATtiny85 (pin c.2 v ATtiny) digitalWrite(2,LOW); // a pak se na 2,5 sekundy nasimuluje stisk tlacitka 1 delay(2500); digitalWrite(2,HIGH); pinMode(2,INPUT_PULLUP); } // prepnuti do normalniho rezimu (obycejny reset ATtiny) void prepni_normal(void) { pinMode(5,OUTPUT); // reset do ATtiny85 (pin c.1 v ATtiny) digitalWrite(5,LOW); delay(200); digitalWrite(5,HIGH); pinMode(5,INPUT_PULLUP); } //-------------------------------------------------------------- // prevod z celkovych sekund na dny, mesice, roky, hodiny, minuty a sekundy void sek_dmrhns(unsigned long celkove_sekundy) { // nastaveni delek mesicu ve 4-letem cyklu (zacina se prestupnym rokem 2000) // Le, Un, Br, Du, Kv, Ce, Cc, Sr, Za, Ri ,Li, Pr unsigned int delky[49] = {0, // nulty mesic neexistuje, ale musi byt nadefinovany 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, // prestupny rok (2000, 2004, 2008, ...) 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, // neprestupny rok (2001, 2005, 2009, ...) 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, // neprestupny rok (2002, 2006, 2010, ...) 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 // neprestupny rok (2003, 2007, 2011, ...) } ; byte sekundy = celkove_sekundy % 60; byte minuty = (celkove_sekundy / 60) % 60; byte hodiny = (celkove_sekundy / 60 / 60) % 24; unsigned int dny = (celkove_sekundy / 60 / 60 / 24); int roky = 2000; // pocita se od roku 2000 do roku 2099 - dal uz to nepujde, protoze rok 2100 neni prestupny byte mesice = 1; // pocitani mesicu zacina lednem - (cislo mesice 1 az 12 pro leden az prosinec) byte index = 1; // nastaveni ukazatele na prvni mesic v poli (bude ukazovat na jeden ze 48 mesicu) dny ++ ; // hned na zacatku je treba pripocitat jeden den while ( dny > delky[index]) // kdyz je zbytek dni vetsi, nez je celkovy pocet dni v aktualnim (indexovem) mesici ... { dny = dny - delky[index]; // ... odecti pocet dni, ktery je v aktualnim mesici ... mesice ++; // ... a zvetsi pocitadlo mesicu if (mesice == 13) // Kdyz je nasledujci mesic leden ... { mesice = 1; // ... nastav ho zpatky na 1 roky ++; // a pripocitej dalsi rok } index ++; // ukazatel na aktualne odecitany mesic se posune dal if (index == 49) // Kdyz ukazatel pretece pres 4 roky (pres 48 mesicu)... { index = 1; // ... vrati se na zacatek - na prvni mesic prestupneho roku } } // tady uz jen vytisknout vysledky (hodnoty casu doplnit o pripadne nuly) Serial.print(dny); Serial.print('.'); Serial.print(mesice); Serial.print('.'); Serial.print(roky); Serial.print(' '); if (hodiny < 10) { Serial.print('0'); } Serial.print (hodiny); Serial.print(':'); if (minuty < 10) { Serial.print('0'); } Serial.print (minuty); Serial.print(':'); if (sekundy < 10) { Serial.print('0'); } Serial.print (sekundy); } //-------------------------------------------------------------- void setup() { Serial.begin(9600); // spusteni serioveho portu Wire.begin(); pinMode(13,OUTPUT); // info LED pinMode(5,INPUT_PULLUP); // Tento pin muze byt pouzit pro reset ATtiny85. Na zacatku ale musi zustat v HIGH. pinMode(2,INPUT_PULLUP); // Tento pin muze byt pouzit pro simulaci tlacitka 1 na ATtiny85. Na zacatku ale musi zustat v HIGH. } void loop() { if (Serial.available() > 2) // test, jestli zvenku uz prisly 3 bajty (napr 'R', 10, 50) { ridicikod = Serial.read(); unsigned int prectena_adresa = Serial.read() * 256; prectena_adresa = prectena_adresa + Serial.read(); if (ridicikod == 'R') { adresa_eeprom = prectena_adresa + 65536; pole[0] = precti_bajt(adresa_eeprom); Serial.write(pole[0]); } if (ridicikod == 'r') // kdyz je prvni znak v prijate komunikaci 'r', bude se vracet pole dat od zadane adresy z nízké banky { adresa_eeprom = prectena_adresa; pole[0] = precti_bajt(adresa_eeprom); Serial.write(pole[0]); } if (ridicikod == 'W') // kdyz je prvni znak v prijate komunikaci 'W', bude se zapisovat do horni poloviny EEPROM (65536 - 131071) { while (Serial.available() < 1) { delay(10); } hodnota = Serial.read(); adresa_eeprom = prectena_adresa + 65536; zapis_bajt(adresa_eeprom, hodnota); } if (ridicikod == 'w') // kdyz je prvni znak v prijate komunikaci 'w', bude se zapisovat do spodni poloviny EEPROM (0-65535) { while (Serial.available() < 1) { delay(10); } hodnota = Serial.read(); adresa_eeprom = prectena_adresa; zapis_bajt(adresa_eeprom, hodnota); } if (ridicikod == 'Z') // kdyz je prvni znak v prijate komunikaci 'Z', bude se zjistovat pocet zaznamenanych udaju { unsigned int pocet = 0; for (adresa_eeprom = 10; adresa_eeprom < 131065; adresa_eeprom = adresa_eeprom +6) { hodnota = precti_bajt(adresa_eeprom); if ((hodnota & 0b11000000) != 0b10000000) { break; } else { pocet ++; } } pole[0] = (pocet >> 8); pole[1] = (pocet & 0x00FF); Serial.write(pole[0]); Serial.write(pole[1]); } if (ridicikod == 't') // kdyz je prvni znak v prijate komunikaci 't', zapise se do RTC hodnota prectenych bajtu { pole[0] = (prectena_adresa >> 8); pole[1] = (prectena_adresa & 0x00FF); while (Serial.available() < 2) { delay(10); } pole[2] = Serial.read(); pole[3] = Serial.read(); zapis_cas(pole[0], pole[1], pole[2], pole[3]); delay(5); pole[4] = 66; // ukoncovaci znacka 'B' // pole se po jednotlivych bajtech posle komunikaci do Excelu for (byte i = 0; i<5 ; i++) { Serial.write(pole[i]); } } if (ridicikod == 'T') // kdyz je prvni znak v prijate komunikaci T', jen se vrati aktualni obsah RTC { delay(10); precti_cas(); delay(5); // pole se po jednotlivych bajtech posle komunikaci do Excelu for (byte i = 0; i<5 ; i++) { Serial.write(pole[i]); } } if (ridicikod == 'U' && prectena_adresa == 18756) // kdyz jsou znaky v prijate komunikaci 'U' 'I' 'D', zapise na prvnich 10 adres identifikaci { while (Serial.available() < 10) { delay(10); } for (adresa_eeprom = 0 ; adresa_eeprom < 10 ; adresa_eeprom ++) { byte znak_id = Serial.read(); zapis_bajt(adresa_eeprom, znak_id ); delay(5); } } if (ridicikod == '?' && prectena_adresa == 18756) // kdyz jsou znaky v prijate komunikaci '?' 'I' 'D', precte se identifikace z prvnich 10 adres { for (adresa_eeprom = 0 ; adresa_eeprom < 10 ; adresa_eeprom ++) { pole[0] = precti_bajt(adresa_eeprom); Serial.write(pole[0]); delay(5); } } if (ridicikod == 'S') // kdyz je prvni znak v prijate komunikaci 'S' odesle se jeden zaznam (6 po sobe jdoucich bajtu) { // v tomhle pripade je v promenne "prectena_adresa" poradove cislo zaznamu a je treba z nej spocitat adresu prvniho bajtu prislusneho zaznamu // prvni bajt zaznamu c. 1 je na adrese 10; prvni bajt zaznamu c. 2 je na adrese 16 ..... adresa_eeprom = (6 * prectena_adresa) + 4; pole[0] = precti_bajt(adresa_eeprom); // tlacitka a stav RTC (bezi/stoji) Serial.write(pole[0]); delay(5); pole[0] = precti_bajt(adresa_eeprom + 1); // cas Serial.write(pole[0]); delay(5); pole[0] = precti_bajt(adresa_eeprom + 2); // cas Serial.write(pole[0]); delay(5); pole[0] = precti_bajt(adresa_eeprom + 3); // cas Serial.write(pole[0]); delay(5); pole[0] = precti_bajt(adresa_eeprom + 4); // cas Serial.write(pole[0]); delay(5); pole[0] = precti_bajt(adresa_eeprom + 5); // teplota Serial.write(pole[0]); delay(5); } if (ridicikod == 's' && prectena_adresa == 25970) // kdyz je prijaty kod 's' 'e' 'r', prepne zaznamnik do "Servisiho rezimu" { prepni_servis(); } if (ridicikod == 'n' && prectena_adresa == 28530) // kdyz je prijaty kod 'n' 'o' 'r', prepne zaznamnik do "Normalniho rezimu" { // jen obycejny reset ATtiny prepni_normal(); } if (ridicikod == 'c' && prectena_adresa == 29558) // kdyz je prijaty kod 'c' 's' 'v', postupne posle zaznamy do terminalu v citelnem tvaru s oddelenim pomoci ';' a { prepni_servis(); // nejdriv odesle identifikaci (prvnich 10 bajtu) s koncem radky for (adresa_eeprom = 0; adresa_eeprom < 10; adresa_eeprom ++) { hodnota = precti_bajt(adresa_eeprom); Serial.write(hodnota); } Serial.write(13); Serial.write(10); // pak uz jen prochazi EEPROM po blocich dlouhych 6 bajtu, a kdyz je tam nejaky zaznam, tak se odesle na seriovy port for (adresa_eeprom = 10; adresa_eeprom < 131065; adresa_eeprom = adresa_eeprom +6) { byte stavy = precti_bajt(adresa_eeprom); // tlacitka, znamenko a setiny teploty, stav RTC if ((stavy & 0b11000000) != 0b10000000) { break; } else { Serial.print(stavy); Serial.write(';'); pole[1] = precti_bajt(adresa_eeprom + 1); Serial.print(pole[1]); Serial.write(';'); pole[2] = precti_bajt(adresa_eeprom + 2); Serial.print(pole[2]); Serial.write(';'); pole[3] = precti_bajt(adresa_eeprom + 3); Serial.print(pole[3]); Serial.write(';'); pole[4] = precti_bajt(adresa_eeprom + 4); Serial.print(pole[4]); Serial.write(';'); pole[5] = precti_bajt(adresa_eeprom + 5); // teplota Serial.print(pole[5]); Serial.write(';'); byte zaokr_tep = 0; if ((pole[5] & 0b00000010) != 0) // zaokrouhlovani vysledku prictenim jednicky { zaokr_tep = 1; } byte citelna_teplota = 0; char t_znamenko = ' '; if ((stavy & 0b00100000) == 0) // kladna teplota { citelna_teplota = (pole[5] >> 2) + zaokr_tep; t_znamenko = '+'; } else // zaporna teplota { citelna_teplota = ((255 - pole[5]) >> 2) - zaokr_tep + 1; t_znamenko = '-'; } Serial.print (t_znamenko); Serial.print (citelna_teplota); Serial.print ("'C;"); unsigned long long_sekundy = pole[4]; long_sekundy = (long_sekundy << 8) + pole[3]; long_sekundy = (long_sekundy << 8) + pole[2]; long_sekundy = (long_sekundy << 8) + pole[1]; sek_dmrhns(long_sekundy); // prevod z celkovych sekund od 1.1.2000 na citelny format datumu (d.m.yyyy hh:nn:ss) // v podprogramu se provadi i odesilani citelneho retezce na seriovy port Serial.write(13); Serial.write(10); if ((adresa_eeprom % 1200) == 0) // kazdych 200 cyklu blikne LED na pinu 13 { digitalWrite(13,HIGH); delay(50); digitalWrite(13,LOW); delay(50); } } } prepni_normal(); } } }