Dom · Zdrowie · Zegar uliczny LED DIY. Domowy zegarek na rękę. Gotowy zegar na Arduino

Zegar uliczny LED DIY. Domowy zegarek na rękę. Gotowy zegar na Arduino

Z dynamicznym wyświetlaczem. Do działania zegarka nie można mieć zastrzeżeń: precyzyjny mechanizm, wygodne ustawienia. Ale jedną dużą wadą jest to, że wskaźniki LED są słabo widoczne w ciągu dnia. Aby rozwiązać problem, przełączyłem się na wyświetlacz statyczny i jaśniejsze diody LED. Jak zawsze w przypadku oprogramowania, wielkie dzięki dla Soir. Ogólnie zwracam uwagę na duży zegar zewnętrzny ze statycznym wyświetlaczem; funkcje ustawień pozostają takie same jak w poprzednich zegarach.

Posiadają dwa wyświetlacze - główny (na zewnątrz na ulicy) i pomocniczy na kierunkowskazach - w pomieszczeniu, na korpusie urządzenia. Wysoką jasność osiąga się dzięki zastosowaniu ultrajasnych diod LED o prądzie roboczym 50mA i chipach sterownika.

Schemat obwodu zewnętrznego zegara elektronicznego z jasnymi diodami LED

Aby sflashować oprogramowanie sterownika plikami i skorzystać z następujących ustawień bezpieczników:

Płytki drukowane zegara, jednostki sterującej i modułu zewnętrznego, w formacie LAY, .


Cechy tego obwodu zegara:

- Format wyświetlania czasu 24-godzinny.
- Cyfrowa korekcja dokładności skoku.
- Wbudowane sterowanie głównym zasilaniem.
- Nieulotna pamięć mikrokontrolera.
- Jest termometr, który mierzy temperaturę w zakresie -55 - 125 stopni.
- Istnieje możliwość naprzemiennego wyświetlania na wyświetlaczu informacji o czasie i temperaturze.


Naciśnięcie przycisku SET_TIME powoduje przejście wskaźnika po okręgu z głównego trybu zegara (wyświetlanie aktualnego czasu). We wszystkich trybach przytrzymanie przycisków PLUS/MINUS powoduje przyspieszoną instalację. Zmiany ustawień po 10 sekundach od ostatniej zmiany wartości zostaną zapisane w pamięci nieulotnej (EEPROM) i stamtąd odczytane po ponownym włączeniu zasilania.


Kolejnym dużym plusem proponowanej opcji jest to, że zmieniła się jasność, teraz przy słonecznej pogodzie jasność jest doskonała. Zmniejszono liczbę przewodów z 14 do 5. Długość przewodu prowadzącego do wyświetlacza głównego (zewnętrznego) wynosi 20 metrów. Jestem zadowolony z działania zegarka elektronicznego, okazał się w pełni funkcjonalnym zegarkiem - zarówno w dzień, jak iw nocy. Z poważaniem, Soir-Aleksandrowicz.

Istnieje wiele sposobów montażu zegarka elektronicznego własnymi rękami: schematy są szeroko prezentowane w literaturze i Internecie. Większość współczesnych implementacji opiera się na mikrokontrolerach. Realizacja takich projektów często wymaga szerokich umiejętności praktycznych i wiedzy teoretycznej z zakresu elektroniki: umiejętności obsługi specjalistycznego oprogramowania, samodzielnego tworzenia płytek drukowanych metodą trawienia chlorkiem żelaza, dobrego lutowania. Trzeba także zaopatrzyć się w różnorodne narzędzia i materiały.

Istnieje jednak prosty i niedrogi sposób na złożenie zegarka elektronicznego własnymi rękami w domu: skorzystaj z platformy Arduino. Jest to kompleks oprogramowania i sprzętu zaprojektowany specjalnie do nauczania podstaw programowania i elektroniki. Za pomocą Arduino każdy, nawet bez specjalnego wcześniejszego przeszkolenia, może własnoręcznie zbudować zegar elektroniczny: schematy obwodów, programy inżynierskie, a nawet lutownica nie są potrzebne!

Połączenie wszystkich elementów elektronicznych odbywa się na specjalnej płytce kontaktowej („bezlutowej”), co eliminuje ryzyko poparzeń, skaleczeń i innych obrażeń – dzięki temu z projektantem Arduino można pracować wspólnie z dziećmi. Wizualny sposób przedstawienia schematu obwodu pozwoli uniknąć błędów podczas montażu urządzenia.

Krok 1. Lista komponentów

Do złożenia prostego zegarka na matrycach LED wystarczy kilka tanich podzespołów:

  • Platforma Arduino. Wystarczą najprostsze modele - czyli Micro;
  • płytka kontaktowa;
  • przewody połączeniowe do płytki stykowej;
  • Moduł zegara czasu rzeczywistego Adafruit DS3231;
  • Moduł matrycy LED 32x8 MAX7219;
  • dwa przyciski.

Do wczytania programu sterującego do pamięci potrzebny będzie także komputer osobisty oraz kabel USB-mini-USB. To wszystko – lutownica, ściągacze izolacji, noże montażowe i inne profesjonalne narzędzia nie są potrzebne: wszystkie operacje wykonuje się ręcznie. Być może w niektórych przypadkach wygodniej jest używać pęsety, ale można się bez niej obejść.


Krok 2. Montaż obwodu elektronicznego

