Zegar biurkowy na atmega328 i woltomierzach analogowych – akt drugi

Zegar biurkowy na atmega328 i woltomierzach analogowych – akt drugi

Witam Was ponownie!

Zachęcony pozytywnymi komentarzami oraz ocenami pierwszej części artykułu dotyczącego budowy „analogowego” zegarka (do postawienia np. na biurku w pracy) niezwłocznie przystąpiłem do realizacji i opisywania części drugiej. A w niej – podłączenie naszych woltomierzy do mikrokontrolera, podłączenie zewnętrznego układu zegara RTC – DS1307 i próba (miejmy nadzieję że skuteczna) złożenia tego wszystkiego do kupy. Zaczynamy!

Po poprzedniej części jesteśmy w posiadaniu dwóch woltomierzy, przeskalowanych na napięcia przyjazne dla naszego mikrokontrolera, z zamontowanymi diodami ułatwiającymi odczyt godziny po ciemku i z wymienionymi podziałkami.

Jako, że niestety nie jestem szczęśliwym posiadaczem płytki Arduino,  muszę wykonać parę kroków zanim będę mógł zacząć programować. Pierwsze co należy zrobić to prawidłowe podłączenie mikrokontrolera ATmega 328P-PU do zasilania. Jak zapewne każdy z Was wie (a jeżeli nie wie to zaraz się dowie) od prawidłowego podłączenia mikrokontrolera do zasilania bardzo często zależy jego prawidłowa praca. Artykułów w tzw. „Internetach” traktujących o prawidłowym sposobie podłączania zasilania do mikrokontrolerów jest bez liku, także nie rozwodząc się przedstawiam schemat wg którego ja będę zasilał swój układ.

schemat podłączenia01

Jak widać na wejściu układu znajduje się stabilizator napięcia 7805. Cały układ będzie zasilany ze starej ładowarki od telefonu pewnej znanej fińskiej firmy, który to zasilacz ma na wyjściu napięcie około 8V, które stabilizujemy do 5V przy pomocy (niespodzianka ;) ) stabilizatora napięcia. Umiejscowienie i wielkości pozostałych elementów znajdujących się w układzie (kondensatorów, dławika oraz rezystora) wynika z danych wyczytanych z datasheet’a mikrokontrolera.

Mając już taki układ na płytce stykowej możemy podłączyć do niego woltomierze. Z tyłu obudowy każdego woltomierza znajdują się dwa zaciski – „+” oraz „-”. Jak łatwo się domyśleć – zacisk „-” podłączamy do masy układu, natomiast zacisk „+” podłączamy do pinu pozwalającego na podanie sygnału PWM – w przypadku mikrokontrolera atmega328 w obudowie do montażu przewlekanego są to piny 5,11,12,15,16,17 – ja, mając na uwadze dalsze projektowanie płytki drukowanej do całego układu podłączyłem woltomierz wskazujący godzinę pod pin 5 (który odpowiada pinowi 3 Arduino), natomiast ten od minut – pod pin 12 (pin 6 Arduino), zgodnie z poniższym schematem:

schemat podłączenia02

Uwaga – jeżeli nie jesteście pewni, który pin ma jaką nazwę/funkcjonalność polecam zerknąć albo do datasheet’a mikrokontrolera albo na tą grafikę.

Dlaczego piszę o tym, który jest to pin w Arduino? Ponieważ grzechem byłoby nie skorzystać z dobrodziejstw i ułatwień, które niesie ze sobą zastosowanie oprogramowania Arduino IDE, które bez przeszkód możemy zmusić do używania programatorów dostępnych na rynku jak USBasp i programowania zwykłych mikrokontrolerów. (po więcej informacji jak to zrobić odsyłam do tego artykułu i tego wątku na forum)

A więc mamy już gotowe środowisko programistyczne oraz prawidłowo zasilony układ – czas coś napisać!

