Domov, design, rekonstrukce, výzdoba.  Dvůr a zahrada.  Svýma rukama

Domov, design, rekonstrukce, výzdoba. Dvůr a zahrada. Svýma rukama

» Hodiny na mikrokontroléru AVR s DS1307. DIY hodinky s LED displejem DIY velké elektronické hodinky

Hodiny na mikrokontroléru AVR s DS1307. DIY hodinky s LED displejem DIY velké elektronické hodinky

V prodeji najdete mnoho různých modelů a možností elektronických digitálních hodinek, ale většina z nich je určena pro vnitřní použití, protože čísla jsou malá. Někdy je však nutné umístit hodiny na ulici – například na zeď domu, nebo na stadion, náměstí, tedy tam, kde je bude z velké dálky vidět mnoho lidí. K tomuto účelu byl vyvinut a úspěšně sestaven tento obvod velkých LED hodin, ke kterým můžete připojit (přes interní tranzistorové spínače) LED indikátory libovolné velikosti. Schematický diagram můžete zvětšit kliknutím na něj:

Popis hodin

  1. Hodinky. V tomto režimu je standardní typ zobrazení času. K dispozici je digitální korekce přesnosti hodin.
  2. Teploměr. V tomto případě zařízení měří teplotu místnosti nebo venkovního vzduchu z jednoho čidla. Rozsah od -55 do +125 stupňů.
  3. Ovládání napájení je zajištěno.
  4. Střídavě zobrazuje informace na indikátoru - hodiny a teploměr.
  5. Pro uložení nastavení a nastavení při ztrátě 220V se používá energeticky nezávislá paměť.


Základem zařízení je ATMega8 MK, který je blikat nastavením pojistek dle tabulky:

Řízení provozu a hodin

Při prvním zapnutí hodinek se na obrazovce objeví reklamní úvodní obrazovka, po které se přepnou na zobrazování času. Stisknutí tlačítka SET_TIME indikátor se bude pohybovat v kruhu z hlavního režimu:

  • režim zobrazení minut a sekund. Pokud v tomto režimu současně stisknete tlačítko PLUS A MÍNUS, pak se sekundy vynulují;
  • nastavení minut aktuálního času;
  • nastavení hodin aktuálního času;
  • symbol t. Nastavení doby zobrazení hodin;
  • symbol Ó. Zobrazení času symbolů indikace vnější teploty (out);
  • množství denní korekce přesnosti hodin. Symbol C a opravná hodnota. Nastavení limitů od -25 do 25 sec. Vybraná hodnota bude přidána nebo odečtena od aktuálního času každý den v 0 hodin 0 minut a 30 sekund. Pro více podrobností si přečtěte pokyny, které jsou v archivu s firmwarem a soubory plošných spojů.

Nastavení hodin

Při držení tlačítek PLUS/MÍNUS Provádíme zrychlené nastavování hodnot. Po změně jakéhokoli nastavení budou po 10 sekundách nové hodnoty zapsány do energeticky nezávislé paměti a odtud budou načteny při opětovném zapnutí napájení. Nová nastavení se projeví během instalace. Mikrokontrolér monitoruje přítomnost hlavního napájení. Po vypnutí je zařízení napájeno z interního zdroje. Schéma redundantního napájecího modulu je uvedeno níže:


Aby se snížila spotřeba proudu, indikátor, senzory a tlačítka se vypnou, ale hodiny samy pokračují v odpočítávání času. Jakmile se objeví síťové napětí 220V, obnoví se všechny indikační funkce.


Vzhledem k tomu, že zařízení bylo koncipováno jako velké LED hodiny, má dva displeje: velký LED - pro ulici a malý LCD - pro snadné nastavení hlavního displeje. Velký displej je umístěn několik metrů od řídící jednotky a je propojen dvěma kabely po 8 vodičích. Pro ovládání anod externího indikátoru se používají tranzistorové spínače podle schématu uvedeného v archivu. Autoři projektu: Alexandrovich & SOIR.

Existuje mnoho způsobů, jak sestavit elektronické hodinky vlastníma rukama: diagramy jsou široce prezentovány v literatuře a na internetu. Většina moderních implementací je založena na mikrokontrolérech. Realizace takových projektů často vyžaduje rozsáhlé praktické dovednosti a teoretické znalosti v oblasti elektroniky: schopnost používat specializovaný software, vytvářet desky plošných spojů doma pomocí leptání chloridem železitým a dobře pájet. Musíte mít také různé nástroje a zásoby.

Existuje však jednoduchý a cenově dostupný způsob, jak sestavit elektronické hodinky vlastníma rukama doma: použijte platformu Arduino. Jedná se o softwarový a hardwarový komplex speciálně navržený pro výuku základů programování a elektroniky. S pomocí Arduina může každý, dokonce i bez speciálního předchozího školení, postavit elektronické hodiny vlastníma rukama: schémata zapojení, inženýrské programy a dokonce ani páječka nejsou potřeba!

Spojení všech elektronických součástek se provádí na speciální kontaktní (“bezpájecí”) prkénce, která eliminuje riziko popálení, řezných ran a jiných zranění – proto můžete s designérem Arduina pracovat společně s dětmi. Vizuální způsob prezentace schématu zapojení vám pomůže vyhnout se chybám při sestavování zařízení.

Krok 1. Seznam komponent

K sestavení jednoduchých hodinek na LED matricích budete potřebovat pouze několik levných komponent:

  • platforma Arduino. Nejjednodušší modely budou stačit - nebo Micro;
  • kontaktní prkénko na krájení;
  • spojovací dráty pro prkénko;
  • Modul hodin reálného času Adafruit DS3231;
  • LED maticový modul 32x8 MAX7219;
  • dvě tlačítka.

K nahrání ovládacího programu do paměti budete potřebovat také osobní počítač a kabel USB-mini-USB. To je vše - není potřeba páječka, odstraňovače izolace, montážní nože a další profesionální nástroje: všechny operace se provádějí ručně. Možná je v některých případech výhodnější použít pinzetu, ale obejdete se bez ní.


Krok 2. Sestavení elektronického obvodu

Obvod elektronických hodin s LED displejem pomocí Arduina se bude zdát docela jednoduchý i pro nezkušené radioamatéry. K montáži je potřeba pouze několik vodičů. Tabulka připojení:

Modul Arduino → 32x8 MAX7219 LED matrice

Modul Arduino → hodiny reálného času Adafruit DS3231

Modul Arduino → tlačítka

D2 - tlačítko 1

D3 - tlačítko 2

Druhý pin tlačítek je připojen na GND.

Jen je třeba dávat pozor a pamatovat si, jak jsou kontaktní otvory na prkénku vzájemně spojeny. Následující schéma znázorňuje způsob vnitřního připojení kontaktních otvorů:


Dvě řady (1 a 4) na obou stranách jsou spojeny vodorovně - obvykle se používají jako napájecí vedení +5V a zem GND. Všechny vnitřní kontakty (2 a 3) jsou vertikálně uzavřeny. V tomto případě je obvodová deska rozdělena vertikálně i horizontálně na dvě symetrické části nezávislé na sobě. To umožňuje například sestavit dvě různá zařízení na jednu desku.

Schéma elektronických hodin s indikací LED, stejně jako uspořádání prvků na desce plošných spojů, je znázorněno na obrázku:

Pečlivě zkontrolujte, zda všechna připojení odpovídají zobrazenému schématu. Ujistěte se také, že jsou vodiče dobře zajištěny v kontaktních otvorech na desce plošných spojů.


Krok 3. Firmware Arduino

Jakmile je sestavení a testování obvodu dokončeno, můžete začít nahrávat řídicí program (nebo „firmware“) do paměti Arduino.


Chcete-li to provést, musíte nainstalovat bezplatné oficiální vývojové prostředí - . Dále budete potřebovat zdrojový kód projektu, který si můžete stáhnout níže v archivu se všemi knihovnami a skicou a pokud potřebujete skicu, můžete si ji zkopírovat samostatně:

//zahrnout knihovny: #include "LedControl.h" #include // Knihovna písem #include // Hodiny DS1307 #include "RTClib.h" // Hodiny DS1307 #include // Knihovna tlačítek od Alexandra Breviga // Setup LED Matrix // pin 12 je připojen k DataIn na displeji // pin 11 je připojen k CLK na displeji // pin 10 je připojen k LOAD na displeji LedControl lc = LedControl(6, 5, 4, 4); //nastaví 3 piny jako 12, 11 & 10 a poté nastaví 4 displeje (max je 8 displejů) //globální proměnné byte intenzita = 7; // Výchozí intenzita/jas (0-15) byte clock_mode = 0; // Výchozí režim hodin. Výchozí = 0 (základní_režim) bool random_mode = 0; // Definovat náhodný režim - mění typ zobrazení každých několik hodin. Výchozí = 0 (vypnuto) byte old_mode = clock_mode; // Uloží předchozí režim hodin, takže pokud přejdeme na datum nebo cokoli jiného, ​​víme, do jakého režimu se vrátit. bool ampér/min = 0; // Definujte 12 nebo 24 hodinový čas. 0 = 24 hodin. 1 = 12 hodin byte change_mode_time = 0; // Podrží hodinu, kdy se režim hodin příště změní v náhodném režimu. dlouhé zpoždění bez znaménka = 500; // Mezi aktualizacemi zobrazení vždy chvíli čekáme int rtc; // Podrží výstup hodin reálného času char days = ( "Ne", "Po", "Út", "St", "Čt", "Pá", "So" ); //denní pole - používá se v režimech slide, basic_mode a mix mode (DS1307 vydává 1-7 hodnot pro den v týdnu) char daysfull = ( "Neděle", "Pondělí", "Úterý", "St", "Čtvrtek" ", "pátek", "sobota"); přípona char = ("st", "nd", "rd", "th"); //datové pole přípon, používané v režimech slide, basic_mode a jumble. např. 1st 2nd ... //definujte konstanty #define NUM_DISPLAY_MODES 3 // Režimy zobrazení čísel (první režim obsahuje nulu) #define NUM_SETTINGS_MODES 4 // Režimy nastavení čísel = 6 (první režim obsahuje nulu) # define SLIDE_DELAY 20 // Čas v milisekundách pro efekt snímku na znak v režimu snímku. Nastavte vyšší pro pomalejší efekt #define cls clear_display // Clear display RTC_DS1307 ds1307; // Vytvoření objektu RTC Button buttonA = Button(2, BUTTON_PULLUP); // Tlačítko nastavení A (pomocí knihovny tlačítek) Tlačítko tlačítkoB = Button(3, BUTTON_PULLUP); // Tlačítko nastavení B (pomocí knihovny tlačítek) void setup() ( digitalWrite(2, HIGH); // zapnutí pullup rezistoru pro tlačítko na kolíku 2 digitalWrite(3, HIGH); // zapnutí pullup odporu pro tlačítko na kolíku 3 digitalWrite(4, HIGH); // zapněte pullup rezistor pro tlačítko na kolíku 4 Serial.begin(9600); //spustí sériový provoz //inicializuje 4 maticové panely //při vytváření jsme již nastavili počet zařízení the LedControl int devices = lc.getDeviceCount(); //musíme inicializovat všechna zařízení ve smyčce pro (int address = 0; address< devices; address++) { /*The MAX72XX is in power-saving mode on startup*/ lc.shutdown(3-address, false); /* Set the brightness to a medium values */ lc.setIntensity(3-address, intensity); /* and clear the display */ lc.clearDisplay(3-address); } //Setup DS1307 RTC #ifdef AVR Wire.begin(); #else Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino #endif ds1307.begin(); //start RTC Clock if (! ds1307.isrunning()) { Serial.println("RTC is NOT running!"); ds1307.adjust(DateTime(__DATE__, __TIME__)); // sets the RTC to the date & time this sketch was compiled } //Show software version & hello message printver(); //enable red led digitalWrite(13, HIGH); } void loop() { //run the clock with whatever mode is set by clock_mode - the default is set at top of code. switch (clock_mode){ case 0: basic_mode(); break; case 1: small_mode(); break; case 2: slide(); break; case 3: word_clock(); break; case 4: setup_menu(); break; } } //plot a point on the display void plot (byte x, byte y, byte val) { //select which matrix depending on the x coord byte address; if (x >= 0 && x<= 7) { address = 3; } if (x >= 8 && x<= 15) { address = 2; x = x - 8; } if (x >= 16 && x<= 23) { address = 1; x = x - 16; } if (x >= 24 && x<= 31) { address = 0; x = x - 24; } if (val == 1) { lc.setLed(address, y, x, true); } else { lc.setLed(address, y, x, false); } } //clear screen void clear_display() { for (byte address = 0; address < 4; address++) { lc.clearDisplay(address); } } //fade screen down void fade_down() { //fade from global intensity to 1 for (byte i = intensity; i >0; i--) ( pro (adresa bajtu = 0; adresa< 4; address++) { lc.setIntensity(address, i); } delay(30); //change this to change fade down speed } clear_display(); //clear display completely (off) //reset intentsity to global val for (byte address = 0; address < 4; address++) { lc.setIntensity(address, intensity); } } //power up led test & display software version number void printver() { byte i = 0; char ver_a = "MADE"; char ver_b = "IN"; char ver_c = "RUSSIA"; //test all leds. for (byte x = 0; x <= 32; x++) { for (byte y = 0; y <= 7; y++) { plot(x, y, 1); } } delay(300); fade_down(); while (ver_a[i]) { puttinychar((i * 4), 1, ver_a[i]); delay(35); i++; } delay(500); fade_down(); i = 0; while (ver_b[i]) { puttinychar((i * 4), 1, ver_b[i]); delay(35); i++; } delay(500); fade_down(); i = 0; while (ver_c[i]) { puttinychar((i * 4), 1, ver_c[i]); delay(35); i++; } delay(500); fade_down(); } // puttinychar // Copy a 3x5 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate // This is unoptimized and simply uses plot() to draw each dot. void puttinychar(byte x, byte y, char c) { byte dots; if (c >= "A" && c<= "Z" || (c >= "a" && c<= "z")) { c &= 0x1F; // A-Z maps to 1-26 } else if (c >= "0" && c<= "9") { c = (c - "0") + 32; } else if (c == " ") { c = 0; // space } else if (c == ".") { c = 27; // full stop } else if (c == ":") { c = 28; // colon } else if (c == "\"") { c = 29; // single quote mark } else if (c == "!") { c = 30; // single quote mark } else if (c == "?") { c = 31; // single quote mark } for (byte col = 0; col < 3; col++) { dots = pgm_read_byte_near(&mytinyfont[c]); for (char row = 0; row < 5; row++) { if (dots & (16 >> řádek)) plot(x + sloupec, y + řádek, 1); else plot(x + sloupec, y + řádek, 0); ) ) ) void putnormalchar (bajt x, byte y, char c) ( bajt tečky; // if (c >= "A" && c<= "Z" || (c >= "a" && c<= "z")) { // c &= 0x1F; // A-Z maps to 1-26 // } if (c >= "A" && c<= "Z") { c &= 0x1F; // A-Z maps to 1-26 } else if (c >= "a" && c<= "z") { c = (c - "a") + 41; // A-Z maps to 41-67 } else if (c >= "0" && c<= "9") { c = (c - "0") + 31; } else if (c == " ") { c = 0; // space } else if (c == ".") { c = 27; // full stop } else if (c == "\"") { c = 28; // single quote mark } else if (c == ":") { c = 29; // clock_mode selector arrow } else if (c == ">") ( c = 30; // šipka výběru režimu hodin ) else if (c >= -80 && c<= -67) { c *= -1; } for (char col = 0; col < 5; col++) { dots = pgm_read_byte_near(&myfont[c]); for (char row = 0; row < 7; row++) { //check coords are on screen before trying to plot //if ((x >= 0) && (x<= 31) && (y >= 0) && (y<= 7)){ if (dots & (64 >> řádek)) ( // pouze 7 řádků. plot(x + sloupec, y + řádek, 1); ) else ( plot(x + sloupec, y + řádek, 0); ) //) ) ) ) //small_mode //zobrazení času v malých 3x5 znacích se sekundami display void small_mode() ( char textchar; // 16 znaků na displeji byte mins = 100; //mins byte secs = rtc; //seconds byte old_secs = secs; / /uchová hodnotu starých sekund – od poslední aktualizace sekund o display – používá se ke kontrole, zda se sekundy změnily cls(); //spustí hlavní smyčku hodin, dokud run_mode vrátí true while (run_mode()) ( get_time(); / /check for button press if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); return; ) //pokud došlo ke změně sekund, aktualizujte je na displeji secs = rtc; if (secs != old_secs) ( //secs char buffer; itoa(secs, buffer, 10); //fix - jinak pokud num má úvodní nulu, např. "03" s, itoa to pokryje znaky s mezerou "3". if (sek< 10) { buffer = buffer; buffer = "0"; } puttinychar(20, 1, ":"); //seconds colon puttinychar(24, 1, buffer); //seconds puttinychar(28, 1, buffer); //seconds old_secs = secs; } //if minute changes change time if (mins != rtc) { //reset these for comparison next time mins = rtc; byte hours = rtc; if (hours > < 1) { hours = hours + ampm * 12; } //byte dow = rtc; // the DS1307 outputs 0 - 6 where 0 = Sunday0 - 6 where 0 = Sunday. //byte date = rtc; //set characters char buffer; itoa(hours, buffer, 10); //fix - as otherwise if num has leading zero, e.g. "03" hours, itoa coverts this to chars with space "3 ". if (hours < 10) { buffer = buffer; //if we are in 12 hour mode blank the leading zero. if (ampm) { buffer = " "; } else { buffer = "0"; } } //set hours chars textchar = buffer; textchar = buffer; textchar = ":"; itoa (mins, buffer, 10); if (mins < 10) { buffer = buffer; buffer = "0"; } //set mins characters textchar = buffer; textchar = buffer; //do seconds textchar = ":"; buffer; secs = rtc; itoa(secs, buffer, 10); //fix - as otherwise if num has leading zero, e.g. "03" secs, itoa coverts this to chars with space "3 ". if (secs < 10) { buffer = buffer; buffer = "0"; } //set seconds textchar = buffer; textchar = buffer; byte x = 0; byte y = 0; //print each char for (byte x = 0; x < 6 ; x++) { puttinychar(x * 4, 1, textchar[x]); } } delay(50); } fade_down(); } // basic_mode() // show the time in 5x7 characters void basic_mode() { cls(); char buffer; //for int to char conversion to turn rtc values into chars we can print on screen byte offset = 0; //used to offset the x postition of the digits and centre the display when we are in 12 hour mode and the clock shows only 3 digits. e.g. 3:21 byte x, y; //used to draw a clear box over the left hand "1" of the display when we roll from 12:59 ->1:00 ve 12hodinovém režimu. //provede 12/24hodinový převod, pokud je ampm nastaveno na 1 byte hours = rtc; if (hodiny > 12) ( hodiny = hodiny - ampér * 12; ) if (hodiny< 1) { hours = hours + ampm * 12; } //do offset conversion if (ampm && hours < 10) { offset = 2; } //set the next minute we show the date at //set_next_date(); // initially set mins to value 100 - so it wll never equal rtc on the first loop of the clock, meaning we draw the clock display when we enter the function byte secs = 100; byte mins = 100; int count = 0; //run clock main loop as long as run_mode returns true while (run_mode()) { //get the time from the clock chip get_time(); //check for button press if (buttonA.uniquePress()) { switch_mode(); return; } if (buttonB.uniquePress()) { display_date(); return; } //check whether it"s time to automatically display the date //check_show_date(); //draw the flashing: as on if the secs have changed. if (secs != rtc) { //update secs with new value secs = rtc; //draw: plot (15 - offset, 2, 1); //top point plot (15 - offset, 5, 1); //bottom point count = 400; } //if count has run out, turn off the: if (count == 0) { plot (15 - offset, 2, 0); //top point plot (15 - offset, 5, 0); //bottom point } else { count--; } //re draw the display if button pressed or if mins != rtc i.e. if the time has changed from what we had stored in mins, (also trigggered on first entering function when mins is 100) if (mins != rtc) { //update mins and hours with the new values mins = rtc; hours = rtc; //adjust hours of ampm set to 12 hour mode if (hours >12) ( hodiny = hodiny - ampér * 12; ) if (hodiny< 1) { hours = hours + ampm * 12; } itoa(hours, buffer, 10); //if hours < 10 the num e.g. "3" hours, itoa coverts this to chars with space "3 " which we dont want if (hours < 10) { buffer = buffer; buffer = "0"; } //print hours //if we in 12 hour mode and hours < 10, then don"t print the leading zero, and set the offset so we centre the display with 3 digits. if (ampm && hours < 10) { offset = 2; //if the time is 1:00am clear the entire display as the offset changes at this time and we need to blank out the old 12:59 if ((hours == 1 && mins == 0)) { cls(); } } else { //else no offset and print hours tens digit offset = 0; //if the time is 10:00am clear the entire display as the offset changes at this time and we need to blank out the old 9:59 if (hours == 10 && mins == 0) { cls(); } putnormalchar(1, 0, buffer); } //print hours ones digit putnormalchar(7 - offset, 0, buffer); //print mins //add leading zero if mins < 10 itoa (mins, buffer, 10); if (mins < 10) { buffer = buffer; buffer = "0"; } //print mins tens and ones digits putnormalchar(19 - offset, 0, buffer); putnormalchar(25 - offset, 0, buffer); } } fade_down(); } //like basic_mode but with slide effect void slide() { byte digits_old = {99, 99, 99, 99}; //old values we store time in. Set to somthing that will never match the time initially so all digits get drawn wnen the mode starts byte digits_new; //new digits time will slide to reveal byte digits_x_pos = {25, 19, 7, 1}; //x pos for which to draw each digit at char old_char; //used when we use itoa to transpose the current digit (type byte) into a char to pass to the animation function char new_char; //used when we use itoa to transpose the new digit (type byte) into a char to pass to the animation function //old_chars - stores the 5 day and date suffix chars on the display. e.g. "mon" and "st". We feed these into the slide animation as the current char when these chars are updated. //We sent them as A initially, which are used when the clocl enters the mode and no last chars are stored. //char old_chars = "AAAAA"; //plot the clock colon on the display cls(); putnormalchar(13, 0, ":"); byte old_secs = rtc; //store seconds in old_secs. We compare secs and old secs. WHen they are different we redraw the display //run clock main loop as long as run_mode returns true while (run_mode()) { get_time(); //check for button press if (buttonA.uniquePress()) { switch_mode(); return; } if (buttonB.uniquePress()) { display_date(); return; } //if secs have changed then update the display if (rtc != old_secs) { old_secs = rtc; //do 12/24 hour conversion if ampm set to 1 byte hours = rtc; if (hours >12) ( hodiny = hodiny - ampér * 12; ) if (hodiny< 1) { hours = hours + ampm * 12; } //split all date and time into individual digits - stick in digits_new array //rtc = secs //array pos and digit stored //digits_new = (rtc%10); //0 - secs ones //digits_new = ((rtc/10)%10); //1 - secs tens //rtc = mins digits_new = (rtc % 10); //2 - mins ones digits_new = ((rtc / 10) % 10); //3 - mins tens //rtc = hours digits_new = (hours % 10); //4 - hour ones digits_new = ((hours / 10) % 10); //5 - hour tens //rtc = date //digits_new = (rtc%10); //6 - date ones //digits_new = ((rtc/10)%10); //7 - date tens //draw initial screen of all chars. After this we just draw the changes. //compare digits 0 to 3 (mins and hours) for (byte i = 0; i <= 3; i++) { //see if digit has changed... if (digits_old[i] != digits_new[i]) { //run 9 step animation sequence for each in turn for (byte seq = 0; seq <= 8 ; seq++) { //convert digit to string itoa(digits_old[i], old_char, 10); itoa(digits_new[i], new_char, 10); //if set to 12 hour mode and we"re on digit 2 (hours tens mode) then check to see if this is a zero. If it is, blank it instead so we get 2.00pm not 02.00pm if (ampm && i == 3) { if (digits_new == 0) { new_char = " "; } if (digits_old == 0) { old_char = " "; } } //draw the animation frame for each digit slideanim(digits_x_pos[i], 0, seq, old_char, new_char); delay(SLIDE_DELAY); } } } /* //compare date digit 6 (ones) and (7) tens - if either of these change we need to update the date line. We compare date tens as say from Jan 31 ->Feb 01, pak jedna číslice se nezmění, pokud ((digits_old != digits_new) || (digits_old != digits_new)) ( //změňte zobrazený den. Smyčka níže prochází postupně každý ze 3 znaků, např. "MON" pro (bajt day_char = 0; day_char<=2 ; day_char++){ //run the anim sequence for each char for (byte seq = 0; seq <=8 ; seq++){ //the day (0 - 6) Read this number into the days char array. the seconds number in the array 0-2 gets the 3 chars of the day name, e.g. m o n slideanim(6*day_char,8,seq,old_chars,days); //6 x day_char gives us the x pos for the char delay(SLIDE_DELAY); } //save the old day chars into the old_chars array at array pos 0-2. We use this next time we change the day and feed it to the animation as the current char. The updated char is fed in as the new char. old_chars = days; } //change the date tens digit (if needed) and ones digit. (the date ones digit wil alwaus change, but putting this in the "if" loop makes it a bit neater code wise.) for (byte i = 7; i >= 6; i--)( if (digits_old[i] != digits_new[i]) ( for (byte seq = 0; seq<=8 ; seq++){ itoa(digits_old[i],old_char,10); itoa(digits_new[i],new_char,10); slideanim(digits_x_pos[i],8,seq,old_char,new_char); delay(SLIDE_DELAY); } } } //print the day suffix "nd" "rd" "th" etc. First work out date 2 letter suffix - eg st, nd, rd, th byte s = 3; //the pos to read our suffix array from. byte date = rtc; if(date == 1 || date == 21 || date == 31) { s = 0; } else if (date == 2 || date == 22) { s = 1; } else if (date == 3 || date == 23) { s = 2; } for (byte suffix_char = 0; suffix_char <=1 ; suffix_char++){ for (byte seq = 0; seq <=8 ; seq++){ slideanim((suffix_char*6)+36,8,seq,old_chars,suffix[s]); // we pass in the old_char array char as the current char and the suffix array as the new char delay(SLIDE_DELAY); } //save the suffic char in the old chars array at array pos 3 and 5. We use these chars next time we change the suffix and feed it to the animation as the current char. The updated char is fed in as the new char. old_chars = suffix[s]; } }//end do date line */ //save digita array tol old for comparison next loop for (byte i = 0; i <= 3; i++) { digits_old[i] = digits_new[i]; } }//secs/oldsecs }//while loop fade_down(); } //called by slide //this draws the animation of one char sliding on and the other sliding off. There are 8 steps in the animation, we call the function to draw one of the steps from 0-7 //inputs are are char x and y, animation frame sequence (0-7) and the current and new chars being drawn. void slideanim(byte x, byte y, byte sequence, char current_c, char new_c) { // To slide one char off and another on we need 9 steps or frames in sequence... // seq# 0123456 <-rows of the display // | ||||||| // seq0 0123456 START - all rows of the display 0-6 show the current characters rows 0-6 // seq1 012345 current char moves down one row on the display. We only see it"s rows 0-5. There are at display positions 1-6 There is a blank row inserted at the top // seq2 6 01234 current char moves down 2 rows. we now only see rows 0-4 at display rows 2-6 on the display. Row 1 of the display is blank. Row 0 shows row 6 of the new char // seq3 56 0123 // seq4 456 012 half old / half new char // seq5 3456 01 // seq6 23456 0 // seq7 123456 // seq8 0123456 END - all rows show the new char //from above we can see... //currentchar runs 0-6 then 0-5 then 0-4 all the way to 0. starting Y position increases by 1 row each time. //new char runs 6 then 5-6 then 4-6 then 3-6. starting Y position increases by 1 row each time. //if sequence number is below 7, we need to draw the current char if (sequence < 7) { byte dots; // if (current_c >= "A" && || (current_c >= "a" && current_c<= "z")) { // current_c &= 0x1F; // A-Z maps to 1-26 // } if (current_c >= "A" && current_c<= "Z") { current_c &= 0x1F; // A-Z maps to 1-26 } else if (current_c >= "a" && current_c<= "z") { current_c = (current_c - "a") + 41; // A-Z maps to 41-67 } else if (current_c >= "0" && current_c<= "9") { current_c = (current_c - "0") + 31; } else if (current_c == " ") { current_c = 0; // space } else if (current_c == ".") { current_c = 27; // full stop } else if (current_c == "\"") { current_c = 28; // single quote mark } else if (current_c == ":") { current_c = 29; //colon } else if (current_c == ">") ( current_c = 30; // šipka výběru režimu hodin ) byte curr_char_row_max = 7 - sekvence; //maximální počet řádků k vykreslení je 6 - pořadové číslo byte start_y = sekvence; //y pozice pro začátek - je stejná jako pořadové číslo. Toto započítáváme každý cyklus //vykreslíme každý řádek až do maxima řádku (vypočteno z pořadového čísla) pro (byte curr_char_row = 0; curr_char_row<= curr_char_row_max; curr_char_row++) { for (byte col = 0; col < 5; col++) { dots = pgm_read_byte_near(&myfont); if (dots & (64 >> curr_char_row)) plot(x + col, y + start_y, 1); //vykreslení vedeno na else plot(x + col, y + start_y, 0); //else plot led off ) start_y++;//přidej jedničku k y, takže nakreslíme další řádek o jeden dolů ) ) //nakreslí prázdný řádek mezi znaky, pokud je sekvence mezi 1 a 7. Pokud to neuděláme, dostaneme zbytky aktuálních znaků na poslední pozici vlevo na displeji if (sekvence >= 1 && sekvence<= 8) { for (byte col = 0; col < 5; col++) { plot(x + col, y + (sequence - 1), 0); //the y position to draw the line is equivalent to the sequence number - 1 } } //if sequence is above 2, we also need to start drawing the new char if (sequence >= 2) ( //vypracujte tečky char byte; //if (new_c >= "A" && new_c<= "Z" || (new_c >= "a" && new_c<= "z")) { // new_c &= 0x1F; // A-Z maps to 1-26 //} if (new_c >= "A" && new_c<= "Z") { new_c &= 0x1F; // A-Z maps to 1-26 } else if (new_c >= "a" && new_c<= "z") { new_c = (new_c - "a") + 41; // A-Z maps to 41-67 } else if (new_c >= "0" && new_c<= "9") { new_c = (new_c - "0") + 31; } else if (new_c == " ") { new_c = 0; // space } else if (new_c == ".") { new_c = 27; // full stop } else if (new_c == "\"") { new_c = 28; // single quote mark } else if (new_c == ":") { new_c = 29; // clock_mode selector arrow } else if (new_c == ">") ( new_c = 30; // šipka voliče režimu hodin ) bajt newcharrowmin = 6 - (sekvence - 2); //minimální číslo řádku pro vykreslení nového znaku - toto generuje výstup 6 až 0, když se naplní pořadová čísla 2-8 . Toto je minimální řádek pro vykreslení nového znakového bajtu start_y = 0; //y pozice pro začátek - je stejná jako pořadové číslo. každý řádek jej započítáváme //vykreslujeme každý řádek nahoru od minima řádku (vypočteno podle pořadového čísla ) až 6 for (byte newcharrow = newcharrowmin; newcharrow<= 6; newcharrow++) { for (byte col = 0; col < 5; col++) { dots = pgm_read_byte_near(&myfont); if (dots & (64 >> newcharrow)) plot(x + col, y + start_y, 1); //vykreslení vedeno na else plot(x + col, y + start_y, 0); //else plot led off ) start_y++;//přidej jedničku k y, takže nakreslíme další řádek o jeden dolů ) ) ) //vytiskne hodiny pomocí slov místo čísel void word_clock() ( cls(); char numbers = ( "jedna ", "dva", "tři", "čtyři", "pět", "šest", "sedm", "osm", "devět", "deset", "jedenáct", "dvanáct", "třináct", "čtrnáct", "patnáct", "šestnáct", "sedmnáct", "osmnáct", "devatenáct"); char numbertens = ( "deset", "dvacet", "třicet", "čtyřicet", "padesát"); //potenciálně 3 řádky pro zobrazení char str_a; char str_b; char str_c; //bajt hours_y, mins_y; //hodiny a minuty a pozice pro hodiny a minuty řádky byte hours = rtc; if (hodiny > 12) ( hodiny = hodiny - ampm * 12; ) if (hod< 1) { hours = hours + ampm * 12; } get_time(); //get the time from the clock chip byte old_mins = 100; //store mins in old_mins. We compare mins and old mins & when they are different we redraw the display. Set this to 100 initially so display is drawn when mode starts. byte mins; //run clock main loop as long as run_mode returns true while (run_mode()) { //check for button press if (buttonA.uniquePress()) { switch_mode(); return; } if (buttonB.uniquePress()) { display_date(); } get_time(); //get the time from the clock chip mins = rtc; //get mins //if mins is different from old_mins - redraw display if (mins != old_mins) { //update old_mins with current mins value old_mins = mins; //reset these for comparison next time mins = rtc; hours = rtc; //make hours into 12 hour format if (hours >12) ( hodiny = hodiny - 12; ) if (hodiny == 0) ( hodiny = 12; ) //rozdělit minimální hodnotu na dvě samostatné číslice int minsdigit = rtc % 10; byte minsdigitten = (rtc / 10) % 10; //pokud min<= 10 , then top line has to read "minsdigti past" and bottom line reads hours if (mins < 10) { strcpy (str_a, numbers); strcpy (str_b, "PAST"); strcpy (str_c, numbers); } //if mins = 10, cant use minsdigit as above, so soecial case to print 10 past /n hour. if (mins == 10) { strcpy (str_a, numbers); strcpy (str_b, " PAST"); strcpy (str_c, numbers); } //if time is not on the hour - i.e. both mins digits are not zero, //then make first line read "hours" and 2 & 3rd lines read "minstens" "mins" e.g. "three /n twenty /n one" else if (minsdigitten != 0 && minsdigit != 0) { strcpy (str_a, numbers); //if mins is in the teens, use teens from the numbers array for the 2nd line, e.g. "fifteen" //if (mins >= 11 && min<= 19) { if (mins <= 19) { strcpy (str_b, numbers); } else { strcpy (str_b, numberstens); strcpy (str_c, numbers); } } // if mins digit is zero, don"t print it. read read "hours" "minstens" e.g. "three /n twenty" else if (minsdigitten != 0 && minsdigit == 0) { strcpy (str_a, numbers); strcpy (str_b, numberstens); strcpy (str_c, ""); } //if both mins are zero, i.e. it is on the hour, the top line reads "hours" and bottom line reads "o"clock" else if (minsdigitten == 0 && minsdigit == 0) { strcpy (str_a, numbers); strcpy (str_b, "O"CLOCK"); strcpy (str_c, ""); } }//end worknig out time //run in a loop //print line a "twelve" byte len = 0; while (str_a) { len++; }; //get length of message byte offset_top = (31 - ((len - 1) * 4)) / 2; // //plot hours line byte i = 0; while (str_a[i]) { puttinychar((i * 4) + offset_top, 1, str_a[i]); i++; } //hold display but check for button presses int counter = 1000; while (counter >0)( //kontrola stisknutí tlačítka if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter--; ) fade_down (); //tisk řádku b len = 0; while (str_b) ( len++; ); //získání délky zprávy offset_top = (31 - ((délka - 1) * 4)) / 2; i = 0; while (str_b[i]) ( puttinychar((i * 4) + offset_top, 1, str_b[i]); i++; ) //podržet zobrazení, ale zkontrolovat počítadlo stisknutí tlačítka = 1000; while (counter > 0)( if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter--; ) fade_down() ; //vytiskne řádek c, pokud existuje. len = 0; while (str_c) ( len++; ); //získání délky zprávy offset_top = (31 - ((délka - 1) * 4)) / 2; i = 0; while (str_c[i]) ( puttinychar((i * 4) + offset_top, 1, str_c[i]); i++; ) čítač = 1000; while (counter > 0)( //kontrola stisknutí tlačítka if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter- -; ) fade_down(); //podržte displej prázdný, ale před dalším spuštěním zkontrolujte, zda nedošlo ke stisknutí tlačítka. čítač = 1000; while (counter > 0)( //kontrola stisknutí tlačítka if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) delay(1); counter- -; ) ) fade_down(); ) /// rolovací zpráva - v současnosti se nepoužívá - příliš pomalá. void scroll() ( char message = ("Ahoj"); cls(); byte p = 6; //aktuální pozice v řetězci byte chara = (0, 1, 2, 3, 4, 5); //znaky z řetězce int x = (0, 6, 12, 18, 24, 30); //xpos pro každý znakový bajt y = 0; //y pos // clear_buffer(); while (zpráva[p] != "\ 0") ( //nakreslete všech 6 znaků pro (bajt c = 0; c< 6; c++) { putnormalchar(x[c],y,message[ chara[c] ]); //draw a line of pixels turned off after each char,otherwise the gaps between the chars have pixels left in them from the previous char for (byte yy = 0 ; yy < 8; yy ++) { plot(x[c] + 5, yy, 0); } //take one off each chars position x[c] = x[c] - 1; } //reset a char if it"s gone off screen for (byte i = 0; i <= 5; i++) { if (x[i] < -5) { x[i] = 31; chara[i] = p; p++; } } } } //display_date - print the day of week, date and month with a flashing cursor effect void display_date() { cls(); //read the date from the DS1307 byte dow = rtc; // day of week 0 = Sunday byte date = rtc; byte month = rtc - 1; //array of month names to print on the display. Some are shortened as we only have 8 characters across to play with char monthnames = { "January", "February", "March", "April", "May", "June", "July", "August", "Sept", "October", "November", "December" }; //print the day name //get length of text in pixels, that way we can centre it on the display by divindin the remaining pixels b2 and using that as an offset byte len = 0; while(daysfull) { len++; }; byte offset = (31 - ((len-1)*4)) / 2; //our offset to centre up the text //print the name int i = 0; while(daysfull[i]) { puttinychar((i*4) + offset , 1, daysfull[i]); i++; } delay(1000); fade_down(); cls(); // print date numerals char buffer; itoa(date,buffer,10); offset = 10; //offset to centre text if 3 chars - e.g. 3rd // first work out date 2 letter suffix - eg st, nd, rd, th etc // char suffix={"st", "nd", "rd", "th" }; is defined at top of code byte s = 3; if(date == 1 || date == 21 || date == 31) { s = 0; } else if (date == 2 || date == 22) { s = 1; } else if (date == 3 || date == 23) { s = 2; } //print the 1st date number puttinychar(0+offset, 1, buffer); //if date is under 10 - then we only have 1 digit so set positions of sufix etc one character nearer byte suffixposx = 4; //if date over 9 then print second number and set xpos of suffix to be 1 char further away if (date >9)( suffixposx = 8; puttinychar(4+posun, 1, vyrovnávací paměť); offset = 8; //odsazení textu na střed, pokud jsou 4 znaky ) //vytiskne 2 znaky sufixu puttinychar(suffixposx+posun, 1, suffix[s ]); puttinychar(suffixposx+4+offset, 1, suffix[s]); zpoždění(1000); fade_down(); //vytiskne název měsíce //získáte délku textu v pixelech, takže jej můžeme vycentrovat na displeji rozdělením zbývajících pixelů b2 a použitím toho jako offsetu len ​​= 0; while(jména měsíců) ( len++; ); offset = (31 - ((délka-1)*4)) / 2; //naše odsazení pro vycentrování textu i = 0; while(jména měsíců[i]) ( puttinychar((i*4) +offset, 1, názvy měsíců[i]); i++; ) delay(1000); fade_down(); ) //dislpay menu pro změnu režimu hodin void switch_mode() ( //pamatujte si režim, ve kterém se nacházíme. Tuto hodnotu použijeme, pokud přejdeme do režimu nastavení, takže se můžeme vrátit zpět z režimu nastavení (6) do jakéhokoli režimu, ve kterém jsme byli in. old_mode = clock_mode; char* modes = ( "Základní", "Malý", "Slide", "Slova", "Nastavení" ); byte next_clock_mode; byte firstrun = 1; //smyčka čeká na tlačítko (časový limit po 35 smyčky pro návrat do režimu X) for (int count = 0; count< 35 ; count++) { //if user hits button, change the clock_mode if (buttonA.uniquePress() || firstrun == 1) { count = 0; cls(); if (firstrun == 0) { clock_mode++; } if (clock_mode >NUM_DISPLAY_MODES + 1) ( clock_mode = 0; ) //vytiskne šipku a název aktuálního režimu hodin na řádek jedna a vytiskne další název režimu hodin na řádek dva char str_top; //strcpy (str_top, "-"); strcpy(str_top, režimy); next_clock_mode = clock_mode + 1; if (režim_dalších_hodin > NUM_DISPLAY_MODES + 1) (režim_dalších_hodin = 0; ) byte i = 0; while (str_top[i]) ( putnormalchar(i * 6, 0, str_top[i]); i++; ) firstrun = 0; ) zpoždění(50); ) ) //spustí hlavní smyčku hodin tak dlouho, dokud run_mode vrátí true byte run_mode() ( //pokud je zapnutý náhodný režim... zkontrolujte hodinu, kdy změníme režim. if (random_mode) ( //pokud hodnota hodiny v režimu změny time = hours. then reurn false = tj. opustit režim. if (change_mode_time == rtc) ( //nastaví další náhodný režim hodin a čas pro jeho změnu set_next_random(); //ukončí aktuální režim. return 0; ) ) / /else return 1 - pokračujte v běhu v tomto režimu return 1; ) //nastaví další hodinu, kdy se hodiny změní režim, když je náhodný režim void set_next_random() ( //nastaví další hodinu, kdy se režim hodin změní - aktuální čas plus 1–4 hodiny get_time(); change_mode_time = rtc + random (1, 5); //pokud change_mode_time nyní překročí 23, pak jej nastavte na mezi 1 a 3:00, pokud (change_mode_time > 23) ( change_mode_time = random (1 , 4); ) //nastavení nového režimu hodin clock_mode = random(0, NUM_DISPLAY_MODES + 1); //výběr nového režimu náhodného hodin ) //zobrazení nabídky pro změnu nastavení hodin void setup_menu() ( char* set_modes = ( "Rndom", "24 Hr", "Nastavit", "Brght", "Exit"); if (ampm == 0) ( set_modes = ("12 Hr"); ) byte setting_mode = 0; byte next_setting_mode; byte firstrun = 1; //smyčka čeká na tlačítko (časový limit po 35 cyklech pro návrat do režimu X) for(int count=0; count< 35 ; count++) { //if user hits button, change the clock_mode if(buttonA.uniquePress() || firstrun == 1){ count = 0; cls(); if (firstrun == 0) { setting_mode++; } if (setting_mode >NUM_SETTINGS_MODES) ( setting_mode = 0; ) //vytiskne šipku a název aktuálního režimu hodin na řádek jedna a vytiskne další název režimu hodin na řádek dva char str_top; strcpy(str_top, set_modes); next_setting_mode = režim_nastavení + 1; if (režim_dalšího_nastavení > NUM_NASTAVENÍ_REŽIMŮ) (režim_dalšího_nastavení = 0; ) byte i = 0; while(str_top[i]) ( putnormalchar(i*6, 0, str_top[i]); i++; ) firstrun = 0; ) zpoždění(50); ) //vyberte přepínač režimu(setting_mode)( případ 0: set_random(); přestávka; případ 1: set_ampm(); přestávka; případ 2: set_time(); přestávka; případ 3: set_intensity(); přestávka; případ 4: //opuštění menu break; ) //změna hodin z režimu 6 (nastavení) zpět na ten, ve kterém byly před clock_mode=old_mode; ) //přepnout náhodný režim - každých pár hodin vybrat jiný režim hodin void set_random())( cls(); char text_a = "Vypnuto"; char text_b = "Zapnuto"; byte i = 0; //pokud je náhodný režim on , vypněte jej if (random_mode)( //vypne náhodný režim random_mode = 0; //vytiskne zprávu na displej while(text_a[i]) ( putnormalchar((i*6), 0, text_a[i] ) ; i++; ) ) else ( //zapnutí náhodného režimu. random_mode = 1; //nastavení hodinového režimu změní set_next_random(); //vytiskne zprávu na displej while(text_b[i]) ( putnormalchar((i * 6), 0, text_b[i]); i++; ) ) delay(1500); //nechte zprávu asi na sekundu ) //nastav 12 nebo 24 hodin void set_ampm() ( // AM/ PM nebo 24hodinový režim hodin - překlopte bit (udělá 0 na 1 nebo 1 na 0 pro režim ampm) ampm = (ampm ^ 1); cls(); ) //změna intenzity intenzity obrazovky void set_intensity() ( cls() ; byte i = 0; text char = "Jasný"; while(text[i]) ( puttinychar((i*4)+4, 0, text[i]); i++; ) //čekání na vstup tlačítkem, zatímco ( ! buttonA.uniquePress()) ( levelbar (0,6,(intenzita*2)+2,2); //zobrazení úrovně intenzity jako sloupec while (buttonB.isPressed()) ( if(intensity == 15) ( intenzita = 0; cls (); ) else ( intenzita++; ) //vytiskne novou hodnotu i = 0; while(text[i]) ( puttinychar((i*4)+4, 0, text[i]); i++; ) //zobrazení úrovně intenzity jako pruh úrovně (0,6,(intenzita*2)+ 2,2); //změňte nastavení jasu na displejích pro (adresa bajtu = 0; adresa< 4; address++) { lc.setIntensity(address, intensity); } delay(150); } } } // display a horizontal bar on the screen at offset xposr by ypos with height and width of xbar, ybar void levelbar (byte xpos, byte ypos, byte xbar, byte ybar) { for (byte x = 0; x < xbar; x++) { for (byte y = 0; y <= ybar; y++) { plot(x+xpos, y+ypos, 1); } } } //set time and date routine void set_time() { cls(); //fill settings with current clock values read from clock get_time(); byte set_min = rtc; byte set_hr = rtc; byte set_date = rtc; byte set_mnth = rtc; int set_yr = rtc; //Set function - we pass in: which "set" message to show at top, current value, reset value, and rollover limit. set_date = set_value(2, set_date, 1, 31); set_mnth = set_value(3, set_mnth, 1, 12); set_yr = set_value(4, set_yr, 2013, 2099); set_hr = set_value(1, set_hr, 0, 23); set_min = set_value(0, set_min, 0, 59); ds1307.adjust(DateTime(set_yr, set_mnth, set_date, set_hr, set_min)); cls(); } //used to set min, hr, date, month, year values. pass //message = which "set" message to print, //current value = current value of property we are setting //reset_value = what to reset value to if to rolls over. E.g. mins roll from 60 to 0, months from 12 to 1 //rollover limit = when value rolls over int set_value(byte message, int current_value, int reset_value, int rollover_limit){ cls(); char messages = { "Set Mins", "Set Hour", "Set Day", "Set Mnth", "Set Year"}; //Print "set xyz" top line byte i = 0; while(messages[i]) { puttinychar(i*4 , 1, messages[i]); i++; } delay(2000); cls(); //print digits bottom line char buffer = " "; itoa(current_value,buffer,10); puttinychar(0 , 1, buffer); puttinychar(4 , 1, buffer); puttinychar(8 , 1, buffer); puttinychar(12, 1, buffer); delay(300); //wait for button input while (!buttonA.uniquePress()) { while (buttonB.isPressed()){ if(current_value < rollover_limit) { current_value++; } else { current_value = reset_value; } //print the new value itoa(current_value, buffer ,10); puttinychar(0 , 1, buffer); puttinychar(4 , 1, buffer); puttinychar(8 , 1, buffer); puttinychar(12, 1, buffer); delay(150); } } return current_value; } void get_time() { //get time DateTime now = ds1307.now(); //save time to array rtc = now.year(); rtc = now.month(); rtc = now.day(); rtc = now.dayOfWeek(); //returns 0-6 where 0 = Sunday rtc = now.hour(); rtc = now.minute(); rtc = now.second(); //flash arduino led on pin 13 every second //if ((rtc % 2) == 0) { // digitalWrite(13, HIGH); //} //else { // digitalWrite(13, LOW); //} //print the time to the serial port - useful for debuging RTC issues /* Serial.print(rtc); Serial.print(":"); Serial.print(rtc); Serial.print(":"); Serial.println(rtc); */ }