Obwód zegara elektronicznego z wyświetlaczem LED z wykorzystaniem Arduino wyda się dość prosty nawet dla niedoświadczonych radioamatorów. Do montażu potrzeba tylko kilku przewodów. Tabela połączeń:

Moduł Arduino → matryca LED 32x8 MAX7219

Moduł Arduino → Zegar czasu rzeczywistego Adafruit DS3231

Moduł Arduino → przyciski

D2 - przycisk 1

D3 - przycisk 2

Drugi pin przycisków jest podłączony do GND.

Trzeba tylko zwrócić uwagę i pamiętać, jak otwory stykowe na płytce stykowej są ze sobą połączone. Poniższy schemat ilustruje sposób wewnętrznego podłączenia otworów stykowych:


Dwa rzędy (1 i 4) po obu stronach są zwarte w poziomie - zwykle służą jako linia zasilania +5V i masa GND. Wszystkie styki wewnętrzne (2 i 3) są zwarte w pionie. W tym przypadku płytka drukowana jest podzielona zarówno w pionie, jak iw poziomie na dwie symetryczne, niezależne od siebie części. Pozwala to np. na montaż dwóch różnych urządzeń na jednej płytce.

Schemat zegara elektronicznego ze wskazaniem LED oraz rozmieszczenie elementów na płytce drukowanej pokazano na rysunku:

Dokładnie sprawdź, czy wszystkie połączenia są zgodne z pokazanym schematem. Upewnij się również, że przewody są dobrze zamocowane w otworach stykowych płytki drukowanej.


Krok 3. Oprogramowanie Arduino

Po zakończeniu montażu i testowaniu obwodu można rozpocząć ładowanie programu sterującego (lub „oprogramowania sprzętowego”) do pamięci Arduino.


Aby to zrobić, musisz zainstalować bezpłatne oficjalne środowisko programistyczne - . Będziesz także potrzebował kodu źródłowego projektu, który możesz pobrać poniżej w archiwum ze wszystkimi bibliotekami i szkicem, a jeśli potrzebujesz tylko szkicu, możesz go skopiować osobno:

//włącz biblioteki: #include "LedControl.h" #include // Biblioteka czcionek #include // Zegar DS1307 #dołącz „RTClib.h” // Zegar DS1307 #dołącz // Biblioteka przycisków autorstwa Alexandra Breviga // Setup LED Matrix // pin 12 jest podłączony do DataIn na wyświetlaczu // pin 11 jest podłączony do CLK na wyświetlaczu // pin 10 jest podłączony do LOAD na wyświetlaczu LedControl lc = Sterowanie Led(6, 5, 4, 4); //ustawia 3 piny na 12, 11 i 10, a następnie ustawia 4 wyświetlacze (maks. 8 wyświetlaczy) //zmienna globalna intensywność bajtów = 7; // Domyślna intensywność/jasność (0-15) bajt clock_mode = 0; // Domyślny tryb zegara. Domyślnie = 0 (tryb_podstawowy) bool tryb_randomowy = 0; // Zdefiniuj tryb losowy - zmienia typ wyświetlania co kilka godzin. Domyślnie = 0 (wyłączone) bajt stary_tryb = tryb_zegara; // Przechowuje poprzedni tryb zegara, więc jeśli przejdziemy do daty lub czegokolwiek innego, wiemy, do jakiego trybu wrócić później. bool amper = 0; // Zdefiniuj czas 12- lub 24-godzinny. 0 = 24 godziny. 1 = 12-godzinny bajt czas_zmiany_trybu = 0; // Zatrzymuje godzinę, kiedy tryb zegara zmieni się w trybie losowym. długi czas opóźnienia bez znaku = 500; // Zawsze czekamy trochę pomiędzy aktualizacjami wyświetlacza int rtc; // Przechowuje wyjście zegara czasu rzeczywistego char Days = ( "Sun", "Pon", "Tue", "Śro", "Thu", "Fri", "Sat" ); //tablica dni - używana w trybach slide, basic_mode i Jumble (DS1307 wyprowadza 1-7 wartości dla dnia tygodnia) char dayfull = ( "Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek ", "piątek", "sobota" ); char sufiks = („st”, „nd”, „rd”, „th” ); //tablica sufiksów daty, używana w trybach slide, basic_mode i Jumble. e,g, 1st 2nd ... //zdefiniuj stałe #define NUM_DISPLAY_MODES 3 // Tryby wyświetlania liczb (ciągłe zero jako pierwszy tryb) #define NUM_SETTINGS_MODES 4 // Tryby ustawień liczb = 6 (ciągłe zero jako pierwszy tryb) # zdefiniuj SLIDE_DELAY 20 // Czas w milisekundach efektu slajdu na znak w trybie slajdu. Zwiększ tę wartość, aby uzyskać wolniejszy efekt #define cls clear_display // Wyczyść wyświetlacz RTC_DS1307 ds1307; // Utwórz obiekt RTC Przycisk przyciskA = Przycisk(2, BUTTON_PULLUP); // Konfiguracja przycisku A (używając biblioteki przycisków) Przycisk przyciskB = Przycisk(3, BUTTON_PULLUP); // Konfiguracja przycisku B (używając biblioteki przycisków) void setup() ( digitalWrite(2, HIGH); // włączenie rezystora podciągającego dla przycisku na pinie 2 digitalWrite(3, HIGH); // włączenie rezystora podciągającego dla przycisku na pinie 3 digitalWrite(4, HIGH); // włącz rezystor podciągający dla przycisku na pinie 4 Serial.begin(9600); //uruchom port szeregowy //inicjuj 4 panele matrycy //ustawiliśmy już liczbę urządzeń podczas tworzenia the LedControl int devices = lc.getDeviceCount(); //musimy zainicjować wszystkie urządzenia w pętli for (int adres = 0; adres< 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--) ( for (adres bajtu = 0; adres< 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 >> wiersz)) plot(x + col, y + wiersz, 1);<= "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 == ">else plot(x + col, y + wiersz, 0);<= -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 >) ) ) void putnormalchar(bajt x, bajt y, znak c) ( bajt kropki; // if (c >= "A" && c<= 31) && (y >") ( c = 30; // strzałka selektora trybu zegara ) else if (c >= -80 && c<= 7)){ if (dots & (64 >= 0) && (x< 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 ->= 0) && (y< 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 >> wiersz)) ( // tylko 7 wierszy. plot(x + col, y + wiersz, 1); ) else ( plot(x + col, y + wiersz, 0); ) //) ) ) ) //small_mode //pokazuje czas małymi znakami 3x5 z sekundami display void small_mode() ( char textchar; // 16 znaków na wyświetlaczu bajt mins = 100; //min bajt secs = rtc; //bajt sekund old_secs = secs; / /zatrzymuje starą wartość sekund - od ostatniej aktualizacji sekund o display - używany do sprawdzania, czy sekundy się zmieniły cls(); //uruchamia główną pętlę zegara, o ile run_mode zwraca wartość true while (run_mode()) ( get_time(); / /sprawdź, czy naciśnięto przycisk if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); return; ) //jeśli sekundy się zmieniły, zaktualizuj je na wyświetlaczu secs = rtc; if (secs != old_secs) ( //secs char bufor; itoa(secs, bufor, 10); //fix - w przeciwnym razie, jeśli num ma początkowe zero, np. "03" s, itoa zastępuje to znakami spacją „3”. jeśli (sek< 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 >> wiersz)) ( // tylko 7 wierszy. plot(x + col, y + wiersz, 1); ) else ( plot(x + col, y + wiersz, 0); ) //) ) ) ) //small_mode //pokazuje czas małymi znakami 3x5 z sekundami display void small_mode() ( char textchar; // 16 znaków na wyświetlaczu bajt mins = 100; //min bajt secs = rtc; //bajt sekund old_secs = secs; / /zatrzymuje starą wartość sekund - od ostatniej aktualizacji sekund o display - używany do sprawdzania, czy sekundy się zmieniły cls(); //uruchamia główną pętlę zegara, o ile run_mode zwraca wartość true while (run_mode()) ( get_time(); / /sprawdź, czy naciśnięto przycisk if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); return; ) //jeśli sekundy się zmieniły, zaktualizuj je na wyświetlaczu secs = rtc; if (secs != old_secs) ( //secs char bufor; itoa(secs, bufor, 10); //fix - w przeciwnym razie, jeśli num ma początkowe zero, np. "03" s, itoa zastępuje to znakami spacją „3”. jeśli (sek< 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 ->1:00 w nocy w trybie 12-godzinnym.<=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 >//wykonaj konwersję 12/24-godzinną, jeśli ampm jest ustawione na 1 bajt godziny = rtc;<=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 >if (godziny > 12) ( godziny = godziny - ampery * 12; ) if (godziny<= "z")) { // current_c &= 0x1F; // A-Z maps to 1-26 // } if (current_c >12) (godziny = godziny - ampery * 12; ) if (godziny<= "Z") { current_c &= 0x1F; // A-Z maps to 1-26 } else if (current_c >01 lutego, wtedy cyfra się nie zmieni if ​​((cyfry_stare != cyfry_nowe) || (cyfry_stare != cyfry_nowe)) ( //zmień pokazany dzień. Pętla poniżej przechodzi kolejno przez każdy z 3 znaków, np. „MON” dla (bajt dzień_char = 0; dzień_char<= "z") { current_c = (current_c - "a") + 41; // A-Z maps to 41-67 } else if (current_c >= 6; i--)( if (cyfry_stare[i] != cyfry_nowe[i]) ( for (bajt seq = 0; seq<= "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 == ">= „A” && || (current_c >= "a" && current_c<= 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); //działka prowadzona na else plot(x + col, y + start_y, 0); //w przeciwnym razie wykres zostanie wyłączony ) start_y++;//dodaj jeden do y, abyśmy narysowali następny wiersz w dół ) ) //narysuj pustą linię pomiędzy znakami, jeśli sekwencja wynosi od 1 do 7. Jeśli tego nie zrobimy, otrzymamy resztki aktualnych znaków ostatnia pozycja pozostawiona na wyświetlaczu if (sekwencja >= 1 && sekwencja<= 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) ( //oblicz kropki w bajtach znakowych; //if (new_c >= "A" && new_c<= "Z" || (new_c >= "a" && nowy_c<= "z")) { // new_c &= 0x1F; // A-Z maps to 1-26 //} if (new_c >= „A” && nowy_c<= "Z") { new_c &= 0x1F; // A-Z maps to 1-26 } else if (new_c >= "a" && nowy_c<= "z") { new_c = (new_c - "a") + 41; // A-Z maps to 41-67 } else if (new_c >= „0” && nowy_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; // strzałka selektora trybu zegara ) bajt newcharrowmin = 6 - (sekwencja - 2); //minimalna liczba wierszy do narysowania nowego znaku - generuje to wynik od 6 do 0 przy podawaniu numerów sekwencji 2-8 Jest to minimalny wiersz do narysowania dla nowego bajtu znaku początek_y = 0; //y, od którego należy rozpocząć — jest taki sam jak numer kolejny. dodajemy go w każdym wierszu. //wykreślamy każdy wiersz w górę od minimum wiersza (obliczonego według numeru kolejnego ) ) do 6 for (bajt 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); //działka prowadzona na else plot(x + col, y + start_y, 0); //w przeciwnym razie wykres zostanie wyłączony ) start_y++;//dodaj jeden do y, abyśmy narysowali następny wiersz w dół ) ) ) //wypisz zegar, używając słów, a nie liczb void word_clock() ( cls(); char number = ( "jeden „, „dwa”, „trzy”, „cztery”, „pięć”, „sześć”, „siedem”, „osiem”, „dziewięć”, „dziesięć”, „jedenaście”, „dwanaście”, „trzynaście”, „czternaście”, „piętnaście”, „szesnaście”, „siedemnaście”, „osiemnaście”, „dziewiętnaście” ); liczby = ( „dziesięć”, „dwadzieścia”, „trzydzieści”, „czterdzieści”, „pięćdziesiąt” ); //potencjalnie 3 linie do wyświetlenia char str_a; //byte hours_y, mins_y; //godziny i minuty oraz pozycje godzin i minut linie hours = rtc;< 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) ( godziny = godziny - 12; ) if (godziny == 0) ( godziny = 12; ) //podziel wartość minut na dwie oddzielne cyfry int minsdigit = rtc % 10;<= 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 >bajt minsdigitten = (rtc / 10) % 10;<= 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)( //sprawdzenie naciśnięcia przycisku if (buttonA.uniquePress()) ( switch_mode(); return; ) if (buttonB.uniquePress()) ( display_date(); ) opóźnienie(1); licznik--; ) fade_down ();< 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+offset, 1, bufor); offset = 8; //przesunięcie do środka tekstu, jeśli 4 znaki ) //wypisz 2 znaki sufiksu puttinychar(suffixposx+offset, 1, sufiks[s ]);< 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) ( tryb_zegara = 0; ) //wypisz strzałkę i nazwę bieżącego trybu_zegara w pierwszej linii i wypisz następną nazwę trybu_zegara w drugiej linii char str_top;< 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) ( tryb_ustawienia = 0; ) //wypisz strzałkę i nazwę bieżącego trybu_zegara w pierwszym wierszu i wypisz nazwę następnego trybu_zegara w drugim wierszu char str_top;< 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); */ }