Pierwszy program, który wgramy na mikrokontroler będzie miał za zadanie sprawdzić, czy nasz woltomierz jest dobrze przeskalowany.

Program nie jest skomplikowany, ale wyjaśnijmy szybko jego działanie. Najpierw definiujemy używane przez nas piny jako wyjścia układu. Następnie w nieskończonej pętli ustawiamy sygnał PWM o wypełnieniu 100% (wartość wypełnienia sygnału PWM mieści się w przedziale 0-255, gdzie 0 oznacza cały czas stan niski, a 255 – stan wysoki), a po odczekaniu 5 sekund zmieniamy jego wypełnienie na 0%. Jeżeli przeskalowaliśmy nasz woltomierz prawidłowo, jego igła powinna przez 5 sekund być zatrzymana dokładnie na wartości maksymalnej, by następnie przez 5 sekund opaść dokładnie na 0. Jeżeli igła nie osiąga dokładnie którejś ze skrajnych wartości – musimy wprowadzić poprawki:

– jeżeli igła nie zatrzymuje się idealnie na 0 (czyli zatrzymuje się powyżej lub poniżej zera) – musimy delikatnie obrócić cały mechanizm odpowiadający za wychylanie igły – w moim przypadku najbezpieczniej to zrobić używając jako „dźwigni” odchodzącej pionowo w dół blaszki, którą zaznaczyłem na poniższym zdjęciu – wystarczy delikatnie obrócić ją zgodnie, bądź przeciwnie do ruchu wskazówek zegara żeby przestawić położenie zerowe igły.

blaszka

– jeżeli igła nie zatrzymuje się idealnie na wartości maksymalnej – musimy zmienić nastawę naszego potencjometru wieloobrotowego tak, aby igła osiągnęła dokładnie zadaną wartość.

Możliwie dokładna kalibracja pozwoli nam uzyskać dość dokładne odczyty godziny z gotowego zegara, także warto się do tego przyłożyć!

Następnie zajmiemy się przekazaniem do naszego układu informacji o tym, która jest godzina. W tym celu użyjemy bardzo popularnego układu DS1307. Jako, że od urodzenia byłem leniem – zamiast kupić układ i wszystkie inne potrzebne do niego rzeczy osobno i zmontować je samemu, wydałem parę złotych więcej i kupiłem gotową, niewielką płytkę zawierającą w sobie układ zegara RTC (akronim angielskiego określenia Real Time Clock – zegar czasu rzeczywistego), kwarc zegarkowy, kondensatory filtrujące zasilanie układu oraz złącze baterii zegarkowej, służącej do podtrzymania liczenia czasu przez układ w przypadku zaniku podstawowego napięcia zasilania. Co ważne, na płytce znajdują się także dwa rezystory o wartości 4,7kΩ każdy, podciągające linie sygnałowe do napięcia zasilania – utrzymują one stan wysoki na liniach w czasie, gdy nie ma na nich transmisji danych.

Płytkę podłączamy do układu zestawem 6 goldpinów – 5V, GND, SQW, SCL, SDA, VBAT. Bardziej spostrzegawczy z Was po zauważeniu pinów opisanych jako SCL oraz SDA wiedzą już jak nasze układy będą się ze sobą komunikować – chodzi oczywiście o interfejs I²C (ze względów licencyjnych występujący czasami pod alternatywną nazwą TWI – Two Wire Interface). W swoim projekcie, ze względu na jego prostotę będę używał tylko 4 z 6 pinów – piny SQW oraz VBAT nie będą mi potrzebne (choć można by np. pin VBAT podpiąć pod przetwornik ADC atmegi i kontrolować, czy aby bateria nam się nie rozładowała). Wpinamy płytkę, podłączamy ją kabelkami zgodnie z poniższym schematem:

schemat podłączenia03