Nyní, abyste dokončili práci na zařízení, stačí provést několik jednoduchých operací:


Kompilace programového kódu a jeho další načítání do paměti mikrokontroléru nějakou dobu zabere, obvykle ne více než jednu minutu. Úspěšné dokončení operace bude hlášeno v konzole Arduino IDE. Poté zbývá pouze restartovat Arduino pomocí tlačítka Reset na zařízení - jednoduché hodiny na LED matricích jsou připraveny!

Připravené hodiny na Arduinu

Hodiny se nastavují pomocí dvou tlačítek. Zařízení podporuje 12- a 24hodinové formáty času, zobrazuje datum a den v týdnu a zobrazuje čas s nebo bez sekund. Je také možné změnit jas LED diod.


Pravděpodobně budete chtít v budoucnu přidat další funkce (například teploměr), nebo nainstalovat zařízení do těla vlastní konstrukce - dobrých výsledků lze dosáhnout pomocí laserových řezacích strojů. Ale nyní můžete bezpečně říci, že jste sestavili plnohodnotné elektronické hodinky vlastníma rukama!

Není to tak dávno, co bylo potřeba mít doma hodiny, ale pouze elektronické, protože hodiny nemám rád, protože tikají. S pájením a leptáním obvodů mám poměrně dost zkušeností. Po prohledání internetu a přečtení nějaké literatury jsem se rozhodl zvolit nejjednodušší schéma, protože nepotřebuji hodinky s budíkem.