strcpy(str_top, set_modes);


Kompilowanie kodu programu i dalsze ładowanie go do pamięci mikrokontrolera zajmie trochę czasu, zwykle nie więcej niż minutę. Pomyślne zakończenie operacji zostanie zgłoszone w konsoli Arduino IDE. Po czym pozostaje już tylko zrestartować Arduino za pomocą przycisku Reset na urządzeniu – prosty zegar na matrycach LED gotowy!

Gotowy zegar na Arduino

Zegar ustawia się za pomocą dwóch przycisków. Urządzenie obsługuje formaty czasu 12- i 24-godzinne, wyświetla datę i dzień tygodnia oraz wyświetla czas z sekundami lub bez. Możliwa jest także zmiana jasności diod LED.


Prawdopodobnie w przyszłości będziesz chciał dodać więcej funkcji (np. termometr) lub zamontować urządzenie w zaprojektowanej przez siebie obudowie – dobre rezultaty można osiągnąć wykonując produkcję na wycinarkach laserowych. Ale teraz możesz śmiało powiedzieć, że własnoręcznie zmontowałeś pełnoprawny zegarek elektroniczny!

Proponuję do powtórzenia obwód prostego zegara elektronicznego z budzikiem, wykonanego na układzie PIC16F628A. Dużą zaletą tego zegarka jest wskaźnik LED typu ALS służący do wyświetlania czasu. Osobiście mam dość wszelkiego rodzaju wyświetlaczy LCD i chcę móc zobaczyć godzinę z dowolnego miejsca w pomieszczeniu, także w ciemności, a nie tylko bezpośrednio przy dobrym oświetleniu. Obwód zawiera minimum części i charakteryzuje się doskonałą powtarzalnością. Zegarek był testowany przez miesiąc, który wykazał jego niezawodność i wydajność. Myślę, że ze wszystkich schematów w Internecie, ten jest najłatwiejszy w montażu i uruchomieniu.

Schemat ideowy zegara elektronicznego z budzikiem na mikrokontrolerze:


Jak widać na schemacie zegara, jest to jedyny mikroukład zastosowany w tym urządzeniu. Do ustawienia częstotliwości zegara służy rezonator kwarcowy 4 MHz. Do wyświetlania czasu służą czerwone wskaźniki ze wspólną anodą; każdy wskaźnik składa się z dwóch cyfr z kropkami dziesiętnymi. W przypadku zastosowania emitera piezoelektrycznego można pominąć kondensator C1 - 100 μF.