W celu obsłużenia układu DS1307 pobieramy jedną z dziesiątek bibliotek, które mają za zadanie ułatwiać obsługę tego układu. Ja zdecydowałem się na bibliotekę o wiele mówiącej nazwie DS1307RTC, którą możecie pobrać stąd. W celu prawidłowego działania biblioteka ta potrzebuje także obecności biblioteki Time, jeżeli jeszcze jej nie macie możecie się w nią zaopatrzyć tutaj. Pobrane biblioteki wrzucamy do folderu Arduino/libraries (wrzucamy tutaj całe foldery z bibliotekami!).

Aby móc cokolwiek odczytać z naszego zegara, musimy mu najpierw powiedzieć która jest godzina – ja w pierwszym przykładzie wpisałem do układu godzinę 12:00, którą na późniejszym etapie poprawimy tak, aby była ona zgodna z prawdą. Wgranie godziny do układu zrealizujemy krótkim programem napisanym na podstawie jednego z przykładów dostarczonych z biblioteką:

Zanim zabierzemy się za odczytywanie godziny musimy napisać funkcję, która zamieni nam dwie wartości (np. 12 oraz 30, oznaczające godzinę 12:30) na sygnały PWM podane na piny, pod które podpięte są nasze woltomierze. Będziemy w tym celu wykorzystywali głównie wbudowaną w Arduino funkcję map. Funkcja ta pozwala łatwo przekształcić wartość będącą w jednym przedziale na odpowiednią wartość w innym przedziale (przykładowo wartość 10 z przedziału 0-100 przekształcona na wartość z przedziału 0-10 będzie wynosiła 1). Napisanie takiej funkcji dla minut nie stanowi większego problemu – będzie ona miała postać:

Natomiast analogiczna funkcja dla godzin wymaga już pewnego zastanowienia się. Można oczywiście zrobić to po prostu w ten sposób:

Jednak mi taki sposób wyświetlania godziny się nie podoba. Dlaczego? Ponieważ dysponujemy analogowym woltomierzem, a ten kod wyświetla godzinę w sposób dość „cyfrowy”. O co mi chodzi? Chodzi mi o to, że część „godzinowa” godziny 12:00 zostanie wyświetlona tak samo jak godziny 12:59. Po krótkim zastanowieniu się postanowiłem stworzyć wartość do mapowania, uwzględniającą zarówno godzinę jak i informację o minutach. Najpierw przedstawię kod, a następnie go omówię:

Funkcja ta dostaje dwie wartości całkowite – godzinę oraz minuty i wyświetla je na pinach HOUR_PIN oraz MIN_PIN. Wartość dla pinu MIN_PIN jest tworzona w sposób chyba dość zrozumiały, natomiast wyjaśnienia wymaga wartość dla godzin. W wyniku wykonania kodu z linijek 3-5 w zmiennej h znajduje się wartość z przedziału 0-119, gdzie ostatnia cyfra powstaje na podstawie minut (funkcją „map(m,0,60,0,10)” – mała uwaga – minuty są tak naprawdę z przedziału 0-59, dlatego nigdy ta funkcja nie zwróci 10), a to co jest przed nią powstaje w wyniku pomnożenia godziny przez 10. Wyświetlając taką wartość mamy już wyraźne rozróżnienie między 12:00 a 12:59. Wiersze 6-12 są konsekwencją projektu tarczy woltomierza z godzinami – godziny 12:00-12:29 wyświetlane są na skrajnej prawej części podziałki, natomiast 12:30-12:59 na skrajnej lewej.

Jeżeli mamy już jak wyświetlić godzinę, możemy zabrać się za jej odczytywanie. Drugi przykład załączony do biblioteki DS1307RTC pokazuje nam, jak to zrobić. Po chwili otrzymujemy następujący kod:

Wgrywamy kod na układ i cieszymy się pierwszym namacalnym efektem na to, że ta kupa części i pomysłów walająca się po biurku od jakiegoś czasu ma szanse stać się faktycznie zegarem!