Toto schéma jsem zvolil, protože je snadné vyrobit si vlastní hodinky

Začněme, co tedy potřebujeme, abychom si vyrobili hodinky vlastníma rukama? No jistě, ruce, zručnost (ani velká) ve čtení schémat zapojení, páječka a součástky. Zde je úplný seznam toho, co jsem použil:

10 MHz quartz – 1 ks, mikrokontrolér ATtiny 2313, rezistory 100 Ohm – 8 ks, 3 ks. 10 kOhm, 2 kondenzátory 22 pF, 4 tranzistory, 2 tlačítka, LED indikátor 4bitový KEM-5641-ASR (RL-F5610SBAW/D15). Instalaci jsem provedl na jednostrannou DPS.

Ale v tomto schématu je chyba: celkem slušnou zátěž dostávají piny mikrokontroléru (dále jen MK), které mají na starosti řízení výbojů. Celkový proud je mnohem vyšší než maximální proud portu, ale při dynamické indikaci se MK nestihne přehřát. Aby nedošlo k poruše MK, přidáme do vybíjecích obvodů odpory 100 Ohm.

V tomto schématu je indikátor řízen podle principu dynamické indikace, podle kterého jsou segmenty indikátoru řízeny signály z odpovídajících výstupů MK. Frekvence opakování těchto signálů je více než 25 Hz a z tohoto důvodu se zdá, že záře čísel indikátorů jsou nepřetržité.

