
Witajcie moi drodzy
Dzisiaj przedstawię mój projekt prostego zegara/kalendarza opartego o mikrokontroler PIC16F1455, gotowy moduł wyświetlacza ośmiocyfrowego na MAX7219 oraz gotowy moduł RTCC (zegara/kalendarza) DS1302, zasilanego i konfigurowanego przez USB. Do zegara zaprojektowałem własną obudowę którą wydrukowałem na drukarce 3D.
Całość opiszę bardzo szczegółowo, wraz z osobnymi krokami któremu podjąłem w trakcie projektowania całości i umieszczę opracowane po drodze przykładowe kody dla PICa.
Założenia projektu
Założenia projektu powstawały w trakcie jego wykonywania, ale tutaj podam ich ostateczną, aktualną wersję.
- projekt będzie bazować na mikrokontrolerze PIC16F1455 i wykorzysta oferowany przez niego wewnętrzny oscylator wysokiej precyzji oraz sprzętowe USB
- do wyświetlania zostanie użyty moduł 7-segmentowego wyświetlacza na MAX7219
- do mierzenia czasu zostanie użyty moduł RTCC DS1302 z bateryjką
- ustawienie godziny będzie możliwe jedynie przez USB (poprzez HID)
- układ zasilany będzie przez USB z 5V z dowolnej ładowarki/powerbanku
- firmware napiszę w MikroC PRO for PIC w języku C
- obudowę zaprojektuję w Blenderze i wydrukuję na swojej drukarce Ender PRO 3
- zegar będzie wyświetlać na przemian datę i godzinę
- wszystkie kody i pliki modelów 3D będą opublikowane na forum
Użyte części, moduły
Tutaj wypiszę najważniejsze elementy elektroniczne jakich użyłem do zrealizowania projektu.
8-bitowy mikrokontroler PIC16F1455 w obudowie DIP14:


Mikrokontroler ze sprzętowym USB, SPI, UART, PWM, dwoma Timerami 8-bitowymi i jednym 16-bitowym. 14kB pamięci Flash i 1kB RAM. Dodatkowo posiadający precyzyjny wewnętrzny oscylator, co pozwala na użycie USB bez potrzeby podłączania na zewnątrz oscylatora kwarcowego.
Do zakupienia za jakieś 6 zł, np. w TME.
Nota katalogowa PIC16F1455 do pobrania:
Wyświetlacz 7-segmentowy ośmiocyfrowy na MAX7219 z interfejsem SPI:

Prosty moduł wyświetlacza 7-segmentowego, ośmiocyfrowego z kropkami. Niestety bez dwukropka. Oparty o układ scalony MAX7219, dzięki czemu do sterowania wymaga tylko kilku pinów. Korzysta z protokołu SPI.
Moduł zakupiłem na eBayu za 1.73£, czyli jakieś 9 zł.

Nota katalogowa MAX7219 (samego układu, nie modułu) do pobrania:
Moduł zegara/kalendarza RTCC DS1302 z bateryjką:

Moduł zegara/kalendarza DS1302 ma na pokładzie rezonator kwarcowy zegarkowy 32.768kHz i bateryjkę CR2032. Ustawiony raz czas jest pamiętany po odłączeniu zasilania dzięki tej bateryjce.
Również zakupiony na eBayu (w zestawie od razu była bateryjka), całość za 0.99£, czyli około 5 zł:

Nota katalogowa DS1302 (samego układu, nie modułu):
Oprócz tego użyłem drobnicy, kilka rezystorów, kondensatorów podstawki pod PICa, oraz płytki uniwersalnej:

