OK

Při poskytování služeb nám pomáhají soubory cookie. Používáním našich služeb vyjadřujete souhlas s naším používáním souborů cookie. Více informací

Úvodní stránka » Arduino » Arduino v příkladech - XIV. díl - Displej a hodiny

Arduino v příkladech - XIV. díl - Displej a hodiny

K čemu je dobré měřit čas. To je na dlouhou debatu. U svých projektů ho hlavně využívám k časování spínání a ukládání logů. O tom toho bylo už napsáno dost, ale o nastavení času? To jsem nenašel.

Podáváme se nejen na to, jak zprovoznit modul času, ale i jak ho za provozu nastavovat za pomoci displeje. A nakonec, když už máme ten displej, který 99% času nepoužíváme, tak si na něm zobrazíme hodiny, ať nesvítí zbytečně. Také je tu důležitá informace ohledně jedné drobnosti, na kterou kolegové zapomínají.

Modul času

K dispozici máme dva. DS1307 a DS3231. Tyto hodinové moduly jsou zálohovány baterii CR2032, na nichž vydrží běžet roky. Mají vlastní EEPROM paměť, budík, nastavení formátu času a spoustu vychytávek. Jaký je mezi nimi rozdíl? Pokud pominu, dvacet korun, tak hlavní rozdíl je v přesnosti. Modul DS3231 je podstatně přesnější – odchylka je ve vteřinách za rok. Vyndal jsem jeden ze šuplíku, kde ležel dva roky. Odchylka 23 s, paráda. U modulu DS1307 podle umístění, může odchylka dosahovat až několika desítek minut ročně. Osobně používám DS3231, ale pokud máte ten druhý při pokojové teplotě, dá se s ním bez problémů také pracovat.

My se podíváme na práci s modulem DS3231.

Na co si dát pozor

Moduly se prodávají ve dvou verzích. Jedna s integrovaným nabíjením baterie a druhá bez tohoto nabíjení. Přestože Vám budou tvrdit, že je to zrovna ta verze bez nabíjení, vždy přišla ta s nabíjením. Pokud tedy nedáte do modulu nabíjecí baterii, nebo budete Arduino používat v bateriovém provozu, bude nezbytné udělat malou úpravu. Je potřeba na desce přerušit přívod z napájení k baterii, nebo vyjmout odpor 201 Ω, viz foto. Pro úsporu energie ještě můžete odstranit svítící diodu.

Zapojení

Pro naší ukázku budeme potřebovat Arduino UNO, SPI displej a modul času. Arduino máme, displej známe, modul má I2C zapojení (A4 na SDA a A5 na SCL) a 5V logiku. Adresa hodinového modulu je 0x68, adresa EEPROM je 0x57. U modulu DS3231 se dá adresa hodin změnit propojkami A0, A1 a A2.

Zobrazujeme čas

Nejdříve si ukážeme zprovoznění modulu bez displeje. Vystačíme si s instalovanými knihovnami. Program na úvod zjistí I2C adresu modulu, to aby jsme se s tím nemuseli mořit a začne vypisovat čas na serial monitor.

Nastavení času při prvním zprovoznění modulu je zapotřebí provést nastavením adjustment_time = true; a vyplněním hodnot do funkce setDS3231time. Čas už zůstane v modulu nastaven, pak vypněte funkci nahrání času změnou hodnoty adjustment_time = false;