Elektronické hodinky vyrobené podle výše uvedeného schématu může zobrazovat pouze čas (hodiny a minuty) a sekundy jsou zobrazeny tečkou mezi segmenty, který bliká. Pro ovládání provozního režimu hodinek jsou v jejich struktuře umístěny tlačítkové spínače, které ovládají nastavení hodin a minut. Tento obvod je napájen z 5V zdroje. Při výrobě plošného spoje byla do obvodu zařazena zenerova dioda 5V.

Jelikož mám zdroj 5V, zenerovu diodu jsem z obvodu vyloučil.

K výrobě desky byl obvod aplikován pomocí žehličky. To znamená, že tištěný spoj byl vytištěn na inkoustové tiskárně na lesklý papír, lze jej převzít z moderních lesklých časopisů. Poté byl vyříznut textolit požadované velikosti. Vyšel mi rozměr 36*26 mm. Tak malá velikost je způsobena tím, že všechny díly jsou vybrány v SMD pouzdru.

Deska byla leptána pomocí chloridu železitého (FeCl3). Leptání trvalo asi hodinu, protože lázeň s deskou byla na krbu, vysoká teplota ovlivňuje dobu leptání, v desce nebyla použita měď. S teplotou to ale nepřehánějte.

Zatímco probíhal proces leptání, abych si nelámal hlavu a nepsal firmware, aby hodiny fungovaly, šel jsem na internet a našel jsem firmware pro toto schéma. Jak flashnout MK najdete i na internetu. Použil jsem programátor, který flashuje pouze ATMEGA MK.