I oczywiście filamentu PLA do wydruku obudowy.
Szczegółowy opis kroków konstrukcji
Poniżej opiszę krok po kroku jak powstawał projekt, załączę zdjęcia i zrzuty ekranu z postępów prac. Sprecyzuję jakie problemy po drodze musiałem rozwiązać, oraz umieszczę kody źródłowe opracowane na każdym etapie (są one zorganizowane tak, że każdy stanowi osobną całość - przykład użycia PICa).
Krok 1 - Uruchomienie PICa (miganie diodą)
Na samym początku postanowiłem uruchomić najprostsze miganie diodą na PICu, to praktycznie zawsze jest wstępem do większych projektów.
Do wgrywania wsadu postanowiłem użyć mojego klonu PICKIT2:

Na płytce uniwersalnej podłączyłem PICa, dałem mu kondensator 100nF między piny zasilania i rezystor 10k na pin MCLR/RESET. Podłączyłem go poprzez ICSP do programatora:



PICKIT2 początkowo nie wspierał PIC16F1455, ale dzięki nieoficjalnym aktualizacjom pliku PK2DeviceFile.dat teraz go wspiera, więc od razu u mnie go rozpoznał:

Zaktualizowane pliki PK2DeviceFile.dat można pobrać za darmo z forum Microchipa za darmo, tak jak soft PICKIT2, ale w razie czego też go wrzucę tutaj:
Uruchomiłem MikroC PRO for PIC, w którym napisałem prosty program blink, skonfigurowany tak by używał wewnętrznego oscylatora z PICa:

Na płytce stykowej podłączyłem dodatkowo diodę i rezystor i w ten sposób udało się uzyskać pierwsze oznaki życia układu:


Załącznik - PIC16F1455 blink (najprostsze miganie diodą LED) - (projekt MikroC, kod C, skompilowany wsad) do pobrania:
Krok 2 - Test UART
Następnie wziąłem się za uruchamianie komunikacji UART z PICa do komputera (poprzez przejściówkę na USB).
Na tym etapie nie zdecydowałem jeszcze się na USB, dlatego eksperymentowałem z UART. Na koniec jednak UART nie użyłem, jednakże załączę tu i tak mój przykładowy kod/projekt, bo może komuś się przyda.
PIC16F1455 ma funkcje TX/RX UART na następujących pinach:

Podłączyłem do komputera tylko pin RX poprzez tą przejściówkę:

I użyłem biblioteki UART z MikroC ( https://download.mikroe.com/documents/compilers/mikroc/pic/help/uart_library.htm ) do wysłania tekstu na PC:

Uruchamianie UART na tym PICu przebiegło bez problemów, jednak ostatecznie go nie użyłem, dlatego że USB jest wygodniejsze oraz o ile dobrze pamiętam to jeden z pinów PIC16F1455 współdzielił funkcję UART z SPI, czego obsługa nieco skomplikowałaby projekt.
Załącznik - PIC16F1455 UART - (projekt MikroC, kod C, skompilowany wsad) do pobrania:
Krok 3 - Programowanie komunikacji z MAX7219
Następnie postanowiłem uruchomić moduł MAX7219:


Używa on protokołu SPI do komunikacji.
Do komunikacji z nim używa się tych pinów (te po drugiej stronie nie są potrzebne):

- VCC (zasilanie, 5V)
- GND (masa)
- DIN (do podłączenia do SDO; wejścia danych z SPI)
- CS (Chip Select; pozwala wybrać cel komunikacji SPI, dzięki czemu na jednej magistrali SPI możemy mieć wiele urządzeń)
- CLK (zegar od SPI)
Nie ma tu pinu 'data out' (SDI od PICa nie podłączamy), komunikacja jest jednostronna.
W PIC16F1455 jest możliwość użycia SPI sprzętowego, chociaż można też zaimplementować go w pełni w software.
Tym razem postanowiłem zrobić to sprzętowo, przy użyciu portu SPI oferowanego przez PIC16F1455:

Port ten obsługuje biblioteka SPI od MikroC, ale oczywiście samą komunikacje przez SPI z MAX7219 trzeba już było napisać samemu.
https://download.mikroe.com/documents/compilers/mikroc/pic/help/spi_library.htm
Podłączyłem wyświetlacz do odpowiednich pinów:


I opracowałem odpowiednie funkcje do jego obsługi:

Użyłem też do tego materiałów z forum MikroC i przykładów dla macierzy LED na tym samym układzie scalonym.
W tabelce zamieszczam skromną dokumentacje opracowanego kodu:
Funkcja | Argumenty | Opis |
MAX7219_SPI_Init | brak | Inicjuje moduł MAX7219 |
MAX7219_SPI_Clear | brak | czyści wyświetlacz MAX7219 |
MAX7219_SPI_WriteChar | pozycja, znak, czyKropka | wyświetla dany znak na danej pozycji wyświetlacza, jeśli trzeci argument to fałsz to gasi kropkę, w przeciwnym razie ją zapala |
MAX7219_SPI_WriteString | tekst | wyświetla tekst na wyświetlaczu (ale dużo znaków nie jest wspieranych) |
MAX7219_SPI_WriteStringWithDots | tekst | wyświetla tekst na wyświetlaczu; w inteligentny sposób obsługuje kropki, gdyż na tym wyświetlaczu kropki należą do danej cyfry |
Rezultat działania kodu na zdjęciach:


Załącznik - PIC16F1455 SPI MAX7219 - (projekt MikroC, kod C, skompilowany wsad) do pobrania:
Krok 4 - Programowanie komunikacji USB
Następnie postanowiłem uruchomić komunikację USB (dokładniej: HID).
Pomysł był taki, że spróbuję odbierać przez HID ciąg znaków i wyświetlać go na MAX7219.
Przy użyciu tego PICa komunikacja HID jest banalnie prosta. Nie wymaga zewnętrznych elementów a biblioteka pod nią jest gotowa w Mikro C.
USB w PIC16F1455 znajduje się na tych pinach:

Do obsługi USB służy ta biblioteka:
https://download.mikroe.com/documents/compilers/mikroc/pic/help/usb_hid_library.htm
Na początek do kodu podpiąłem struktury deskryptora USB. Utworzone urządzenie będzie miało USB_VENDOR_ID (aka VID) 0x1234, tak jak widoczne na obrazku poniżej:

Dodatkowo do pola 'Product string descriptor' wpisałem nazwę USB HID Clock20, co też przyda się potem przy identyfikacji naszego urządzenia gdy mamy wiele innych rzeczy podłączonych na USB:

Uzupełniłem kod o niezbędną inicjalizację i komunikację HID.
Do układu z PICem dodałem złącze micro USB:



Wtedy cały układ prezentował się już tak (wciąż miałem podłączonego MAX7219 z poprzedniego punktu):

Wgrałem wsad i usłyszałem znajomy dźwięk podłączenia nowego urządzenia do Windowsa - czyli PIC został rozpoznany!
Moje urządzenie o identyfikatorze 0x1234 pojawiło się w Menedżerze urządzeń:

Kod programu zmodyfikowałem tak, by wyświetlał na podłączonym wyświetlaczu to co zostanie odebrane przez USB/HID.
Całość postanowiłem testować poprzez Terminal HID od MikroC. Działa on podobnie jak terminal UART - można przez niego wysłać dane, tyle że po HID.
Włącza się go z poziomu Mikro C z zakładki Tools:

Od razu pojawiło się w nim moje urządzenie ("USB HID Clock20"):

Ostatecznie, przetestowałem działanie nowego programu.
Wysyłanie stringu "1 2 3 4 " przez HID Terminal:

Rezultat na MAX7219:

Wysyłanie stringu "1999.12.23" przez HID Terminal:

Rezultat na MAX7219:

W ten sposób uruchomiłem komunikację poprzez USB i mogłem przejść do kolejnego etapu projektu.
Załącznik - PIC16F1455 USB + MAX7219 - (projekt MikroC, kod C, skompilowany wsad) do pobrania:
Krok 5 - Obsługa czasu z RTCC DS1302
Kolejnym krokiem było uruchomienie RTCC DS1302. W tym kroku bardzo pomocny był przykładowy kod komunikacji z tym RTCC dla Arduino:
https://playground.arduino.cc/Main/DS1302/
Swoje rozwiązanie oparłem o ten kod, a właściwie wręcz go skopiowałem i uruchomiłem u siebie za pomocą sprytnego użycia preprocesora C:

Funkcji do konwersji BCD użyłem stąd:
https://download.mikroe.com/documents/compilers/mikroc/pic/help/conversions_library.htm
Niestety część kodu dotyczącą struktury czasu musiałem przepisać, gdyż Mikro C chyba ze względu na padding w niechciany sposób odczytywał jej pola.
Na początku testowałem wszystko na sztywno ustawiając bieżącą datę w kodzie na starcie programu, ale w następnym kroku opiszę na to lepsze rozwiązanie.
Krok 6 - Ustawianie bieżącego czasu przez USB
Ten punkt jest poniekąd powiązany mocno z poprzednim punktem. Po uruchomieniu RTCC dodałem możliwość ustawienia daty/godziny przez USB, analogicznie do tego jak wcześniej testowałem wysyłanie napisu do wyświetlania przez HID.
Datę/godzinę do ustawienia przyjąłem w takim formacie:
"SS MM HH dd mm yy"
Są to kolejno:
- SS - wartość sekund (dwie cyfry)
- MM - wartość minut (dwie cyfry)
- HH - wartość godzin (dwie cyfry)
- dd - wartość dni (dwie cyfry)
- mm - wartość miesięcy (dwie cyfry)
- yy - wartość lat minus 2000 (dwie cyfry)
Tego formatu napis wysyła się przez HID do zegara by ustawić bieżący czas, przykładowo wysyłanie "00 15 22 20 02 20" wygląda tak (ze spacjami!):

Po odebraniu pakietu z HID zegar dekoduje go i zapisuje w RTCC jako bieżący czas. RTCC na bieżąco odlicza czas, nawet po odpięciu zasilania od zegara, bo ma bateryjkę. Program zegara ciągle pokazuje bieżący czas na wyświetlaczu.
Rezultat wyświetlony przez zegar (zdjęcie robione chwilę później, stąd różnica w czasie):


Zegar raz wyświetla datę, a raz godzinę.
Na tym etapie część programistyczna tworzenia zegara była już w zasadzie skończona - dalszych zmian we wsadzie nie wprowadzałem.
Załącznik: finalny firmware zegara (wiele można by tam poprawić, ale działa; kod, hex, projekt Mikro C):
Krok 7 - Lutowanie 'partyzanckie' na uniwersalnej wierconej płytce
Teraz przyszła kolej na przeniesienie projektu z płytki stykowej na lutowaną uniwersalną. Postanowiłem, że będzie się ją łączyć z modułem RTCC z pomocą wtyku na goldpiny 2.54mm, a wyświetlacz będzie podłączany kabelkami. Przygotowałem potrzebne elementy:

Następnie rozpoczął się żmudny proces lutowania i kombinowania, nie będę go tutaj szczegółowo opisywać, ale i tak zamieszczę zdjęcia:





Gotowa elektronika:

Krok 8 - Projekt 3D obudowy i wydruk jej
Obudowę do zegara zaprojektowałem od zera w programie Blender i wydrukowałem na drukarce 3D Creality Ender 3 PRO.
Obudowę robiłem w ten sposób, że na przemian mierzyłem i drukowałem małe testowe fragmenty, taka metoda pozwala mi uniknąć sytuacji w której po kilkugodzinnym wydruku okazuje się że coś było źle zwymiarowane.
Zacząłem od zwymiarowania wyświetlacza:


Raz poprawiałem wymiary, za drugim razem wyszło idealnie:


Następnie naniosłem cztery otwory na mocowanie wyświetlacza i poszerzyłem część obudowy, na razie jedynie od jej frontu:


Znów wydrukowałem całość do sprawdzenia i przymiarek:



Wykonałem kolejne poprawki na modelu:

I po wydruku sprawdziłem mocowanie wyświetlacza oraz modułu RTCC za pomocą śrubek. Dobrze się je wkręca do filamentu PLA, jest on na tyle miękki, że da się je wkręcić i na tyle twardy, by je dobrze trzymać. Ale oczywiście z czasem gwint się wyrabia i już tak nie trzyma.


Zegar uruchomiony w celu sprawdzenia czy nic się nie popsuło:

W tym momencie dopiero miałem już cały koncept obudowy. Uznałem, że tył nie będzie ściągany, więc z dolnych śrubek od wyświetlacza trzeba będzie zrezygnować, ale mimo to wyświetlacz dalej się dobrze trzymał.
Zrobiłem też z tyłu otwór na złącze USB:

Po raz ostatni zaimportowałem STLe do Cura:

I wydrukowałem finalny element:



I jeszcze pokrywa:

Wydruk pokrywy:

Do zamocowania pokrywy użyłem śrubek z jakiegoś zezłomowanego laptopa:


I wreszcie moment przykręcania pokrywy i finalizacji projektu:

Wyszło nieźle, chociaż sam wydruk mógłby być lepszej jakości.
Załącznik: źródła .blend (model 3D programu Blender) obudowy:
Załącznik: pliki .STL (wyeksportowane do STL dwie części) obudowy:
Gotowy zegar - zdjęcia
Tutaj umieszczę zdjęcia już gotowego w pełni projektu.
Zegar zasilany przez USB z komputera, jeszcze na roboczym stole:


(Ciekawostka: w rogu powyższych zdjęć widać coś co też wkrótce będę wrzucać na forum, ale nie jest to związane z tym zegarem)

Zegar z ładowarką od telefonu Xiaomi, która też oczywiście może go zasilać:

Zegar na boku (zdjęcie ukazuje dopasowanie wyświetlacza do obudowy):

Zegar zasilany z power banka (oczywiście nie mojego):


Próba pomiaru poboru prądu przez zegar:

Pobór prądu jest tak mały że USB Doctor nawet go nie wykrywa, pewnie mniej niż 0.01A, oczywiście to zależy też od tego ile segmentów LED się świeci.
Zegar na szafce, w nocy:


Dodatek - program do ustawiania bieżącej godziny
W celu odłączenia się od "HID Terminal" z MikroC przygotowałem narzędzie które oferuje podobną funkcjonalność.
Prezentuje się ono tak:

Po wysłaniu pakietu jest odpowiedni komunikat:

Program też oczywiście wykrywa, czy w ogóle nasze urządzenie (o VID 0x1234 i PID 0x0001, jak wspomiane wcześniej) jest podłączone:

Za pomocą tego programu można łatwo ustawić bieżący czas w moim zegarku - po prostu naciska się najpierw przycisk ustawiający tekst daty, a potem przycisk wysyłający go przez HID.
Załącznik do pobrania (wymaga NET Framework 2):
Dodatek - schemat projektu
W trakcie projektu tworzenia projektu nie posiadałem żadnego schematu a całość tworzyłem w oparciu o dokumentację PICa i modułów, ale pod koniec uznałem, że warto będzie takowy narysować, zwłaszcza dla zainteresowanych projektem czytelników z forum.

Schemat chyba nie wymaga wyjaśnienia, chociaż można by tu dać jeszcze na zasilanie kondensator elektrolityczny o małej pojemności. I może jakieś rezystory pull-up/pull-down, ale u mnie działa bez nich.
Ten sam schemat do pobrania w formacie .sch z Eagle:
Dodatek - załączniki
Linki do niektórych załączników są też w tekście, ale dam je tutaj jeszcze raz w tabelce dla przejrzystości.
Cały projekt jest open source/open hardware, jak zaprojektuję pod niego PCB to też je udostępnię.
Nazwa | Opis | Załącznik |
p16f1455_blink_intOsc | Przykładowy kod migania diodą LED na PIC16F1455 | |
p16f1455_uart_intOsc | Przykładowy kod wysyłania danych przez UART na PIC16F1455 | |
p16f1455_spi_max7219_intOsc | Przykładowy kod obsługi MAX7219 przez SPI na PIC16F1455 | |
p16f1455_usb_and_spi_max7219_intOsc | Przykładowy kod odbioru danych przez HID i wyświetlania ich na MAX7219 przez SPI na PIC16F1455 | |
p16f1455_usb_and_ds1302_spi_max7219_intOsc | Finalny kod zegarka | |
Schemat Eagle | Schemat poglądowy zegara w formacie .sch programu Eagle | |
clockPIC16F1455_20.blend | Źródła modelu w formacie .blend programu Blender | |
clockPIC16F1455_20_stl | Modele obudowy (podstawa i pokrywa, dwa pliki) w formacie STL | |
MyHIDTerminal | Prosty terminal do wysyłania danych przez z HID z funkcjonalnościa automatycznego formatowania stringu daty/godziny dla zegara |
Dalszy rozwój projektu
Projekt powstał "na raty" w przeciągu kilku dni więc siłą rzeczy jest dość skromny. Wiele można by ulepszyć. Przede wszystkim myślę o:
- lepszy, bardziej 'zegarkowy' wyświetlacz - użyty wyświetlacz nie ma dwukropka i niektórym osobom może to przeszkadzać; przydałoby się znaleźć lepszy wyświetlacz z dwukropkami, ale w tej chwili takiego modułu nie znam. Może ktoś z czytelników poleci taki moduł wyświetlacza (ale mający te 8 cyfr, bo 4-cyfrowe widziałem)?
- PCB pod ten konkretny projekt - przydałoby się zaprojektować PCB pod ten konkretny projekt, pasujące idealnie do obudowy, pewnie na wzór tego które ja przygotowałem
- dodać pomiar temperatury itd. itp. - PIC ma jeszcze co najmniej jeden pin wolny, do tego można pewnie wykorzystać lepiej kilka pinów sprytnie używając Chip Select od SPI. Można by dodać np. pomiar temperatury i wilgotności na czujniku DHT11/DHT22 lub podobnym
- wyprowadzić złącze ICSP - dla wygodniejszego programowania; można by te 5 pinów potrzebnych do programowania dać na obudowę
- wprowadzić system aktualizacji programu przez bootloader USB - zamiast wyprowadzania złącza ICSP można by użyć bootloadera, ale w tej chwili nawet nie wiem czy byłoby to dużo pracy dla PIC16F1455 bo jeszcze się tym nie zajmowałem
- sprawdzić/dodać obsługę ustawiania daty przez USB z poziomu telefonu z systemem Android - na ten moment można to zrobić tylko z komputera, nie wiem jak wygląda kwestia z Androidem, ale ustawienie daty to zasadniczo tylko wysłanie jednego pakietu HID
- ulepszyć model obudowy - schować śrubki albo dać je na spód, wydrukować w lepszej jakości
- wykonać inną obudowę, nie z drukarki 3D - przykładowo drewnianą, ale nie wiem czy jest to teraz w zasięgu moich możliwości
- przejrzeć i przepisać kod - bieżący kod działa raczej bez błędów, ale można by go zrobić bardziej elegancko
Podsumowanie
Z projektu mojego zegara/kalendarza jestem zadowolony. Całość powstała spontanicznie w przeciągu paru dni na skutek kilku godzin wolnego czasu. Głównym mankamentem jest tutaj brak dwukropka na wyświetlaczu, ale mi on wcale nie przeszkadza. Wkrótce być może wykonam drugą wersję tego zegara, już z dedykowanym PCB zaprojektowanym w Eagle i jakąś dodatkową funkcjonalnością, chociażby czujnikiem DHT11.
Cool? Ranking DIY