Do zrobienia w tej części zostały dwie rzeczy – oprogramowanie diod doświetlających oraz podpięcie i oprogramowanie przycisków służących do zmieniana wyświetlanej godziny. Zaczniemy od łatwiejszej sprawy, czyli od diod oświetlających.

Ze względu na niski prąd na wyjściach mikrokontrolera (ok. 20mA) diody będziemy załączali poprzez tranzystor PNP. Dla tych, którzy dopiero zaczynają przygodę z elektroniką krótkie wyjaśnienie – w najprostszym ujęciu, tranzystor działa niczym przycisk, jednak jest to przycisk, który załączamy/rozłączamy podając na niego prąd, a nie wciskając go. Użyjemy więc tranzystora jako klucza „dopuszczającego” napięcie do diod zwartych na stałe do masy, a żeby wykorzystać możliwości układu bazę tranzystora podłączymy pod wejście pozwalające na podanie sygnału PWM, tak aby móc dowolnie ściemniać i rozjaśniać diody. Wiemy już, w jaki sposób podłączymy diody do układu, pozostaje jeszcze kwestia wartości które będziemy na nie podawać. Można by oczywiście uzależnić jasność świecenia diod wyłącznie od tego, która jest godzina, ale jest to mało eleganckie rozwiązanie. Lepszym pomysłem jest wykorzystanie fotorezystora. Jest to rezystor, którego rezystancja (oporność) zmienia się wraz z ilością światła na niego padającą. Podłączyć go musimy oczywiście pod konwerter analogowo-cyfrowy (ponieważ zwykły pin nie byłby w stanie rozróżnić takich zmian). Poniższy schemat prezentuje sposób, w jaki połączymy tranzystor z mikrokontrolerem (nie zapominamy o rezystorze na bazie tranzystora!) i dalej tranzystor z diodami znajdującymi się już w woltomierzach, a także fotorezystor pod przetwornik ADC (dodatkowy rezystor tworzy z fotorezystorem dzielnik napięcia, o którym więcej możecie przeczytać tutaj).

schemat podłączenia04

Kod, który będzie odpowiadał za zapalanie diody w zależności od oświetlenia będzie wyglądał następująco:

Użyłem tutaj dwóch stałych – DAYLIGHT_VALUE oraz NIGHTLIGHT_VALUE – dzięki nim diody nie świecą w ogóle przy dużym oświetleniu fotorezystora (czyli przy odczycie przekraczającym wartość DAYLIGHT_VALUE) i rozświetlają się z maksymalną jasnością dla wartości odczytu większej niż 0 (ponieważ przy dzielniku napięcia nie osiągniemy wartości zerowej odczytu). Dlaczego w funkcji map mapuję wartość do zakresu 0-200 a nie 0-255? Ponieważ chciałem, aby (jeżeli jest już to potrzebne) diody zapalały się z jakąś konkretną jasnością, a nie ledwo się żarzyły. Tutaj drobna uwaga – ze względu na fakt, że użyliśmy tranzystora PNP pamiętamy o tym, że „zapalamy” diody stanem niskim (czyli diody zapalone na stałe to PWM o wypełnieniu = 0), a gasimy stanem wysokim (PWM o wypełnieniu = 255).