A konečně je naše deska hotová a můžeme začít pájet hodinky. Pro pájení potřebujete 25W páječku s tenkým hrotem, aby nedošlo k popálení MK a dalších dílů. Pájení provádíme opatrně a nejlépe připájeme všechny nohy MK poprvé, ale pouze samostatně. Pro ty, kteří se nevyznají, vězte, že díly vyrobené v SMD pouzdru mají na svých vývodech cín pro rychlé pájení.

A takto vypadá deska s připájenými díly.

Pamatuji si... Před třiceti lety bylo šest ukazatelů malý poklad. Každý, kdo pak dokázal vyrobit hodiny pomocí TTL logiky s takovými indikátory, byl považován za sofistikovaného odborníka ve svém oboru.

Záře indikátorů vypouštění plynu se zdála teplejší. Po pár minutách jsem byl zvědavý, jestli tyto staré lampy budou fungovat, a chtěl jsem s nimi něco udělat. Nyní je velmi snadné takové hodinky vyrobit. Vše, co potřebujete, je mikrokontrolér...

Jelikož jsem se zároveň zajímal o programování mikrokontrolérů ve vyšších jazycích, rozhodl jsem se trochu si pohrát. Pokusil jsem se sestrojit jednoduché hodiny pomocí digitálních indikátorů výboje plynu.

Účel designu

Rozhodl jsem se, že hodiny by měly mít šest číslic a čas by měl být nastaven minimálním počtem tlačítek. Kromě toho jsem chtěl zkusit použít několik nejběžnějších rodin mikrokontrolérů od různých výrobců. Chtěl jsem napsat program v C.

Indikátory vybití plynu vyžadují k provozu vysoké napětí. Ale nechtěl jsem řešit nebezpečné síťové napětí. Hodinky měly být napájeny nezávadným napětím 12 V.

Jelikož mým hlavním cílem byla hra, nenajdete zde žádný popis mechanického provedení ani nákresy těla. Pokud si přejete, můžete si hodinky sami vyměnit podle svého vkusu a zkušeností.