Można zastosować dowolne wskaźniki ze wspólną anodą, pod warunkiem, że każda cyfra ma własną anodę. Aby mieć pewność, że zegarek elektroniczny będzie dobrze widoczny w ciemności i z dużej odległości, spróbuj wybrać większy ALS.


Wskazanie zegara jest dynamiczne. W danym momencie wyświetlana jest tylko jedna cyfra, co pozwala znacznie zmniejszyć pobór prądu. Anody każdej cyfry są kontrolowane przez mikrokontroler PIC16F628A. Segmenty wszystkich czterech cyfr są ze sobą połączone i poprzez rezystory ograniczające prąd R1 ... R8 podłączone do zacisków portu MK. Ponieważ wskaźnik zapala się bardzo szybko, migotanie cyfr staje się niezauważalne.


Przyciski chwilowe służą do ustawiania minut, godzin i budzika. Pin 10 służy jako wyjście sygnału alarmowego, a kaskada tranzystorów VT1,2 służy jako wzmacniacz. Emiter dźwięku jest elementem piezoelektrycznym typu ZP. Aby poprawić głośność, możesz zastąpić go małym głośnikiem.


Zegar zasilany jest ze stabilizowanego źródła 5V. Można go także zasilać na baterie. Zegarek posiada 9 trybów wyświetlania. Przełączanie pomiędzy trybami odbywa się za pomocą przycisków „+” i „-”. Przed wyświetleniem samych odczytów na wskaźnikach wyświetlana jest krótka podpowiedź dotycząca nazwy trybu. Czas wyświetlania podpowiedzi wynosi jedną sekundę.


Za pomocą przycisku „Korekta” budzik przechodzi do trybu ustawień. W takim przypadku przez pół sekundy wyświetlany jest krótkotrwały monit, po czym ustawiona wartość zaczyna migać. Korekta odczytów odbywa się za pomocą przycisków „+” i „-”. Długie naciśnięcie przycisku powoduje aktywację trybu automatycznego powtarzania z określoną częstotliwością. Wszystkie wartości, z wyjątkiem godzin, minut i sekund, są zapisywane w pamięci EEPROM i przywracane po wyłączeniu zasilania.


Jeśli w ciągu kilku sekund nie zostanie naciśnięty żaden przycisk, zegar elektroniczny przejdzie w tryb wyświetlania czasu. Naciśnięcie przycisku „On/Off” powoduje włączenie lub wyłączenie budzika, co potwierdzane jest krótkim dźwiękiem. Gdy budzik jest włączony, kropka na najniższej cyfrze wskaźnika świeci się. Zastanawiałam się gdzie umieścić zegar w kuchni i zdecydowałam się zamontować go bezpośrednio do kuchenki gazowej :) Materiał przesłała firma in_sane.


Omów artykuł BUDZIK ELEKTRONICZNY

Cześć, geektimes! W pierwszej części artykułu omówiono zasady uzyskiwania dokładnego czasu na domowym zegarku. Pójdźmy dalej i zastanówmy się, jak i na czym lepiej tym razem wyeksponować.

1. Urządzenia wyjściowe

Mamy więc określoną platformę (Arduino, Raspberry, kontroler PIC/AVR/STM itp.) i zadaniem jest podłączenie do niej jakiegoś wskaźnika. Istnieje wiele opcji, które rozważymy.

Wyświetlacz segmentowy

Tutaj wszystko jest proste. Wskaźnik segmentowy składa się ze zwykłych diod LED, które są po prostu podłączone do mikrokontrolera za pomocą rezystorów gaszących.

Uwaga na ruch!

Plusy: prostota konstrukcji, dobre kąty widzenia, niska cena.
Wady: Ilość wyświetlanych informacji jest ograniczona.
Istnieją dwa rodzaje konstrukcji wskaźników, ze wspólną katodą i wspólną anodą w środku, wygląda to mniej więcej tak (schemat ze strony producenta).

Istnieje 1001 artykułów na temat podłączenia diody LED do mikrokontrolera, Google może pomóc. Trudności zaczynają się, gdy chcemy zrobić duży zegar – w końcu patrzenie na mały wskaźnik nie jest szczególnie wygodne. Następnie potrzebujemy następujących wskaźników (zdjęcie z serwisu eBay):

Zasilane są napięciem 12 V i po prostu nie będą działać bezpośrednio z mikrokontrolera. Tutaj z pomocą przychodzi nam mikroukład. CD4511, właśnie w tym celu. Nie tylko konwertuje dane z 4-bitowej linii na żądane liczby, ale także zawiera wbudowany przełącznik tranzystorowy umożliwiający podanie napięcia na wskaźnik. Zatem w obwodzie będziemy musieli mieć napięcie „zasilania” 9-12 V i oddzielny konwerter obniżający napięcie (na przykład L7805) do zasilania „logiki” obwodu.

Wskaźniki matrycowe

Zasadniczo są to te same diody LED, tylko w postaci matrycy 8x8. Zdjęcie z eBay'a:

Sprzedawane są na eBayu w postaci pojedynczych modułów lub gotowych bloków, np. 4 sztuki. Zarządzanie nimi jest bardzo proste - mikroukład jest już przylutowany do modułów MAX7219, zapewniając ich działanie i połączenie z mikrokontrolerem za pomocą jedynie 5 przewodów. Bibliotek dla Arduino jest wiele, każdy może zajrzeć do kodu.
Plusy: niska cena, dobre kąty widzenia i jasność.
Wady: niska rozdzielczość. Ale na zadanie wnioskowania czas jest wystarczający.