//------------------------------------------------------------------
// inicializace zakladnich knihoven
#include <Wire.h> // inport knihovny I2C
//------------------------------------------------------------------
// promenne pro vyhledani adres hodinoveho modulu
byte error; // prommena pro zobrazeni chyby
int nDevices = 0; // promenna pro vyhledavani poctu zarizeni
//------------------------------------------------------------------
// promenne pro zobrazeni casu
#define DS3231_I2C_ADDRESS 0x68
byte second;
byte minute;
byte hour;
byte dayOfWeek;
byte dayOfMonth;
byte month;
byte year;
//------------------------------------------------------------------
// povoleni nahrani aktualniho casu
boolean adjustment_time = false;
//------------------------------------------------------------------
// spusteni programu
void setup() {
  Wire.begin(); // inicializace knihovny I2C
  Serial.begin(9600); // nastaveni rychlosti seriove komunikace
  //------------------------------------------------------------------
  // vyhledani adresy hodinoveho modulu
  Serial.println("Skenuji...");
  for (byte address = 0; address < 127; address++ ) { // prochazeni povolenych adres
    Wire.beginTransmission(address); // volani adresy
    error = Wire.endTransmission(); // ukonceni volani
    if (error == 0) { // kdyz je vracena hodnota false, zobrazi nalezenou adresu
      Serial.print("I2C zarizeni nalezeno na adrese 0x");
      if (address < 16) Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");
      nDevices++;
    }
    else if (error == 4) { // kdyz je vracena hodnota true, zobrazi chybu hledani
      Serial.print("Neznama chyba na adrese 0x");
      if (address < 16) Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  // zobrazeni poctu nalezenych zarizeni
  if (nDevices == 0) Serial.println("Zadne zarizeni nenalezeno");
  else {
    Serial.print("Nalezeno ");
    Serial.print(nDevices);
    Serial.println(" I2C zarizeni.");
  }
  //------------------------------------------------------------------
  // nastaveni casu pri prvnim spusteni
  // DS3231 seconds, minutes, hours, day, date, month, year
  if (adjustment_time) setDS3231time(30, 42, 21, 4, 26, 11, 14);
}
//------------------------------------------------------------------
// hlavni smycka
void loop() {
  readDS3231time(); // precti cas a uloz promenne
  displayTime(); // zobraz aktualni cas,
  delay(1000); // pockej vterinu
}
//------------------------------------------------------------------
// ulozeni casu
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) { // uloz data do DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS); // otevri komunikaci
  Wire.write(0); // nastav prvni hodnotu registru pred zapisem
  Wire.write(decToBcd(second)); // uloz vteriny
  Wire.write(decToBcd(minute)); // uloz minuty
  Wire.write(decToBcd(hour)); // uloz hodiny
  Wire.write(decToBcd(dayOfWeek)); // uloz den tydne (1=Nedele, 7=Sobota)
  Wire.write(decToBcd(dayOfMonth)); // uloz den mesice (1-31)
  Wire.write(decToBcd(month)); // uloz mesic
  Wire.write(decToBcd(year)); // uloz rok (0 to 99)
  Wire.endTransmission(); // ukonci komunikaci
}
//------------------------------------------------------------------
// cteni casu
void readDS3231time() {
  Wire.beginTransmission(DS3231_I2C_ADDRESS); // otevri komunikaci
  Wire.write(0); // nastav prvni hodnotu registru pred ctenim
  Wire.endTransmission(); // ukonci komunikaci
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7); // precti 7 bytu
  // dotaz na data z DS3231 zaciname v registru 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());
}
//------------------------------------------------------------------
// zobraz data z hodinoveho modulu
void displayTime() {
  Serial.print(hour, DEC);
  Serial.print(":");
  if (minute < 10) {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second < 10) {
    Serial.print("0");
  }
  Serial.print(second, DEC);
  Serial.print(" ");
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print("20");
  Serial.print(year, DEC);
  Serial.print(" Den tydne: ");
  switch (dayOfWeek) {
    case 1:
      Serial.println("Nedele");
      break;
    case 2:
      Serial.println("Pondeli");
      break;
    case 3:
      Serial.println("Utery");
      break;
    case 4:
      Serial.println("Streda");
      break;
    case 5:
      Serial.println("Ctvrtek");
      break;
    case 6:
      Serial.println("Patek");
      break;
    case 7:
      Serial.println("Sobota");
      break;
  }
}
//------------------------------------------------------------------
// prevod jednotek pro ulozeni dat do hodinoveho modulu
byte decToBcd(byte val) {
  return ((val / 10 * 16) + (val % 10));
}
//------------------------------------------------------------------
// prevod jednotek pro cteni dat z hodinoveho modulu
byte bcdToDec(byte val) {
  return ((val / 16 * 10) + (val % 16));
}

Jednoduché a funkční s jednou malou nevýhodou, pokud nebudete mít po ruce počítač, čas nezměníte.

Nastavujeme čas

Teď tam přidáme ten displej. Po spuštění programu uvidíte běžící hodiny. Mě osobně se to moc líbí. Po stisku displeje se Vám zobrazí nastavení času. Moc jsem tomu graficky nedal, ale funguje to.

Protože je program poněkud větší, najdete ho ke ztažení zde.

Teď už je program podstatně složitější. Využili jsme většinu toho, co jsme se od počátku naučili. Čas nejen zobrazujeme, ale v interakci s displejem i nastavujeme. Třeba změna letní na zimní. Dá se řešit i programově, ale to zabírá zase místo. Jsme na jednočipu, místa není nikdy dost.

Program je pečlivě popsaný a kdo to s modulem myslí vážně, vytáhne si co potřebuje. Co ale zmíním, že mimo práci s modulem času jsme si ukázali ještě jednu důležitou věc. A to je výpočet úhlů. Úžasná věc pro grafické zobrazení nastavení klapek, sklonu atd. V budoucnu se k tomu vrátíme.

Závěr

Program nám zabírá ¾ paměti Arduino Uno a to jsem původně chtěl šipky kreslit. Nevešlo se to tam. Prostě použité Arduino Uno není pro větší projekty s displejem moc vhodné. Řešení jsou dvě. Buď použijeme větší čip, anebo to co zabírá místo přesuneme přímo do displeje.

My se podíváme na druhou variantu a proto tímto článkem uzavřeme displeje na SPI a příště se podrobněji podíváme na displej Nextion, jak ho načal kolega.

JB

jaroslav.bohac@arduinotech.cz

Přidat komentář

Zvýrazněné položky jsou povinné.

Přehled komentářů

  1. Zálohování reálného času (Tomáš H., 27.12.2016 17:23:49) Odpovědět

    Dobrý den, zakoupil jsem zde před časem modul RTC DS1307 s 32K flash. Pochopil jsem, že při vložené baterii a bez externího napájení by čas interně v DS1307 měl normálně běžet. Mi čas běží jen při připojeném externím napájení. Po odpojení a opětovném připojení napájení je čas na té hodnotě, na které byl před odpojením. Tedy obvod si pamatuje poslední hodnotu času, ale neposouvá jej. Je to správně a já tuto funkci špatně pochopil nebo dělám něco špatně?


TOP produkty

Kontakt

Ing. Petr Foltýn
Kunčice pod Ondřejníkem 814, 73913
TOPlist