Zde je to, co jsem dostal:

  • Zobrazení času: HH MM SS
  • Indikace alarmu: HH MM --
  • Režim zobrazení času: 24 hodin
  • Přesnost ±1 sekunda za den (v závislosti na křemenném krystalu)
  • Napájecí napětí: 12V
  • Spotřeba proudu: 100 mA

Schéma hodin

Pro zařízení s šestimístným digitálním displejem byl režim multiplex přirozeným řešením.

Účel většiny prvků blokového diagramu (obrázek 1) je jasný bez komentáře. Do jisté míry nestandardním úkolem bylo vytvořit převodník úrovní TTL na řídicí signály vysokonapěťových indikátorů. Budiče anody jsou vyrobeny pomocí vysokonapěťových tranzistorů NPN a PNP. Diagram je vypůjčen od Stefana Knellera (http://www.stefankneller.de).

Čip 74141 TTL obsahuje dekodér BCD a vysokonapěťový ovladač pro každou číslici. Může být obtížné objednat jeden čip. (I když nevím, jestli je už někdo vyrábí). Ale pokud najdete indikátory vypouštění plynu, 74141 může být někde poblíž :-). V době TTL logiky neexistovala k čipu 74141 prakticky žádná alternativa. Tak zkus někde nějakou najít.

Indikátory vyžadují napětí asi 170 V. Nemá smysl vyvíjet speciální obvod pro převodník napětí, protože existuje velké množství čipů převodníku boost. Vybral jsem si levný a široce dostupný IC34063. Obvod převodníku je téměř kompletně zkopírován z datového listu MC34063. Právě k němu přibyl vypínač T13. Vnitřní spínač není vhodný pro tak vysoké napětí. Jako indukčnost pro převodník jsem použil tlumivku. Je znázorněn na obrázku 2; jeho průměr je 8 mm a jeho délka je 10 mm.

Účinnost převodníku je poměrně dobrá a výstupní napětí je relativně bezpečné. Při zatěžovacím proudu 5 mA klesne výstupní napětí na 60 V. R32 funguje jako proudový rezistor.

Pro napájení logiky je použit lineární regulátor U4. Na obvodu a desce je prostor pro záložní baterii. (3,6 V - NiMH nebo NiCd). D7 a D8 jsou Schottkyho diody a rezistor R37 je navržen tak, aby omezoval nabíjecí proud podle vlastností baterie. Pokud stavíte hodinky jen pro zábavu, nebudete potřebovat baterii D7, D8 a R37.

Konečný obvod je znázorněn na obrázku 3.

Obrázek 3

Tlačítka nastavení času jsou připojena pomocí diod. Stav tlačítek se kontroluje nastavením logické „1“ na příslušném výstupu. Jako bonus je k výstupu mikrokontroléru připojen piezo emitor. Chcete-li umlčet to ošklivé skřípání, použijte malý vypínač. K tomu by se docela hodilo kladivo, ale to je poslední možnost :-).

Seznam součástek obvodu, nákres desky plošných spojů a schéma rozložení naleznete v sekci "Ke stažení".

procesor

Toto jednoduché zařízení může ovládat téměř každý mikrokontrolér s dostatečným počtem pinů, jejichž minimální požadovaný počet je uveden v tabulce 1.

Stůl 1.
Funkce závěry
Výživa 2
Quartzový rezonátor 2
Řízení anody 6
Ovladač 74141 4
Vstup tlačítkem 1
Piezo emitor 1
Celkový 16

Každý výrobce vyvíjí vlastní rodiny a typy mikrokontrolérů. Umístění čepů je u každého typu individuální. Snažil jsem se navrhnout univerzální desku pro více typů mikrokontrolérů. Deska má 20pinovou patici. Pomocí několika propojovacích vodičů jej můžete přizpůsobit různým mikrokontrolérům.

Mikrokontroléry testované v tomto obvodu jsou uvedeny níže. Můžete experimentovat s jinými typy. Výhodou schématu je možnost použití různých procesorů. Radioamatéři zpravidla používají jednu rodinu mikrokontrolérů a mají odpovídající programátor a softwarové nástroje. S mikrokontroléry jiných výrobců mohou být problémy, a tak jsem vám dal možnost vybrat si procesor z vaší oblíbené rodiny.

Všechna specifika zapínání různých mikrokontrolérů jsou reflektována v tabulkách 2...5 a obrázcích 4...7.

Tabulka 2
Freescale
Typ MC68HC908QY1
Quartzový rezonátor 12 MHz
Kondenzátory C1, C2 22 pF
Program freescale.zip
(viz sekce "Stahování")
Nastavení

Poznámka: Paralelně s křemenným rezonátorem je zapojen rezistor 10 MΩ.

Tabulka 3.
Mikročip
Typ PIC16F628A
Quartzový rezonátor 32,768 kHz
Kondenzátory C1, C2 22 pF
Program pic628.zip
(viz sekce "Stahování")
Nastavení Int. 4 MHz generátor - I/O RA6,
MCLR OFF, WDT OFF, LVP OFF,
BROUT OFF, CP OFF, PWRUP OFF

Poznámka: Mikroobvod musí být v zásuvce otočen o 180°.

Tabulka 4.
Atmel
Typ ATtiny2313
Quartzový rezonátor 12 MHz
Kondenzátory C1, C2 15 pF
Program attiny.zip
(viz sekce "Stahování")
Nastavení Sq. 8 MHz oscilátor, RESET ON

Poznámka: Přidejte SMD součástky R a C na pin RESET (10 kΩ a 100 nF).

Tabulka 5.
Atmel
Typ AT89C2051
Quartzový rezonátor 12 MHz
Kondenzátory C1, C2 22 pF
Program at2051.zip
(viz sekce "Stahování")
Nastavení --

Poznámka: Přidejte SMD součástky R a C na pin RESET (10 kΩ a 100 nF); připojte piny označené hvězdičkami k napájecí sběrnici +Ub přes 3,3 kOhm SMD odpory.

Když porovnáte kódy pro různé mikrokontroléry, uvidíte, že jsou velmi podobné. Existují rozdíly v přístupu k portům a definici funkcí přerušení a také v tom, co závisí na hardwarových komponentách.

Zdrojový kód se skládá ze dvou částí. Funkce hlavní() nakonfiguruje porty a spustí časovač, který generuje signály přerušení. Poté program prohledá stisknutá tlačítka a nastaví vhodné hodnoty času a alarmu. Tam se v hlavní smyčce porovná aktuální čas s budíkem a zapne se piezo emitor.

Druhá část je podprogram pro obsluhu přerušení časovače. Podprogram, který se volá každou milisekundu (v závislosti na schopnostech časovače), zvyšuje časové proměnné a řídí číslice na displeji. Kromě toho se kontroluje stav tlačítek.

Provozování okruhu

Při instalaci komponent a nastavení začněte u zdroje napájení. Připájejte regulátor U4 a okolní součásti. Zkontrolujte napětí 5 V pro U2 a 4,6 V pro U1. Dalším krokem je sestavení měniče vysokého napětí. Pomocí trimovacího rezistoru R36 nastavte napětí na 170 V. Pokud rozsah nastavení nestačí, mírně změňte odpor rezistoru R33. Nyní nainstalujte čip U2, tranzistory a rezistory anody a obvodu digitálního ovladače. Vstupy U2 připojte ke sběrnici GND a jeden z rezistorů R25 - R30 zapojte do série k napájecí sběrnici +Ub. Čísla indikátorů by se měla rozsvítit v odpovídajících pozicích. V poslední fázi kontroly obvodu připojte kolík 19 mikroobvodu U1 k zemi - piezo emitor by měl pípnout.

Zdrojové kódy a zkompilované programy naleznete v příslušném ZIP souboru v sekci „Ke stažení“. Po flashování programu do mikrokontroléru pečlivě zkontrolujte každý pin v pozici U1 a nainstalujte potřebné drátové a pájecí propojky. Viz obrázky mikrokontroléru výše. Pokud je mikrokontrolér naprogramován a zapojen správně, jeho generátor by měl začít pracovat. Můžete nastavit čas a budík. Pozornost! Na desce je místo ještě na jedno tlačítko - to je náhradní tlačítko pro budoucí rozšíření :-).

Zkontrolujte přesnost frekvence generátoru. Pokud není v očekávaném rozsahu, mírně změňte hodnoty kondenzátorů C1 a C2. (Pájejte malé kondenzátory paralelně nebo je vyměňte za jiné). Přesnost hodinek by se měla zlepšit.

Závěr

Malé 8bitové procesory jsou docela vhodné pro jazyky na vysoké úrovni. C nebyl původně určen pro malé mikrokontroléry, ale pro jednoduché aplikace jej v pohodě využijete. Jazyk symbolických instrukcí je vhodnější pro složité úlohy, které vyžadují kritické časy nebo maximální zatížení procesoru. Pro většinu radioamatérů jsou vhodné jak bezplatné, tak sharewarově omezené verze C kompilátoru.

Programování v C je stejné pro všechny mikrokontroléry. Musíte znát hardwarové funkce (registry a periferie) zvoleného typu mikrokontroléru. Pozor na bitové operace - jazyk C není vhodný pro manipulaci s jednotlivými bity, jak je vidět na příkladu originálu pro ATtiny.

