Arduino zegar na RTC DS3231
-
jacek
16/11/2017
- Informatyka
- 2891 czytań 0 komentarzy
Podłączenie RTC do Arduino jest banalne. Pamiętamy tylko o napięciu zasilania bo może ono być 3.3V lub 5V. Zegar RTC jest podłączany do magistrali I2C podobnie jak wyświetlacz LCD w naszym projekcie. One ze sobą nie kolidują, bo na tej magistrali możemy podpiąć znacznie więcej urządzeń. Muszą mieć tylko różne adresy. Aby je ustalić warto uruchomić specjalny program skaner I2C (wynik zobaczymy na "serialmonitorze"):
W naszym programie wpiszemy datę i czas początkowy do zegara ręcznie. W tym celu najpierw znajdujemy wiersz nr 40 z funkcją:
Teraz już możemy zmontować i uruchomić nasz zegar i wgrać oprogramowanie wyświetlające czas i temperaturę:
W naszym programie zdefiniowany jest symbol domku, by pokazać, że temperatura jest mierzona wewnątrz pomieszczenia, gdzie stoi zegar. Przydatna do tego jest strona do generowanie kodu binarnego takich i innych zaprojektowanych przez nas znaków - http://omerk.github.io/lcdchargen/.
W sekcji woid setup() zdeklarowany jest znak domku:
// -------------------------------------- // i2c_scanner // // Version 1 // This program (or code that looks like it) // can be found in many places. // For example on the Arduino.cc forum. // The original author is not know. // Version 2, Juni 2012, Using Arduino 1.0.1 // Adapted to be as simple as possible by Arduino.cc user Krodal // Version 3, Feb 26 2013 // V3 by louarnold // Version 4, March 3, 2013, Using Arduino 1.0.3 // by Arduino.cc user Krodal. // Changes by louarnold removed. // Scanning addresses changed from 0...127 to 1...119, // according to the i2c scanner by Nick Gammon // http://www.gammon.com.au/forum/?id=10896 // Version 5, March 28, 2013 // As version 4, but address scans now to 127. // A sensor seems to use address 120. // Version 6, November 27, 2015. // Added waiting for the Leonardo serial communication. // // // This sketch tests the standard 7-bit addresses // Devices with higher bit address might not be seen properly. // #include <Wire.h> void setup() { Wire.begin(); Serial.begin(9600); while (!Serial); // Leonardo: wait for serial monitor Serial.println("\nI2C Scanner"); } void loop() { byte error, address; int nDevices; Serial.println("Scanning..."); nDevices = 0; for(address = 1; address < 127; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address<16) Serial.print("0"); Serial.print(address,HEX); Serial.println(" !"); nDevices++; } else if (error==4) { Serial.print("Unknown error at address 0x"); if (address<16) Serial.print("0"); Serial.println(address,HEX); } } if (nDevices == 0) Serial.println("No I2C devices found\n"); else Serial.println("done\n"); delay(5000); // wait 5 seconds for next scan }
W naszym programie wpiszemy datę i czas początkowy do zegara ręcznie. W tym celu najpierw znajdujemy wiersz nr 40 z funkcją:
//setDS3231time(00,24,23,14,15,11,17);.Usuwamy komentarz i wpisujemy w miejsce liczb aktualne dane. Zapisujemy plik i wysyłamy przez USB do Arduino. Potem ponownie przywracamy komentarz i wysyłamy program do naszej płytki. Od teraz RTC będzie liczył czas sam, a my tylko będziemy pobierali jego wartości do wyświetlenia na ekranie LCD czy porcie szeregowym.
Teraz już możemy zmontować i uruchomić nasz zegar i wgrać oprogramowanie wyświetlające czas i temperaturę:
//Podłączenie pinów RTC3231 do Arduino Uno //RTC na I2C: (SDA) D-A4, (SCL) C-A5 //LCD na I2C z konwerterem do tych samych pinów jak RTC #include <DS3231.h> //https://github.com/jarzebski/Arduino-DS3231 #include <TimeLib.h> #include "Wire.h" #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x3f,16,2); // Ustawienie adresu ukladu na 0x3f #define DS3231_I2C_ADDRESS 0x68 DS3231 clock; RTCDateTime dt; // Konwersja liczby dziesiętnej do postaci binarnej byte decToBcd(byte val){ return( (val/10*16) + (val%10) ); } // Konwersja liczby binarnej do postaci dziesiętnej byte bcdToDec(byte val){ return( (val/16*10) + (val%16) ); } // symbol domku do temperatury http://omerk.github.io/lcdchargen/ byte customChar[8] = { 0b00100, 0b01110, 0b11111, 0b10101, 0b10101, 0b11111, 0b11111, 0b00000 }; void setup(){ Wire.begin(); Serial.begin(9600); // Ustawienie czasu w momencie inicjacji układu: // DS3231 seconds, minutes, hours, day (numer dnia tygodnia), date, month, year //setDS3231time(00,31,20,6,17,11,17); lcd.begin(16,2); //deklaracja wierszy wyświetlacza musi byc przed lcd.create.Char(0,customChar); lcd.createChar(0,customChar);// utworzenie znaku domka lcd.backlight(); // załączenie podświetlenia lcd.setCursor(0,0); lcd.print((char)0); lcd.print("Prosty zegar RTC na DS3231"); delay(1000); lcd.clear(); } void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year){ // ustawienie czasu i daty w DS3231 Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // określa, że następna wartość ma trafić do rejestru sekund Wire.write(decToBcd(second)); // ustawienie sekund Wire.write(decToBcd(minute)); // ustawienie minuty Wire.write(decToBcd(hour)); // ustawienie godziny Wire.write(decToBcd(dayOfWeek)); // ustawienie dnia tygodnia (1=niedziela, 7=sobota) Wire.write(decToBcd(dayOfMonth)); // ustawienie dnia (1-31) Wire.write(decToBcd(month)); // ustawienie miesiąca Wire.write(decToBcd(year)); // ustawienie roku (0-99) Wire.endTransmission(); } void readDS3231time(byte *second,byte *minute,byte *hour,byte *dayOfWeek,byte *dayOfMonth,byte *month,byte *year){ Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // ustawia rejestr DS3231 na 00h Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 7); // żąda 7 bajtów danych od modułu DS3231 począwszy od rejestru 00h *second = bcdToDec(Wire.read() & 0x7f); *minute = bcdToDec(Wire.read()); *hour = bcdToDec(Wire.read() & 0x3f); *dayOfWeek = bcdToDec(Wire.read()); *dayOfMonth = bcdToDec(Wire.read()); *month = bcdToDec(Wire.read()); *year = bcdToDec(Wire.read()); } void displayTime(){ byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; // retrieve data from DS3231 readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // Przekazanie danych do wyświetlenie w serial monitorze i do LCD // CZAS // Godziny // podczas wyświetlania konwertuje wartość zmiennej typu bitowego do postaci dziesiętnej Serial.print(hour, DEC); if (hour<10) { lcd.setCursor(0,0); lcd.print("0"); lcd.print(hour, DEC); } else { lcd.setCursor(0,0); lcd.print(hour, DEC); } Serial.print(":"); lcd.setCursor(2,0); lcd.print(":"); // Minuty //Serial.print(minute, DEC); if (minute<10) { Serial.print("0"); Serial.print(minute, DEC); lcd.setCursor(3,0); lcd.print("0"); lcd.print(minute, DEC); } else { lcd.setCursor(3,0); lcd.print(minute, DEC); Serial.print(minute, DEC); } Serial.print(":"); lcd.setCursor(5,0); lcd.print(":"); //Sekundy if (second<10){ Serial.print("0"); Serial.print(second, DEC); lcd.setCursor(6,0); lcd.print("0"); lcd.print(second, DEC); } else { Serial.print(second, DEC); lcd.setCursor(6,0); lcd.print(second, DEC); } // DATA Serial.print(" "); Serial.print(dayOfMonth, DEC); Serial.print("/"); Serial.print(month, DEC); Serial.print("/"); Serial.print("20"); Serial.print(year, DEC); lcd.setCursor(0,1); //lcd.print("0"); // Dzień if (dayOfMonth<10){ lcd.setCursor(0,1); lcd.print("0"); lcd.print(dayOfMonth, DEC); } else { lcd.setCursor(0,1); lcd.print(dayOfMonth, DEC); } lcd.print("."); // Miesiąc if (month<10){ lcd.setCursor(3,1); lcd.print("0"); lcd.print(month, DEC); } else { lcd.setCursor(3,1); lcd.print(month, DEC); } lcd.print("."); //Rok lcd.print("20"); if (year<10){ lcd.setCursor(8,1); lcd.print("0"); lcd.print(year, DEC); } else { lcd.setCursor(8,1); lcd.print(year, DEC); } Serial.print(" "); lcd.setCursor(11,1); switch(dayOfWeek){ case 1: Serial.println("Niedziela"); lcd.print("Nd"); break; case 2: Serial.println("Poniedzialek"); lcd.print("Pn"); break; case 3: Serial.println("Wtorek"); lcd.print("Wt"); break; case 4: Serial.println("Sroda"); lcd.print("Sr"); break; case 5: Serial.println("Czwartek"); lcd.print("Czw"); break; case 6: Serial.println("Piatek"); lcd.print("Pt"); break; case 7: Serial.println("Sobota"); lcd.print("So"); break; } } // temperatura z DS3231 void displayTemp(){ clock.forceConversion(); lcd.setCursor(9,0); lcd.print((char)0); lcd.print(clock.readTemperature(),1); lcd.print((char)223); lcd.print("C"); } void loop() { displayTime(); // wyświetlanie czasu rzeczywistego displayTemp(); // wyswietla temperature delay(1000); // odśwież co sekundę }
W naszym programie zdefiniowany jest symbol domku, by pokazać, że temperatura jest mierzona wewnątrz pomieszczenia, gdzie stoi zegar. Przydatna do tego jest strona do generowanie kodu binarnego takich i innych zaprojektowanych przez nas znaków - http://omerk.github.io/lcdchargen/.
W sekcji woid setup() zdeklarowany jest znak domku:
void setup(){ Wire.begin(); Serial.begin(9600); // Ustawienie czasu w momencie inicjacji układu: // DS3231 seconds, minutes, hours, day (numer dnia tygodnia), date, month, year //setDS3231time(00,31,20,6,17,11,17); lcd.begin(16,2); //deklaracja wierszy wyświetlacza musi byc przed lcd.create.Char(0,customChar); lcd.createChar(0,customChar);// utworzenie znaku domka lcd.backlight(); // załączenie podświetlenia lcd.setCursor(0,0); lcd.print((char)0); lcd.print("Prosty zegar RTC na DS3231"); delay(1000); lcd.clear(); }Tu znak ten miał nr 3 i musi on być taki sam jak w deklaracji w setup(). Ale można go sobie zmień w zakresie od 0 do 7. Z jakiegoś powodu na stronie kodera jest przykład użycia znaku w postaci lcd.write((uint8_t)3);, ale to nie działa i trzeba zrobić tak jak tu napisałem.
Dodaj komentarz
Zaloguj się, aby móc dodać komentarz.
Oceny
Tylko zarejestrowani użytkownicy mogą oceniać zawartość strony
Zaloguj się , żeby móc zagłosować.
Zaloguj się , żeby móc zagłosować.
Brak ocen. Może czas dodać swoją?