Odkąd zobaczyłem w internecie zdjęcie zegara podającego tekst w formie tekstu, chciałem taki zegar mieć. Czas mijał, chętka nie chciała odejść więc gdzieś tam z tyłu głowy, pomysł ciągle krążył. Poniżej opiszę jak zrobiłem taki gadżet, wykorzystując antyramę.
Do innego projektu potrzebowałem expandery portów. Dwa expandery po 16 portów każdy a do tego celu wybrałem układ MCP23017, w obudowie SMD. Układ ten sterowany jest za pomocą magistrali I2C, a można połączyć do 8 układów. Daje nam to 8×16 wyjść używając tylko 2 pinów uC. Zaprojektowałem jednostronną płytkę pcb do tego układu. Wykonanie płytek zleciłem przez internet w chinach. Mimo że potrzebowałem jedynie dwie płytki, minimalna wielkość zamówienia wynosiła 10szt, więc dostałem 8 sztuk płytek pcb więcej. Wtedy mnie olśniło – hej! to mi się świetnie nada na zegar słowny. Poniższa grafika przedstawia projekt płytki expandera oraz schemat. Na schemacie zaznaczone są wszystkie składowe płytki PCB oraz sposób w jaki sposób diody led zostały połączone ze sobą oraz jak podłączone zostały do płytki.
Zacząłem projektować front. Na pierwszy ogień poszedł słownik poprawnej polszczyzny i upewnienie się jak poprawnie zapisywać wszystkie godziny w języku polskim. Gdy już sobie to ustaliłem, spisałem wszystkie słowa i ułożyłem je w tablicę, tak aby posiadała mniej-więcej taką samą liczbę znaków na każdy wiersz. Puste miejsca wypełniłem losowymi literami. Wyszło mi 15 wierszy po 24 znaki każdy. W programie CAD wyskalowałem tekst tak aby mieścił się w kwadracie 350mm x 350mm.
Przygotowany w ten sposób szkic liter zleciłem do wycięcia ploterem na czarnej folii samoprzylepnej z zamysłem przyklejenia jej do tafli antyramy. Cięcie miało być w negatywie, tak aby klej znajdował się od strony górnej. Niestety ta technika okazała się nietrafiona. Litery są na tyle wąskie że ploter nie docinał niektórych do końca, co spowodowało że nawet odklejenie od podkładu było problematyczne. Zleciłem więc wycięcie grafiki w ciemnoszarym brystolu.
Mając już gotowy front mogłem zająć się antyramą. Profil aluminiowy 20mm x 10mm przyciąłem na długość 370mm a końce ściąłem pod kątem 45st, dzięki temu powstała ramka o gabarytach zewnętrznych 370mm x 370mm i świetle 350mm x 350mm. Za pomocą krótkich wkrętów samowiercących z łbem stożkowym przywierciłem ramkę dokładnie do środka antyramy. Wyciąłem płytę w środku ramki. Do aluminiowej ramki doczepiłem zawiesię do obrazów.
Do powstałego otworu dopasowałem na wcisk kwadrat ze sztywnej tektury introligatorskiej 3mm. Szkic liter wraz z kratką (którego screen znajduje się powyżej) wydrukowałem i przykleiłem do tektury. Wiertłem 3mm wywierciłem otwory wszędzie tam gdzie znajdują się używane litery, oznaczyłem otwory z obu stron i zacząłem lutować diody. Wykorzystałem 3mm diody białe z płaskim czołem, niestety zamiast zamówionych mlecznych dostałem czyste. Trochę to mi pokrzyżowało plany.
Do każdej z grup diod dolutowałem rezystor tak, aby prąd na diodach nie przekroczył 10mA. Należy zwrócić też uwagę na moc rezystorów. W moim przypadku, żadna z grup diod nie przekroczyła 0,2W więc zamówiłem dobrane diody o mocy 0,25W. Dobranie rezystora do diód jest bardzo proste, znając napięcie zasilania, oczekiwany prąd oraz spadek napięcia na diodzie (przyjąłem 3,7V dla diody białej) skorzystałem z prawa Oma, znanego jako R=U/I
( Uzasilania[V] – Udiody[V] ) / ( Idiody[A] * Ndiod ) = R[Om]; gdzie Uzasilania to napięcie zasilania diód; Idiody to prąd pojedynczej diody w amperach (10mA =0,01A); Ndiod to liczba diód połączonych równolegle; R to wartość rezystancji.
Moc wydzielaną na rezystorze można wyliczyć ze wzoru P[W]=U[V] I[A]. Po podstawieniu do wzoru na moc przekształconego wzoru na prawo Oma otrzymać można następujące wyrażenie P[W]=U[V] ( U[V] / R[Om] ) = (( U[V] )^2) / R[Om]
Przykładowe wyliczenie rezystancji i mocy dla słowa ÓSMA. Słowo zawiera 4 litery czyli potrzebne są 4 diody.
R = (5V-3,7V) / 0,01A * 4 = 32.5 Oma
P = (5V-3,7V)^2 / 32,5 Oma = 0,052W
Najbliższa większa wartość rezystancji z szeregu wynosi 33Omy i taki rezystor lutuję w tym segmencie.
Oczywiście w internecie dostępne są kalkulatory rezystorów do diód, ale ja wykorzystałem arkusz excella gdzie wszystkie rezystancje policzyły mi się same ;)
Mając już przygotowaną płytę z diodami i rezystorami zacząłem lutować segmenty do płytek pcb. Co na początku nie wyglądało tragicznie, skończyło się okropnym pająkiem.
Płytki expanderów połączyłem ze sobą a następnie unieruchomiłem klejem na ciepło. Do tej samej magistrali podłączyłem moduł zegara opartego na DS3231. Całość polutowałem z nieśmiertelnym mini arduino, do którego też podłączyłem dwa przyciski ściągające do masy, służące do ustawiania godziny i minuty. Kod prezentuję poniżej. Wykorzystałem gotowe biblioteki dostępne w repozytorium arduino. Starałem się aby kod był przejrzysty ale nie walczyłem o jego bezwzględną optymalizację.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
#include "Arduino.h" #include "Wire.h" #include "uRTCLib.h" #include "Adafruit_MCP23017.h" /* Zegar slowny, PK. ver.16052018 UKLAD ZEGARA pierwszaxdrugadziesiątah | pierwsza druga dziesiąta \ vczwartadwunastabqszósta | czwarta dwunasta szósta |>expander0 = 12wyjsc siódmaeósmakmydziewiątaw | siódma ósma dziewiąta | trzeciajedenastapiątalbr | trzecia jedenasta piąta / dziewiętnaściełdwanaście | dziewiętnaście dwanaście \ jedenaściedsiedemnaścieq | jedenaście siedemnaście | czternaściepiętnaścietcv | czternaście piętnaście | szesnaściegnczterdzieści | szesnaście czterdzieści |>expander1 = 14wyjsc osiemnaścieatrzydzieścir | osiemnaście trzydzieści | btrzynaściedwadzieściaźu | trzynaście dwadzieścia | wqedziesięćpięćdziesiątf | dziesięć pięćdziesiąt / kjednadcminutanfsiedemnb | jedna minuta siedem \ pięćbosiemqczteryesześćr | pięć osiem cztery sześć |>expander2 = 15 wyjsc fdwiedziewięćbytrzyjeden | dwie dziewięć trzy jeden | minutyrponpółnocyipkopeć | minut y po północy / */ /* addr 0 = A2 low , A1 low , A0 low 000 addr 1 = A2 low , A1 low , A0 high 001 addr 2 = A2 low , A1 high , A0 low 010 addr 3 = A2 low , A1 high , A0 high 011 addr 4 = A2 high , A1 low , A0 low 100 addr 5 = A2 high , A1 low , A0 high 101 addr 6 = A2 high , A1 high , A0 low 110 addr 7 = A2 high, A1 high, A0 high 111 Basic pin reading and pullup test for the MCP23017 I/O expander // Connect pin #12 of the expander to Analog 5 (i2c clock) // Connect pin #13 of the expander to Analog 4 (i2c data) // Connect pins #15, 16 and 17 of the expander to ground (address selection) // Connect pin #9 of the expander to 5V (power) // Connect pin #10 of the expander to ground (common ground) // Connect pin #18 through a ~10kohm resistor to 5V (reset pin, active low) // Output #0 is on pin 21 so connect an LED or whatever from that to ground */ Adafruit_MCP23017 expander0; //obsluguje GODZINY Adafruit_MCP23017 expander1; //obsluguje DZIESIATKI MINUT Adafruit_MCP23017 expander2; //obsluguje MINUTY // uRTCLib rtc; uRTCLib rtc(0x68, 0x57); volatile byte godzina; volatile byte minuta; volatile byte sekunda; bool state=LOW; //zmienna pomocnicza do debugowania expandera /*int m; //minuta int dm; //dziesiatka minut int h; //godzina int s; //sekunda*/ int prevm; int prevdm; int prevh; short buttonh=5; short buttonm=4; void setup() { Serial.begin(9600); Serial.println("Serial OK"); Wire.begin(); //skladnia: uRTCLib::set(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) //rtc.set(0, minuta, godzina, 1, 1, 1, 18); expander0.begin(0); // expander0.pinMode(0, OUTPUT); expander0.pinMode(1, OUTPUT); //pierwsza 0A1 expander0.pinMode(2, OUTPUT); //druga 0A2 expander0.pinMode(3, OUTPUT); //trzecia 0A3 expander0.pinMode(4, OUTPUT); //czwarta 0A4 expander0.pinMode(5, OUTPUT); //piata 0A5 expander0.pinMode(6, OUTPUT); //szosta 0A6 expander0.pinMode(7, OUTPUT); //siodma 0A7 expander0.pinMode(8, OUTPUT); //osma 0B0 expander0.pinMode(9, OUTPUT); //dziewiata 0B1 expander0.pinMode(10, OUTPUT); //dziesiata 0B2 expander0.pinMode(11, OUTPUT); //jedenasta 0B3 expander0.pinMode(12, OUTPUT); //dwunasta 0B4 expander0.pinMode(13, OUTPUT); expander0.pinMode(14, OUTPUT); expander0.pinMode(15, OUTPUT); expander1.begin(1); // expander1.pinMode(0, OUTPUT); expander1.pinMode(1, OUTPUT); //dziesiec 1A1 expander1.pinMode(2, OUTPUT); //dwadziescia 1A2 expander1.pinMode(3, OUTPUT); //trzydziesci 1A3 expander1.pinMode(4, OUTPUT); //czterdziesci 1A4 expander1.pinMode(5, OUTPUT); //piecdziesiat 1A5 expander1.pinMode(6, OUTPUT); //jedenascie 1A6 expander1.pinMode(7, OUTPUT); //dwanascie 1A7 expander1.pinMode(8, OUTPUT); //trzynascie 1B0 expander1.pinMode(9, OUTPUT); //czternascie 1B1 expander1.pinMode(10, OUTPUT); //pietnascie 1B2 expander1.pinMode(11, OUTPUT); //szesnascie 1B3 expander1.pinMode(12, OUTPUT); //siedemnascie 1B4 expander1.pinMode(13, OUTPUT); //osiemnascie 1B5 expander1.pinMode(14, OUTPUT); //dziewietnascie 1B6 expander1.pinMode(15, OUTPUT); expander2.begin(2); // expander2.pinMode(0, OUTPUT); expander2.pinMode(1, OUTPUT); //jeden 2A1 expander2.pinMode(2, OUTPUT); //dwie 2A2 expander2.pinMode(3, OUTPUT); //trzy 2A3 expander2.pinMode(4, OUTPUT); //cztery 2A4 expander2.pinMode(5, OUTPUT); //piec 2A5 expander2.pinMode(6, OUTPUT); //szesc 2A6 expander2.pinMode(7, OUTPUT); //siedem 2A7 expander2.pinMode(8, OUTPUT); //osiem 2B0 expander2.pinMode(9, OUTPUT); //dziewiec 2B1 expander2.pinMode(10, OUTPUT); //jedna 2B2 expander2.pinMode(11, OUTPUT); //minuta 2B3 expander2.pinMode(12, OUTPUT); //minut 2B4 expander2.pinMode(13, OUTPUT); //y 2B5 expander2.pinMode(14, OUTPUT); //po 2B6 expander2.pinMode(15, OUTPUT); //polnocy 2B7 pinMode(buttonh, INPUT_PULLUP); pinMode(buttonm, INPUT_PULLUP); } void loop() { rtc.refresh(); godzina=rtc.hour(); minuta=rtc.minute(); sekunda=rtc.second();; if(digitalRead(buttonh)==LOW){ godzina=rtc.hour()+1; if (godzina>=24){godzina=0;} rtc.set(sekunda, minuta, godzina, 1, 1, 1, 18); pokazgodzine(godzina, minuta); } if(digitalRead(buttonm)==LOW){ minuta=rtc.minute(); minuta=minuta+1; if (minuta>=60){minuta=0;} rtc.set(sekunda, minuta, godzina, 1, 1, 1, 18); pokazgodzine(godzina, minuta); } if(minuta!=prevm){pokazgodzine(godzina, minuta);} prevh=godzina; prevm=minuta; Serial.print(rtc.hour()); Serial.print(':'); Serial.print(rtc.minute()); Serial.print(':'); Serial.print(rtc.second()); Serial.println(); delay(250); } void clr(short num){ //funkcja do wylaczania wszystkich wyjsc expanderow if (num==0){ for(int i=0;i<=15;i++){expander0.digitalWrite(i, LOW);} } if (num==1){ for(int i=0;i<=15;i++){expander1.digitalWrite(i, LOW);} } if (num==2){ for(int i=0;i<=15;i++){expander2.digitalWrite(i, LOW);} } return 0; } void pokazgodzine(short h, short m){ //wyswietlanie godziny innej niz polnoc if(h>0){ if (h>12){h=h-12;} clr(0); expander0.digitalWrite(h,HIGH); //godzina if (m==0){ //zero minut clr(1); clr(2); } if (m>0 && m<=9){ //wiecej niz 0 minut, mniej niz 10 minut clr(1); clr(2); expander2.digitalWrite(m, HIGH); } if (m%10==0 && m!=0){ //pelne dziesiatki minut clr(1); clr(2); expander1.digitalWrite(m/10, HIGH); } if (m>10 && m<=19){ //wiecej niz 10 minut, mniej niz 20 minut clr(1); clr(2); expander1.digitalWrite((m-5), HIGH); } if (m%10==0 && m!=10){ clr(1); clr(2); expander1.digitalWrite(((m-m%10)/10), HIGH); } if (m>20 && m!=30 && m!=40 && m!=50){ clr(1); clr(2); expander1.digitalWrite((m-m%10)/10, HIGH); expander2.digitalWrite((m%10),HIGH); } } //koniec wyswietlania godziny innej niz polnoc //wywietlanie godziny zero if(h==0){ clr(0); clr(1); clr(2); if (m==0){ //polnoc expander0.digitalWrite(12,HIGH); } if (m==1){ expander2.digitalWrite(10,HIGH); //jedna expander2.digitalWrite(11, HIGH); //minuta } if (m>1 && m<=4){ expander2.digitalWrite(m, HIGH);//dwie/trzy/cztery expander2.digitalWrite(12, HIGH);//minut expander2.digitalWrite(13, HIGH); //y } if (m>4 && m<=9){ expander2.digitalWrite(m, HIGH);//piec/szesc/siedem/osiem/dziewiec expander2.digitalWrite(12, HIGH); //minut }//minut if (m%10==0 && m!=0){ expander1.digitalWrite(m/10,HIGH);//dziesiec/dwadziescia/trzydziesci/czterdziesci/piecdziesiat expander2.digitalWrite(12, HIGH); //minut } if (m>10 && m<=19){ expander1.digitalWrite(m-5,HIGH); //wiecej niz 10 minut, mniej niz 20 minut expander2.digitalWrite(12, HIGH); //minut } if (m>20 && m!=30 && m!=40 && m!=50){ expander1.digitalWrite((m-m%10)/10,HIGH);//pelne dziesiatki minut expander2.digitalWrite((m%10),HIGH);//jednosci minut expander2.digitalWrite(12, HIGH); //minut if((m>=22 && m<=24) || ( m>=32 && m<=34) || (m>=42&&m<=44) || (m>=52&&m<=54)){ expander2.digitalWrite(13,HIGH); } } if (m>0){ expander2.digitalWrite(14, HIGH);//po expander2.digitalWrite(15, HIGH);//polnocy } } //koniec wyswietlania godziny zero } |
Po wgraniu na uC zegar ożył, ale konieczne okazało się zrobienie rozproszenia światła pod literami. Po paru próbach optymalnym rozwiązaniem okazało się naklejenie pasków tektury rozdzielających poszczególne słowa aby światło nie przenikało do sąsiadów. W powstałe w ten sposób kieszenie wkleiłem białą piankę opakowaniową. Na arkusz z literami przykleiłem arkusz białego papieru.
Pozostało złożyć zegar.
Ostatnio mam bardzo ograniczony dostęp do swojego warsztatu więc nie wszystko w środku jest zrobione tak ładnie, jakbym chciał. Niestety musiałem się ratować często dość partyzanckimi metodami, ale z zewnątrz efekt jest przyjemny dla oka. Zostało wymienić jedynie fatalnej jakości frontową taflę przezroczystego polistyrenu na szkło i dokupić docelowy zasilacz 5V 0,5A, ponieważ teraz zegar pracuje na zasilaczu laboratoryjnym.
Zachęcam do takiej zabawy, bo efekt jest tego wart.
Ooo, cube – dawno Cię nie widziałem! :) Fajnie, że wróciłeś!
Tak się życie układa że robi się mniej tego, na co masz ochotę a więcej tego co musisz. Brakuje mi jakichś 24godzin w dobie i bym na wszystko znalazł czas.
Miło że zrobiłeś wersję mickiewiczowską! Ja bym pewnie wybrał Esp8266. Nie trzeba modułu zegara, i co za tym idzie żadnych przycisków i zmiany czasu letniego. Ale i tak piąteczka.
super, ciekawa jestem jaki koszt całości? A może zrobił byś na zamówienie?
Super sprawa. Napisałeś iż, płytki zamówiłeś w chinach. Mogę prosić o podpowiedz gdzie, jaki koszt i ile się czeka ?
jlcpcb.com – niecałe 2$ za te płytki i 9,5$ za przesyłkę do polski. Czekałem ze 2-3 tygodnie.
:) 2$ za 10 płytek to niezła cena, sam laminat kosztuje więcej. Otwory są metalizowane ?
Akurat te płytki nie mają metalizowanego otworu bo są jednostronne/jednowarstwowe. Ale oczywiście metalizację robią jak potrzeba.
Świetny projekt. Chciałbym zrobić taki zegar dla siebie. Czy moglbys powiedziec mi w jakim programie zrobiles tarczę? Ja próbuję w solidworksie 12 ale totalnie mi nie wychodzi.
Cześć. Chciałem zrobić sobie taki zegar. Czy mógłbyś wysłać mi plik w cad’zie i projekt płytki na maila maxskubi@onet.pl ?
Witam. Świetny projekt. Czy mógłbym się dowiedzieć co to za czcionka?
Witam. Jestem zainteresowany zrobieniem takiego zegara. Mogę prosić o projekt płytki na adres andrzej.drozd1@o2.pl?? Z góry pięknie dziękuje
Cześć,
dużo dobrej pracy. Efekt fajny, byłaby możliwość pozyskania od Ciebie projektu “planszy” w krzywych? Dziękuję z góry.