Podłączając do układu przyciski, które posłużą do przestawiania godziny wykorzystam możliwości zastosowanego przeze mnie mikrokontrolera. Mam na myśli dostępne w atmega328 PCI, czyli Pin Change Interrupt – przerwania wyzwalane zmianą stanu pinu. Standardowo, w atmega328 oraz płytkach Arduino zawierających ten mikrokontroler mamy do dyspozycji dwa piny wywołujące przerwanie zewnętrzne – jest to pin 2 i 3 Arduino (widać to po opisach INT0 oraz INT1). Oprócz tego każdy pin układu (oczywiście oprócz pinów związanych z zasilaniem) opisany jest jako PCINTXX, gdzie XX to kolejna liczba oznaczające odwołanie do tego konkretnego pinu. Jak łatwo się domyśleć pozwala to na “podpięcie” przerwania pod dowolny z pinów mikrokontrolera. Niestety, mimo wszelkich swoich dobrodziejstw oprogramowanie Arduino nie pozwala domyślnie na korzystanie z użytecznej możliwości podpięcia zewnętrznego przerwania pod dowolny pin mikrokontrolera. Na szczęście jest na świecie wiele osób, które poświęcają swój wolny czas na tworzenie tego typu dodatków, z czego my zaraz skorzystamy. Podobnie jak w przypadku biblioteki dla układu DS1307, tak w przypadku PCINT również mamy do wyboru wiele różnych bibliotek oferujących zbliżoną funkcjonalność. Ja zdecydowałem się na użycie biblioteki PinChangeInt, którą pobrałem z tej strony. Zdecydowałem się akurat na tą bibliotekę, ponieważ nie dość, że implementuje ona potrzebne nam przerwania to dodaje ona do nich bardzo użyteczną funkcjonalność. Normalnie, przerwania typu Pin Change Interrupt wywoływane są, jak sama nazwa wskazuje, poprzez zmianę stanu na pinie, niezależnie od tego czy jest to zmiana typu falling, czy rising (zbocze opadające sygnału, czy zbocze narastające) i to do programisty należy rozróżnienie który przypadek miał właśnie miejsce, jednak dzięki użyciu tej biblioteki możemy jedną prostą komendą doprecyzować, czy chcemy aby przerwanie wywoływało się na zbocze opadające, zbocze narastające, czy też chcemy wykrywać każdą zmianę sygnału na pinie. Po przeanalizowaniu paru przykładów i wczytaniu się w dokumentację znajdującą się na stronie biblioteki doszedłem do następującego kodu obsługującego 5 przycisków (jeden odpowiedzialny za włączenie trybu pozwalającego na przestawienie godziny oraz dwie pary – jedna zwiększająca/zmniejszająca godzinę, a druga zwiększająca/zmniejszająca minuty):

Pozostaje jedynie kwestia podłączenia przycisków do mikrokontrolera – jak widzicie w powyższym kodzie przyciski podpiąłem pod piny 0,1,2,4,7 i zadeklarowałem je jako wejścia z włączonym rezystorem podciągającym (pullup). Zaoszczędzi mi to konieczności umieszczania rezystorów podciągających osobno na płytce, wobec czego nasz układ z dołożonymi przyciskami będzie wyglądał tak:

schemat podłączenia05

 Składając do kupy wszystkie powyższe elementy kodu otrzymałem następujący kod obsługujący cały zegar:

 

Cały kod jest bogato opatrzony w komentarze, a jego większość jest pobrana z wcześniej już wyjaśnionych kawałków kodu, także myślę, że nie powinno być trudności ze zrozumieniem sposobu jego działania. Jeżeli jednak jakieś by się pojawiły – proszę o info w komentarzach, postaram się rozwiać wszelkie wątpliwości.

Ostatecznie, nauczony doświadczeniem postanowiłem do układu dołożyć także złącze pozwalające na zaprogramowanie układu bez wyjmowania go z płytki, co zmodyfikowało schemat do ostatecznej wersji:

schemat podłączenia06

No, to by było na tyle w tej części. Trochę tego wyszło, mam nadzieję że nie przejechaliście całości tylko po to żeby dać jakąś słabą ocenę, tylko znaleźliście chwilę czasu na przeczytanie ;) W następnej części zaprojektujemy płytkę drukowaną, wytrawimy ją, zaprojektujemy obudowę, oddamy ją do wycięcia laserowego i złożymy wszystko razem, otrzymując (miejmy nadzieję ;) ) estetyczny i fajny zegarek na biurko. Z racji tego, że wolę pisać o rzeczach które już zrobiłem następna część może powstać z lekkim opóźnieniem – nie wiem ile czasu zajmie firmie wycięcie dla mnie obudowy. Cześć!

Ocena: 4.86/5 (głosów: 90)