Wskaźniki LCD

Wskaźniki LCD mogą być graficzne lub tekstowe.

Graficzne są droższe, ale pozwalają na wyświetlenie bardziej zróżnicowanych informacji (na przykład wykresu ciśnienia atmosferycznego). Tekstowe są tańsze i łatwiejsze w obsłudze, pozwalają także na wyświetlanie pseudografiki - istnieje możliwość wczytania do wyświetlacza własnych symboli.

Praca ze wskaźnikiem LCD z kodu nie jest trudna, ma jednak pewną wadę - wskaźnik wymaga wielu linii sterujących (od 7 do 12) z mikrokontrolera, co jest niewygodne. Dlatego Chińczycy wpadli na pomysł połączenia wskaźnika LCD z kontrolerem i2c, co okazało się bardzo wygodne – do podłączenia wystarczą tylko 4 przewody (zdjęcie z eBay).


Wskaźniki LCD są dość tanie (jeśli kupisz je na eBay), duże, łatwe do podłączenia i mogą wyświetlać różnorodne informacje. Jedynym minusem są niezbyt duże kąty widzenia.

Wskaźniki OLED

Stanowią ulepszoną kontynuację poprzedniej wersji. Są od małych i tanich o przekątnej 1,1", po duże i drogie. Zdjęcie z serwisu eBay.

Właściwie są dobrzy we wszystkim oprócz ceny. Jeśli chodzi o małe wskaźniki o wielkości 0,9-1,1 cala, to (poza nauką pracy z i2c) trudno znaleźć dla nich jakiekolwiek praktyczne zastosowanie.

Wskaźniki wyładowania gazu (IN-14, IN-18)

Wskaźniki te są obecnie bardzo popularne, najwyraźniej ze względu na „ciepłe brzmienie światła lampy” i oryginalność projektu.


(zdjęcie ze strony nocrotec.com)

Schemat ich połączeń jest nieco bardziej skomplikowany, ponieważ Wskaźniki te wykorzystują do zapłonu napięcie 170 V. Przetwornicę z 12V=>180V można wykonać na mikroukładzie MAX771. Do zasilania wskaźników napięciem służy radziecki mikroukład K155ID1, który został stworzony specjalnie w tym celu. Cena emisyjna do własnej produkcji: około 500 rubli za każdy wskaźnik i 100 rubli za K155ID1, wszystkich pozostałych części, jak pisano w starych magazynach, „nie brakuje”. Główna trudność polega na tym, że zarówno IN-xx, jak i K155ID1 są już dawno wycofane z produkcji i można je kupić jedynie na targowiskach radiowych lub w kilku wyspecjalizowanych sklepach.

2. Wybór platformy

Już mniej więcej rozpracowaliśmy wyświetlacz; pozostaje tylko zdecydować, której platformy sprzętowej najlepiej użyć. Jest tu kilka opcji (nie rozważam domowych, ponieważ ci, którzy wiedzą, jak okablować płytkę i lutować procesor, nie potrzebują tego artykułu).

Arduino

Najłatwiejsza opcja dla początkujących. Gotowa płytka jest niedroga (około 10 dolarów w serwisie eBay z bezpłatną wysyłką) i posiada wszystkie niezbędne złącza do programowania. Zdjęcie z eBay'a:

Istnieje ogromna liczba różnych bibliotek dla Arduino (na przykład dla tych samych ekranów LCD, modułów czasu rzeczywistego), Arduino jest sprzętowo kompatybilne z różnymi dodatkowymi modułami.
Główna wada: złożoność debugowania (tylko przez konsolę portu szeregowego) i dość słaby procesor jak na współczesne standardy (2KB RAM i 16 MHz).
Główna zaleta: można zrobić wiele rzeczy, praktycznie bez zawracania sobie głowy lutowaniem, zakupem programatora i płytek okablowania, wystarczy tylko połączyć ze sobą moduły;

32-bitowe procesory STM

Dla tych, którzy chcą czegoś mocniejszego, dostępne są gotowe płyty z procesorami STM, np. płyta z STM32F103RBT6 i ekranem TFT. Zdjęcie z eBay'a:

Tutaj mamy już pełnoprawne debugowanie w pełnoprawnym IDE (spośród wszystkich najbardziej przypadło mi do gustu Coocox IDE), jednak przydałby nam się osobny programator-debugger ST-LINK ze złączem JTAG (kwestia cena wynosi 20-40 dolarów w serwisie eBay). Alternatywnie można dokupić płytkę rozwojową STM32F4Discovery, na której ten programator jest już wbudowany i można jej używać osobno.

Malina PI

I na koniec, dla pragnących pełnej integracji ze współczesnym światem, przygotowaliśmy komputery jednopłytkowe z Linuxem, znanym już chyba każdemu – Raspberry PI. Zdjęcie z eBay'a:

To pełnoprawny komputer z Linuxem, gigabajtem RAM-u i 4-rdzeniowym procesorem na pokładzie. Na krawędzi płytki znajduje się panel 40 pinów, pozwalający na podłączenie różnych urządzeń peryferyjnych (piny są dostępne z poziomu kodu np. w Pythonie, nie mówiąc już o C/C++), jest też standardowe USB w postaci 4 złącza (można podłączyć WiFi). Jest też standardowe złącze HDMI.
Moc tablicy wystarczy nie tylko do wyświetlania czasu, ale także do uruchomienia serwera HTTP służącego do ustawiania parametrów poprzez interfejs WWW, ładowania prognozy pogody przez Internet i tak dalej. Ogólnie rzecz biorąc, jest dużo miejsca na lot fantazji.

Z Raspberry (i procesorami STM32) jest tylko jedna trudność - jej piny wykorzystują logikę 3 V, a większość urządzeń zewnętrznych (na przykład ekrany LCD) działa „staroświeckim sposobem” od 5 V. Oczywiście można to tak podłączyć i w zasadzie będzie działać, ale nie jest to do końca poprawna metoda, a szkoda psuć płytkę za 50 dolarów. Prawidłowym sposobem jest użycie „konwertera poziomów logicznych”, który w serwisie eBay kosztuje tylko 1-2 USD.
Zdjęcie z eBay'a:

Teraz wystarczy podłączyć nasze urządzenie przez taki moduł, a wszystkie parametry będą spójne.

ESP8266

Metoda jest dość egzotyczna, ale dość obiecująca ze względu na zwartość i niski koszt rozwiązania. Za bardzo niewielkie pieniądze (około 4-5 dolarów na eBayu) można kupić moduł ESP8266 zawierający procesor i WiFi na pokładzie.
Zdjęcie z eBay'a:

Początkowo takie moduły miały pełnić funkcję mostka WiFi do wymiany przez port szeregowy, jednak entuzjaści napisali wiele alternatywnych firmware, które pozwalają im współpracować z czujnikami, urządzeniami i2c, PWM itp. Hipotetycznie całkiem możliwe jest otrzymywanie czasu z NTP i wyślij go przez i2c na wyświetlacz. Dla tych, którzy chcą podłączyć wiele różnych urządzeń peryferyjnych, dostępne są specjalne płytki NodeMCU z dużą liczbą pinów, cena około 500 rubli (oczywiście na eBayu):

Jedynym minusem jest to, że ESP8266 ma bardzo mało pamięci RAM (w zależności od oprogramowania, od 1 do 32 KB), ale to czyni zadanie jeszcze bardziej interesującym. Moduły ESP8266 wykorzystują logikę 3V, więc powyższy konwerter poziomów również tutaj się przyda.

Na tym kończy się wstępna wycieczka po domowej elektronice; autor życzy wszystkim udanych eksperymentów.

Zamiast wniosków

Ostatecznie zdecydowałem się na użycie Raspberry PI ze wskaźnikiem tekstowym skonfigurowanym do pracy z pseudografiką (która okazała się tańsza niż ekran graficzny o tej samej przekątnej). Pisząc ten artykuł, zrobiłem zdjęcie ekranu zegara na pulpicie.

Zegar wyświetla dokładny czas pobrany z Internetu i pogodę, która jest aktualizowana z Yandex, wszystko to jest napisane w Pythonie i działa całkiem dobrze już od kilku miesięcy. Jednocześnie na zegarku działa serwer FTP, który umożliwia (w połączeniu z przekierowaniem portów na routerze) aktualizację oprogramowania na nim nie tylko z domu, ale także z dowolnego miejsca, w którym jest Internet. Jako bonus, zasoby Raspberry w zasadzie wystarczą do podłączenia kamery i/lub mikrofonu z możliwością zdalnego monitorowania mieszkania lub sterowania różnymi modułami/przekaźnikami/czujnikami. Możesz dodać wszelkiego rodzaju „gadżety”, takie jak diody LED informujące o przychodzącej poczcie i tak dalej.

PS: Dlaczego eBay?
Jak widać ceny czy zdjęcia z serwisu eBay zostały podane dla wszystkich urządzeń. Dlaczego tak jest? Niestety nasze sklepy często kierują się zasadą „kupiłeś za 1 dolara, sprzedałeś za 3 dolary i żyjesz z tych 2 procent”. Dla prostego przykładu Arduino Uno R3 kosztuje (w chwili pisania tego tekstu) 3600 rubli w Petersburgu, a na eBayu 350 rubli z bezpłatną wysyłką z Chin. Różnica jest naprawdę o rząd wielkości, bez żadnej literackiej przesady. Tak, na odbiór paczki na poczcie trzeba będzie poczekać miesiąc, ale myślę, że taka różnica w cenie jest tego warta. Ale jeśli jednak ktoś tego potrzebuje właśnie teraz i pilnie, to pewnie jest wybór w lokalnych sklepach, tutaj każdy decyduje sam.

Przedstawiam Państwu wersję elektroniczną zegar mikrokontrolera. Obwód zegara jest bardzo prosty, zawiera minimum części i może być powtarzany przez początkujących radioamatorów.

Konstrukcja zmontowana jest na mikrokontrolerze i zegarze czasu rzeczywistego DS1307. Do wskazania aktualnej godziny służy czterocyfrowy, siedmiosegmentowy wskaźnik LED (bardzo jasny, w kolorze niebieskim, który dobrze prezentuje się w ciemności, a jednocześnie zegar pełni rolę nocnika) światło). Sterowanie zegarem odbywa się za pomocą dwóch przycisków. Dzięki zastosowaniu układu zegara czasu rzeczywistego DS1307 algorytm programu okazał się dość prosty. Mikrokontroler komunikuje się z zegarem czasu rzeczywistego poprzez magistralę I2C i jest zorganizowany programowo.

