Predstavljamo vam analogno uro, ki prikazuje čas na barvnem grafičnem TFT zaslonu.
Avtor teksta in fotografij: David Johnson-Davies
Predstavljena ura temelji na RGB TFT zaslonu, ki ga upravlja mikrokontroler ATtiny814. Za natančno merjenje časa uporablja oscilator s kvarčnim kristalom in izkorišča postopke za branje s TFT zaslona, opisane v mojem članku Branje s TFT zaslona [1].
Navedel sem vezje, tako da lahko projekt sestavite na prototipni plošči. Uporabite lahko tudi mojo univerzalno ploščico – “nahrbtnik” z univerzalnim TFT zaslonom [2].
Uvod
To se je začelo kot predstavitveni program za mojo grafično TFT knjižnico s podporo za branje z zaslona, vendar je postalo vse bolj zapleteno, zato sem se odločil, da ga napišem kot samostojen projekt.
Kako deluje
Brez možnosti ponovnega branja z zaslona bi morali celoten zaslon ponovno narisati vsakič, ko se kazalci premaknejo, kar je enkrat na sekundo, če ima ura sekundni kazalec. To bi zahtevalo hiter procesor (in večjo porabo energije).
Ta vsebina je samo za naročnike
Ta ura se temu izogne z uporabo možnosti branja s TFT zaslona za ekskluzivno določanje barve vsakega kazalca na sliki ure. Ko se kazalec premakne, ga lahko odstranite iz zadnjega položaja tako, da ga ponovno narišete, s čimer se ozadje povrne v prejšnje stanje. To zagotavlja, da se elementi pod kazalci, kot so številke ur, ne izbrišejo, ko se kazalci premaknejo čez njih.
Primerni prikazovalniki
Ura je zasnovana za delovanje s TFT RGB 240×240 ali 320×240 zaslonom, ki je na voljo v trgovini AliExpress. Izdelal sem tudi različico nižje ločljivosti, ki bo delovala na zaslonu 128×128 ali 160×128; glejte različico nižje ločljivosti [3]. Primerni so naslednji zasloni, glej tabelo 1.
Žal Adafruit zasloni niso združljivi s to aplikacijo, saj ne podpirajo branja z zaslona; več informacij o tem je v članku Branje z zaslona TFT [4].
Vezje
Tukaj je vezje, ki je v bistvu vezje TIV nahrbtnika je na sliki 2.
Program zaseda 5KB, zato potrebujete mikrokontroler ATtiny serije 1 z vsaj 8KB, na primer ATtiny814 do ATtiny2314. Mikrokontrolerji serije 0 niso primerni, saj ne podpirajo zunanjega kristala. Uporabiti bi morali tudi enega od novejših mikrokontrolerjev serije 2, vendar tega še nisem preizkusil.
Ura uporablja ATtiny814 Real-Time Clock za generiranje prekinitve vsako sekundo, časovno pa jo nadzoruje 32,768 kHz kristal. Za kristal sem uporabil poceni cilindrični kristal [5], ki ima običajno kapacitivnost obremenitve 12,5 pF. Za izračun vrednosti kondenzatorjev uporabite formulo C = 2(CL – CS), kjer je CL obremenitvena kapacitivnost, CS pa neželena kapacitivnost, ki je običajno ocenjena na 2,5 pF na tiskanem vezju. Tako dobimo C = 20pF.
Če ste vezje izdelali na ploščici, lahko kondenzatorje verjetno izpustite, saj bo med vrsticami na ploščici verjetno dovolj kapacitivnosti.
Univerzalni “nahrbtnik” s TFT zaslonom
Program lahko zaženete tudi na mojem nahrbtniku z univerzalnim zaslonom TFT [6] s procesorjem ATtiny814 slika 3.
Program ure
Program vključuje mojo knjižnico iz članka Branje s TFT zaslona [7].
Rutina ClockFace() nariše številčnico ure in številke ur, vendar brez kazalcev:
void ClockFace () {
int x0 = 120, y0 = 120, radius = 120;
MoveTo(x0, y0); fore = BLUE; DrawCircle(radius);
radius = radius – 2; fore = DARKBLUE; Fill-
Circle(radius);
int x = 0, y = 118<<sca;
for (int i=0; i<60; i++) {
// Hours and hour marks
if (i%5 == 0) {
fore = YELLOW;
MoveTo(x0+(x>>sca), y0+(y>>sca));
DrawTo(x0 + ((x*15)>>(sca+4)), y0 + ((y*15)>>(sca+4)));
scale = 2;
MoveTo(x0 + ((x>>sca)*13/16) – 3*(1+(i==0))*2, y0 + ((y>>sca)*13/16) – 8);
fore = GREEN; back = DARKBLUE;
if (i==0) PlotInt(12); else PlotInt(i/5);
scale = 1;
}
for (int i=2;i–;) { x = x + (y*top)/bot; y = y – (x*top)/bot; }
}
}
Za izračun 60 točk okoli kroga uporablja algoritem kroga avtorja Minsky, pri čemer ne potrebuje funkcij s plavajočo vejico ali trigonometričnih funkcij. Vrednost top/bot ali 10/191 je približek vrednosti (2*π)/120, kjer je 2*π število radianov v krogu. 120 je število delitev kroga, ki ga uporabljam, pri čemer dve delitvi ustrezata eni sekundi. Vrednost sca je faktor merila, izbran tako, da se 2sca*118*top prilega v int spremenljivko.
Nastavitev ure realnega časa
Za merjenje časa se uporablja periferni RTC vmesnik v ATtiny814, ki svoj takt dobi z zunanjim kristalom s frekvenco 32,768 kHz in vsako sekundo pošlje prekinitev.
Rutina RTCSetup() konfigurira kristalni oscilator in ga nato določi kot vir ure za Real-Time Clock periferno napravo:
void RTCSetup () {
uint8_t temp;
// Initialize 32.768kHz Oscillator:
// Disable oscillator:
temp = CLKCTRL.XOSC32KCTRLA & ~CLKCTRL_ENA-
BLE_bm;
// Enable writing to protected register
CPU_CCP = CCP_IOREG_gc;
CLKCTRL.XOSC32KCTRLA = temp;
while (CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm); // Wait until XOSC32KS is 0
temp = CLKCTRL.XOSC32KCTRLA & ~CLKCTRL_SEL_bm; // Use External Crystal
// Enable writing to protected register
CPU_CCP = CCP_IOREG_gc;
CLKCTRL.XOSC32KCTRLA = temp;
temp = CLKCTRL.XOSC32KCTRLA | CLKCTRL_ENABLE_bm; // Enable oscillator
// Enable writing to protected register
CPU_CCP = CCP_IOREG_gc;
CLKCTRL.XOSC32KCTRLA = temp;
// Initialize RTC
while (RTC.STATUS > 0); // Wait until synchronized
// 32.768kHz External Crystal Oscillator (XOSC32K)
RTC.CLKSEL = RTC_CLKSEL_TOSC32K_gc;
// RTC Clock Cycles 32768, enabled ie 1Hz interrupt
RTC.PITCTRLA = RTC_PERIOD_CYC32768_gc;
RTC.PITINTCTRL = RTC_PI_bm; // Periodic Interrupt: enabled
}
// Interrupt Service Routine called every second
ISR(RTC_PIT_vect) {
RTC.PITINTFLAGS = RTC_PI_bm; // Clear interrupt flag
NextSecond(BOTH);
}
V bistvu gre za enako rutino, kot sem jo uporabil pri prejšnjih urah, ki temeljijo na ATtiny čipih serije 1, kot je Mega Tiny Time Watch [Posodobljeno] [8].
Premikanje kazalcev
Rutina za prekinitev se kliče vsako sekundo:
ISR(RTC_PIT_vect) {
RTC.PITINTFLAGS = RTC_PI_bm;
// Clear interrupt flag
NextSecond(BOTH);
}
Preprosto pokliče funkcijo NextSecond(), da se kazalci premaknejo naprej, če je to potrebno:
void NextSecond (int draw) {
int x0 = 120, y0 = 120;0
// Positions of hands
static int secx = 0, secy = 118<<sca;
static int minx = 0, miny = 118<<sca;
static int hrx = 0, hry = 86<<sca;
// Seconds and minutes
static uint8_t secs = 0, mins = 0;
// Advance second hand
fore = White;
if (draw & UNDRAW) { MoveTo(x0, y0); DrawTo(x0+(secx>>sca), y0+(secy>>sca)); }
for (int i=2;i–;) { secx = secx + (secy*top)/bot; secy = secy – (secx*top)/bot; }
if (secs == 59) { secx = 0, secy = 118<<sca; } // Realign
if (draw & DRAW) { MoveTo(x0, y0); DrawTo(x0+(secx>>sca), y0+(secy>>sca)); }
// Advance hour hand every 12 mins
if (secs == 59 && mins%12 == 0) {
fore = RED;
DrawHand(x0, y0, hrx>>sca, hry>>sca);
for (int i=2;i–;) { hrx = hrx + (hry*top)/bot; hry = hry – (hrx*top)/bot; }
} else if (secs == 0 && mins%12 == 0) {
fore = RED;
DrawHand(x0, y0, hrx>>sca, hry>>sca);
}
// Advance minute hand every 60 secs
if (secs == 59) {
fore = PINK;
if (draw & UNDRAW) DrawHand(x0, y0, minx>>sca, miny>>sca);
for (int i=2;i–;) {minx = minx + (miny*top)/bot; miny = miny – (minx*top)/bot; }
} else if (secs == 0) {
fore = PINK;
if (mins == 0) minx = 0, miny = 118<<sca; // Realign
if (draw & DRAW) DrawHand(x0, y0, minx>>sca, miny>>sca);
mins = (mins + 1)%60;
}
secs = (secs + 1)%60;
}
V vsakem primeru je kazalec narisan dvakrat, pri čemer se uporabi izločanje z izključujočimi se koraki: enkrat v prejšnjem položaju, da se odstrani stara slika, in enkrat v novem položaju, da se nariše nova slika.
Drugi kazalec je narisan kot črta in napreduje vsako sekundo.
Minutni kazalec se premakne za eno sekundo vsakih 60 sekund. Zaradi časa, ki je potreben za izris, staro različico odstranim in novo različico izrišem z zaporednimi klici funkcije NextSecond(). Urni kazalec se premakne za eno sekundo vsakih 12 minut.
Risanje urnega in minutnega kazalca
Tako urni kot minutni kazalec se s funkcijo DrawHand() narišeta kot zapolnjeni štirikotniki v obliki romba z uporabo postopkov iz risanja zapolnjenih štirikotnikov in trikotnikov [9]:
void DrawHand(int x0, int y0, int x, int y) {
int v = x/2, u = y/2, w = v/5, t = u/5;
FillQuad(x0, y0, x0+v-t, x0+u+w, x0+x, x0+y, x0+v+t, x0+u-w);
}
Ker moram izrisati le zapolnjen štirikotnik, sem postopek nekoliko poenostavil, da bo nekoliko hitrejši.
Nastavitev časa
Za nastavitev začetnega časa ure lahko pokličete SetTime() z ustreznima vrednostima ure in minute:
void SetTime (int hour, int minute) {
uint32_t secs = (uint32_t)(hour * 60 + minute) * 60;
for (uint32_t i=0; i<secs; i++) NextSecond(NONE);
}
S parametrom draw v funkciji NextSecond() lahko določite, ali naj se kazalca ob vsakem klicu narišeta ali ne, funkcija SetTime() pa pokliče funkcijo NextSecond(NONE), da premakne položaje kazalcev, ne da bi jih dejansko izrisala, kar je veliko hitreje. Ko je nastavljen pravilen čas, se pokliče EnableClock(), da se omogoči enosekundna prekinitev:
void EnableClock () {
RTC.PITCTRLA = RTC.PITCTRLA | RTC_PITEN_bm;
}
Trenutno morate čas začetka določiti, preden naložite program:
const int Hour = 12, Minute = 34;
// E.g. 12:34a
Verzija z nižjo resolucijo
Zagotovil sem tudi različico ure z nižjo resolucijo s parametri, prilagojenimi za barvni TFT 128×128 zaslon slika 4.
Prevajanje programa
Prevedite program z megaTiny Core [10] Spencea Kondeja na GitHubu. Izberite možnost ATtiny3224/ 1624/ 1614/ 1604/ 824/ 814/ 804/ 424/ 414/ 404/ 241/ 204 pod naslovom megaTinyCore v meniju Board. Preverite, ali so naslednje možnosti nastavljene, kot sledi (ne upoštevajte drugih možnosti):
Čip: “ATtiny814” (ali kakor je ustrezno)
Ura: “20 MHz internal”.
Nato program naložite z UPDI programatorjem. Priporočljiva možnost je uporaba 3,3-voltne plošče USB na serijski vmesnik, kot je plošča SparkFun FTDI Basic [11], ki je povezana z uporom 4,7 kΩ na naslednji način slika 5
Viri
Tukaj je celoten program: [12].
Tukaj je različica za zaslon 128×128 (ali 160×128): Grafična analogna ura 128×128 [13].
Viri:
http://www.technoblogy.com/show?3UEJ
http://www.technoblogy.com/show?3JCM
http://www.technoblogy.com/show?3ZWB#lower-resolution-version
http://www.technoblogy.com/show?3UEJ
https://www.adafruit.com/product/2211
http://www.technoblogy.com/show?3JCM
http://www.technoblogy.com/show?3UEJ
http://www.technoblogy.com/show?2OKF
http://www.technoblogy.com/show?3ZYQ
https://github.com/SpenceKonde/megaTinyCore
http://www.technoblogy.com/show?3ZWB#cite_note2
http://www.technoblogy.com/list?265D
http://www.technoblogy.com/list?44KF
Povzeto po:
http://www.technoblogy.com/show?3ZWB