Podobne posty

16 komentarzy do “Zegar biurkowy na atmega328 i woltomierzach analogowych – akt drugi

  • Końcowe schematy troszeczkę się poplątały… Jak robię coś na swój użytek to przy takich kombinacjach często nazywam połączenie i daję tylko oznaczenie obok. Mimo iż trzeba skakać wzrokiem trochę, to i tak schemat staję się bardziej czytelny. Spróbuj tak przy następnym.

    Wg mnie 5/5 :) Ogólnie cały pomysł bardzo ciekawy :).

    Odpowiedz
  • Moja uwaga: jeśli robisz schematy tak, jak tutaj, nie zmieniaj położenia konkretnego fragmentu schematu (ostatnie schematy świetnie, wcześniejsze są “przesuwane”).
    Szkoda, że nie ma nagrania pokazującego pracę zegara. W takiej formie, jak jest na chwilę obecną.
    Poza tym naprawdę świetny artykuł. Czekam na pozostałą część.

    Odpowiedz
  • Nie ma to jak dobry pomysł. Tyle rzeczy często mamy w piwnicy, z których coś można zrobić ciekawego. Potrzeba tylko czasu, chęci no i pomysłu. Z drugiej strony dzisiaj sklepów z elementami elektronicznymi jest dużo mniej niż kiedyś i ta dziedzina grzebania w elektronice odchodzi do lamusa.

    Odpowiedz
    • Sklepów tego typu faktycznie jest mniej, ale moim zdaniem nie tyle wynika to ze spadku popularności “grzebania w elektronice” co z popularyzacji internetu i zakupów przez internet – na Allegro, nawet z uwzględnieniem przesyłki duperele elektroniczne kupi się taniej, a sklepy stacjonarne nie dość że mają wyższe koszty to jeszcze żeby się utrzymać w biznesie muszą mieć dużo różnorodnego towaru na stanie, nierzadko zalegającego dość długo aż ktoś przyjdzie i będzie szukał AKURAT tego elementu.

      Odpowiedz
      • Myślę, że oprócz tego dochodzi “modułowość” urządzeń. Prościej jest wymienić cały panel na przykład w telewizorze niż wziąć lutownicę i wymieniać jakieś drobne uszkodzone podzespoły

        Odpowiedz
        • To na pewno w jakimś stopniu też, choć świadomość wśród ludzi procesu planned obsolescence (przejawiająca się chociażby przez artykuł tu, na majsterkowie) i nasza polska mentalność nakazująca nam wycisnąć ze wszystkiego ostatnie soki i reanimować sprzęt, mimo że nierzadko taniej byłoby wymienić go na nowy nie pozwoli całkiem umrzeć dziedzinie “grzebania w elektronice”, moim zdaniem oczywiście ;)

          Odpowiedz
  • Składam powoli całość, a że mój pierwszy DS1307 wariuje to użyłem DS3231 do którego mam większe przekonanie. Myślałem, że będę musiał zmienić bibliotekę ale na szczęście wygląda, że ten RTC działa równie dobrze na tej samej. Nie wiem czy oczekiwać jakichś problemów?
    Zauważyłem też drobny wpływ załączenia podświetlenia. Ja z braku tranzystora PNP zrobiłem na NPN. Po włączeniu podświetlenia wskazówka lekko opada. Nie wiem czy to wpływ przewodów zasilania diod na cewkę miernika i czy ewentualnie można to wyeliminować?

    Odpowiedz
  • Nie widzę na schemacie zewnętrznego rezonatora. Czyżby układ chodził na wewnętrznym? Jeśli tak to jak ustawić ArduinoIDE, żeby zaprogramować uC na wewnętrznym oscylatorze? Udało mi się znaleźć bootloader dla ATmega88P ale dla 328P nie znalazłem i bez zewnętrznego kwarcu 16MHz nie mogę go zaprogramować.

    Odpowiedz

Odpowiedz

anuluj

Masz uwagi?