Schemat zegara:

Niestety na schemacie jest błąd:
— zaciski MK należy podłączyć do baz tranzystorów:
РВ0 do Т4, РВ1 do Т3, РВ2 do Т2, РВ3 do Т1
lub zmień podłączenie kolektorów tranzystorów do cyfr wskaźnika:
T1 do DP1…..T4 do DP4

Części użyte w obwodzie zegara:

♦ Mikrokontroler ATTiny26:

♦ zegar czasu rzeczywistego DS1307:

♦ 4-cyfrowy siedmiosegmentowy wskaźnik LED – FYQ-5641UB-21 ze wspólną katodą (ultra jasny, niebieski):

♦ kwarc 32,768 kHz, o pojemności wejściowej 12,5 pF (można pobrać z płyty głównej komputera), dokładność zegara zależy od tego kwarcu:

♦ wszystkie tranzystory to konstrukcje NPN, można zastosować dowolne (KT3102, KT315 i ich zagraniczne odpowiedniki), ja użyłem BC547S
♦ mikroukładowy stabilizator napięcia typu 7805
♦ wszystkie rezystory o mocy 0,125 wata
♦ kondensatory polarne na napięcie robocze nie niższe niż napięcie zasilania
♦ zasilacz rezerwowy DS1307 – ogniwo litowe 3 V CR2032

Do zasilania zegarka można użyć dowolnej niepotrzebnej ładowarki do telefonu komórkowego (w tym przypadku, jeśli napięcie na wyjściu ładowarki mieści się w granicach 5 woltów ± 0,5 wolta, część obwodu - stabilizator napięcia na chipie typu 7805 - może zostać wyeliminowane)
Pobór prądu urządzenia wynosi 30 mA.
Do zegara DS1307 nie trzeba instalować baterii zapasowej, ale wówczas w przypadku zaniku zasilania sieciowego konieczne będzie ponowne ustawienie aktualnej godziny.
Nie podano płytki drukowanej urządzenia; konstrukcja została zmontowana w obudowie z wadliwego zegarka mechanicznego. Do oddzielenia godzin i minut na wskaźniku służy dioda LED (z częstotliwością migania 1 Hz, z pinu SQW DS1307).

Ustawienia mikrokontrolera są fabryczne: częstotliwość taktowania - 1 MHz, bity FUSE nie wymagają dotykania.

Algorytm działania zegara(w Konstruktorze algorytmów):

1. Ustawianie wskaźnika stosu
2. Ustawianie timera T0:
— częstotliwość SK/8
- przerwania przepełnienia (przy tej zadanej częstotliwości przerwanie wywoływane jest co 2 milisekundy)
3. Inicjalizacja portów (piny PA0-6 i PB0-3 konfigurujemy jako wyjście, PA7 i PB6 jako wejście)
4. Inicjalizacja magistrali I2C (piny PB4 i PB5)
5. Sprawdzenie 7. bitu (CH) zera rejestru DS1307
6. Włącz globalne przerwanie
7. Wejście w pętlę i sprawdzenie czy przycisk został wciśnięty

Przy pierwszym włączeniu lub ponownym włączeniu, jeśli DS307 nie ma zasilania rezerwowego, bieżący czas zostaje zresetowany do pierwotnego ustawienia. W tym przypadku: przycisk S1 – ustawienie czasu, przycisk S2 – przejście do kolejnej cyfry. Ustaw czas - do DS1307 zapisywane są godziny i minuty (sekundy są ustawione na zero), a pin SQW/OUT (7-ty pin) jest skonfigurowany do generowania impulsów fali prostokątnej o częstotliwości 1 Hz.
Po naciśnięciu przycisku S2 (S4 - w programie) przerwa globalna zostaje wyłączona, program przechodzi do podprogramu korekty czasu. W tym przypadku za pomocą przycisków S1 i S2 ustawia się dziesiątki i jednostki minut, następnie od 0 sekund naciśnięcie przycisku S2 rejestruje zaktualizowany czas w DS1307, rozwiązuje przerwanie globalne i wraca do programu głównego.

Zegarek wykazywał dobrą dokładność, miesięczna strata czasu wyniosła 3 sekundy.
Aby poprawić dokładność, zaleca się podłączenie kwarcu do DS1307, jak wskazano w arkuszu danych:

Program napisany jest w środowisku Algorithm Builder.
Na przykładzie programu zegarowego można zapoznać się z algorytmem komunikacji mikrokontrolera z innymi urządzeniami poprzez magistralę I2C (każda linia jest szczegółowo komentowana w algorytmie).

Zdjęcie zmontowanego urządzenia i płytki drukowanej w formacie .lay od czytelnika strony Anatolija Pilguka, za co mu serdecznie dziękujemy!

W urządzeniu zastosowano: Tranzystory - SMD BC847 oraz rezystory CHIP

Załączniki do artykułu:

(42,9 KiB, 3233 odsłon)

(6,3 KiB, 4183 odsłon)

(3,1 KiB, 2662 odsłon)

(312,1 KiB, 5932 odsłon)


Druga wersja programu zegarowego w AB (dla tych, którzy nie mogą pobrać wyższej)

(11,4 KiB, 1947 odsłon)