Jsi hotov? Pak se nalaďte, uvažujte o elektronkách a sledujte...

...staré časy jsou zpět... :-)

Poznámka redakce

Úplným analogem SN74141 je mikroobvod K155ID1, vyrobený softwarem Minsk Integral.
Mikroobvod lze snadno najít na internetu.

Koncept hodin s velkými čísly

Konstrukčně se zařízení bude skládat ze dvou desek - nad sebou. První deska je matice LED, které tvoří hodiny a minuty, druhá je výkonová část (ovládání LED), logika a napájení. Díky tomuto designu budou hodinky kompaktnější (bez pouzdra přibližně 22 cm x 9 cm, tloušťka 4-5 centimetrů) + umožní přišroubovat matrici k jinému projektu, pokud se něco pokazí.

Výkonová část bude postavena na bázi budiče UL2003 a tranzistorových spínačů. Logické - na Atmega8 a DS1307. Napájení: 220V - transformátor; logická 5V (přes 7805), výkonová část - 12V (přes LM2576ADJ). K dispozici bude samostatná přihrádka pro 3V baterii pro autonomní napájení hodin reálného času - DS1307.

Uvažuji o použití Atmega8 a DS1307 (hodiny plánuji pověsit ze stropu, abych v případě výpadku proudu nemusel pokaždé tápat v nastavení), nicméně rozložení desky bude znamenat možnost provozu zařízení bez DS1307 (poprvé a možná navždy - jak to bude fungovat).

V závislosti na konfiguraci bude tedy provozní algoritmus hodinového programu následující:

Atmega8– počítadlo času podle časovače. Práce v cyklu bez přestávek: dotazování na klávesnici, úprava času (je-li to nutné), zobrazení 4 číslic a oddělovače.

Atmega8+DS1307. Práce v cyklu bez přestávek: dotazování na klávesnici, úprava času DS1307 (je-li to nutné), čtení času z DS1307, zobrazení 4 číslic a oddělovač. Nebo jiná možnost - čtení z DS1307 na časovači, zbytek ve smyčce (zatím nevím, jak nejlépe).

Segment se skládá ze 4 červených LED zapojených do série. Jedna číslice – 7 segmentů se společnou anodou. Neplánuji oddělovat segmenty pomocí vzoru osmičky, jak je tomu u konvenčních ukazatelů.

Výkonová část hodin

Výkonová část hodin je postavena na budiči UL2003 a tranzistorových spínačích VT1 a VT2.

UL2003 je zodpovědný za ovládání segmentů indikátoru, klávesy jsou pro ovládání číslic.

Oddělovač hodin a minut je ovládán samostatně (signál K8).

Segmenty, bity a separátor jsou řízeny mikrokontrolérem aplikací kladného potenciálu (tj. aplikací +5 V) na K1-K8, Z1-Z4.

Signály do segmentů a bitů musí být dodávány synchronně as určitou frekvencí, aby byl zajištěn dynamický výstup informace (hodiny a minuty).

Tranzistor BCP52 lze použít jako tranzistor VT1 (BCP53).

Schéma výkonové části hodin s velkými číslicemi

Plošný spoj sedmisegmentového indikátoru pro hodiny s velkými číslicemi

Jak jsem již uvedl dříve, hodiny se budou skládat ze dvou desek plošných spojů - indikační + logická a výkonová část.

Začněme návrhem a výrobou desky plošných spojů indikátoru.

Vývoj desky plošných spojů pro sedmisegmentový indikátor pro hodiny s velkými číslicemi

Plošný spoj sedmisegmentového indikátoru pro hodiny s velkými číslicemi ve formátu "lay" je umístěn na konci článku, v přiložených souborech. Můžete si přečíst o technologii výroby desek plošných spojů metodou LUT.

Pokud jste vše udělali správně, bude hotová DPS vypadat nějak takto.

Hotová deska plošných spojů sedmisegmentového indikátoru pro hodiny s velkými číslicemi

Montáž sedmisegmentového indikátoru

Vzhledem k tomu, že indikační deska je oboustranná, první věcí, kterou musíte udělat, je provést přechody mezi vrstvami. Dělám to pomocí nožiček nepotřebných dílů - provlékám je otvory a z obou stran připájem. Když jsou všechny přechody hotové, začistím je plochým jemným pilníkem - vypadá to velmi úhledně a pěkně.

Mezivrstvové lahvičky na indikační desce

Dalším krokem je ve skutečnosti sestavení indikátoru. Proč potřebujeme sadu červených (zelená, bílá, modrá) LED. Vzal jsem například tyto.

Příprava na sestavení indikátoru

Při instalaci diod nezapomeňte, že děláme indikátor se společnou anodou - tzn. Diody "+" musí být spojeny dohromady. Běžné anody na PCB jsou velké kusy mědi. Nezapomeňte věnovat pozornost anodě dělícího bodu.

Umístění anod na desce plošných spojů indikátoru

V důsledku toho byste po 2 hodinách usilovné práce měli získat toto:

Sedmi segmentový indikátor

Digitální část hodin

Digitální část hodin s velkými čísly sestavíme podle následujícího schématu:

Hodinový diagram s velkými čísly

Obvod hodin je docela průhledný, takže nevidím žádný smysl vysvětlovat, jak to funguje. Plošný spoj ve formátu *.lay je ke stažení na konci článku. Všimněte si, že deska s plošnými spoji je určena hlavně pro díly pro povrchovou montáž.

Takže základna prvků, kterou jsem použil:

1. Diodový můstek DFA028 (postačí jakýkoli kompaktní pro povrchovou montáž);
2. Regulátory napětí LM2576ADJ v pouzdře D2PAK, 78M05 v pouzdře HSOP3-P-2,30A;
3. Tranzistorové spínače BCP53 (pouzdro SOT223) a BC847 (pouzdro SOT23);
4. mikrokontrolér Atmega8 (TQFP);
5. Hodiny reálného času DS1307 (SO8);
6. Napájení 14V 1,2A z nějakého starého zařízení;
7. Zbývající díly jsou libovolného typu, velikostně vhodné pro instalaci na desku plošných spojů.

Samozřejmě, pokud chcete použít další balíčky dílů, budete muset provést nějaké změny na PCB.

Věnujte pozornost hodnotám odporu R3 a R4 - musí být přesně takové, jak je uvedeno na diagramu - ne více, ne méně. To se provádí za účelem poskytnutí přesně 12V na výstupu regulátoru napětí LM2576ADJ. Pokud stále nemůžete najít takové hodnoty odporu, pak lze hodnotu odporu R4 vypočítat pomocí vzorce:

R4=R3(12/1,23-1) nebo R4=8,76R3

Sestavení digitální části. Verze 1, bez DS1307

Pokud jste se při výrobě plošného spoje pro hodinky řídili doporučeními uvedenými v, pak je zbytečné připomínat, že před montáží je třeba plošný spoj provrtat, odstranit všechny viditelné zkraty na něm a deska musí být pokryta tekutou kalafunou? Poté začneme s montáží hodinek.

Doporučuji začít s montáží zdroje a teprve poté osadit digitální část. Toto je obecné doporučení pro vlastní montáž zařízení. Proč? Jednoduše proto, že pokud je zdroj sestaven s chybou, můžete spálit veškerou nízkonapěťovou elektroniku, která by měla být tímto zdrojem napájena.

Pokud je vše provedeno správně, napájení by mělo okamžitě fungovat. Zkontrolujeme sestavení zdroje - změřte napětí na zkušebních bodech.

Obrázek ukazuje testovací body, ve kterých by se mělo kontrolovat napájecí napětí. Pokud napětí odpovídá deklarovanému, můžete začít s montáží digitální části hodinek. V opačném případě zkontrolujeme instalaci a funkčnost napájecích prvků.

Testovací body a hodnoty napětí pro napájení hodin

Po kontrole napájení přistoupíme k montáži digitální části hodin - instalaci všech ostatních prvků na plošný spoj. Kontrolujeme zkraty zejména v nohách mikrokontroléru Atmega a driveru UL2003.

Instalace digitální části hodin

Vezměte prosím na vědomí, že sestavujeme hodiny BEZ instalace hodin reálného času DS1307, avšak veškeré zapojení tohoto čipu musí být dokončeno. V budoucnu, pokud bude potřeba, nám to ušetří čas na úpravu hodin pro druhou verzi, kde budou stále používány samostatné nezávislé hodiny reálného času na DS1307.

Předběžné testování mikrokontroléru ATMEGA8

Abychom mohli zkontrolovat správnost a funkčnost mikrokontroléru, potřebujeme:

1. Například programátor.
2. pro obvodové programování mikrokontroléru.
3. Program AVRDUDESHELL.

Desku hodin připojíme k datovému kabelu. Datový kabel připojíme k programátoru. Programátor pro počítač, na kterém je nainstalován program AVRDUDESHELL. Deska hodin by neměla být připojena ke zdroji 220V.

Úspěšné čtení dat z mikrokontroléru programem AVRDUDESHELL

Pokud se vyskytnou problémy při čtení pojistek, zkontrolujte instalaci - někde může být zkrat nebo „chybějící spojení“. Další tip - možná je mikrokontrolér v režimu nízkorychlostního programování, pak stačí přepnout programátor do tohoto režimu (