Čítač s GPS normálem – 4. Displej
Koncepce
Rozlišení měřícího přístroje, to znamená počet číslic na displeji, by měl odpovídat normálu, s kterým je měřená hodnota porovnávána. To znamená, že když mám v čítači jednoduchý krystalový oscilátor, bez teplotní kompenzace, nemá smysl mít na displeji víc než pět míst.
Kmitočtovým normálem popisovaného čítače je GPSDO. Vzhledem k jeho stabilitě budeme schopni měřit kmitočet 1GHz s rozlišením 0,01Hz. 1GHz, to je jednička, devět nul a k tomu dvě desetinná místa. Celkem je potřeba minimálně dvanácti-místný displej. Se znaky Hz to je čtrnáct míst. Výšku číslic chceme větší než 10mm a velikost předního panelu přístroje by měla být asi 220 x 80mm. K tomu je potřeba mít na panelu pár tlačítek pro ovládání čítače. Alfanumerický, ani TFT displej potřebných rozměrů s dostatečnou velikostí znaků jsme nenašli. Zajímavé by bylo použití digitronů, ale to bychom se připravili o možnost zobrazovat alfanumerické znaky. Takže použijeme 14-ti segmentový LED displej sestavený ze sedmi dvoumístných zobrazovačů 5241AS.
Výška znaku na zobrazovači je 0,54inch, to je 14mm. Rozteč řad nožiček zobrazovače je 15mm, takže se pod zobrazovače vejdou integrované obvody v 16-ti pinovém SSOP pouzdru, kterými bude displej ovládán. Deska plošných spojů potom může být úzká a dlouhá, tak jak bylo plánováno. Zobrazovače displeje budou napájeny sadou posuvných registrů a mikroprocesor je bude ovládat po sériové lince.
Součástky budou rozmístěny z obou stran dvouvrstvého plošného spoje, to pro ruční osazování není problém. Tlačítka a LEDky jsme uspořádali tak, aby se na panel vešly nápisy a do výřezu v desce BNC konentor.
Zapojení displeje
Čtrnáct znaků po čtrnácti segmentech, k tomu desetinné tečky a malý šestimístný displej postavený ze sedmisegmentů, to je 258 LEDek. K tomu pár dvoubarevných LEDek jako indikace provozních stavů čítače. Není potřeba aby svítily všechny najednou, použijeme multiplex. V jednom okamžiku bude svítit 1/4 diod, skupiny se budou střídat po 4ms. To je pořád ještě 70 diod, které je potřeba připojit k nějakému budiči. Ten bude ovládán po sériové lince. Existují specializované obvody, v podstatě velké posuvné registry, určené pro ovládání displejů. My použijeme běžně dostupný 74HC595, který se v SSOP pouzdru vejde pod displej. Posuvných registrů bude deset a budou ovládat anody zobrazovačů.
Katody budou ovládány tranzistorovým polem ULN2803. Budou potřeba tři, aby bylo možné proud rozdělit mezi jednotlivá pouzdra.
Úkolem mikroprocesoru bude, každou čtvrtou milisekundu připojit katody další ze čtyř skupin LEDek s pomocí dekodéru 74HC238. K zobrazení celého čísla je potřeba 16ms, to je 62,5Hz. Dost vysoký kmitočet na to, aby lidské oko nepoznalo blikání a nízký na to, aby měl procesor čas na ostatní práci.
Pro anody displeje procesor před přepnutím katod nahraje do posuvných registrů další skupinu čísel a signálem RCK překlopí klopné obvody typu D, které jsou na výstupu obvodů 74HC595.
Zapojení klávesnice
Pro ovládání čítače bude potřeba asi deset tlačítek. Tolik volných vývodů na procesoru nemáme a ani se mi nechce používat moc široký kabel k propojení desky displeje s hlavní deskou čítače. Tlačítka by bylo možné multiplexovat, ale to je pořád ještě 7 drátů. Procesor má integrovaný AD převodník, co kdybychom jej použili? I spotřeba místa na desce plošných spojů bude menší, když nebudu muset z tlačítek vytvářet síť. Když každé tlačítko připojí svůj rezistor do odporového děliče, kterým se vytvoří příslušné napětí, bude to fungovat. Nevýhoda tohoto řešení je, že stisk většího množství tlačítek s velkými hodnotami rezistorů odpovídá stisku jiného tlačítka s malou hodnotou rezistoru. Ale to v našem případě nevadí.
Odporový dělič je napájen svým stabilizátorem, aby klávesnice nebyla rušena provozem displeje.
Pořadí anod, připojených k posuvným registrům je upraveno tak, aby bylo optimalizováno využití místa na plošném spoji. I jednotlivé LEDky jsou do sítě zapojeny s ohledem na jejich umístění na desce. V programu to pak nějak vyřeším.
Programování displeje
Pro práci s displejem je potřeba mít v paměti uloženu znakovou sadu pro 14-ti segmentové zobrazovače. K tomu se bude hodit pole dat. Překladač jazyka C po zahájení běhu programu pole dat uloží do paměti RAM a čísla bude číst z ní. To je škoda, paměť RAM je malá a navíc by znaková sada mohla být během práce programu poškozena. V knihovně pgmspace.h jsou funkce, kterými je možné přesvědčit překladač, aby pole dat nechal v paměti ROM. Takže začátek znakové sady může vypadat např. takto:
const uint8_t AsciiChar[] PROGMEM = { 0b00000000, 0b00000000, // 32 - prazdny znak 0b10100000, 0b00000000, // 33 - ! znak " leve 0b10000000, 0b00000001, // 34 - znak " prave 0b11000100, 0b00000010, // 35 - # znak Anteny 0b10100101, 0b01101100, // 36 - znak $ 0b10011000, 0b01000100, // 37 - % znak Alfa 0b01111000, 0b00000100, // 38 - & znak Beta
Text, který bude zobrazován, si připravíme do pole dat v paměti RAM. Pro řetězec znaků bude potřeba funkce:
void Show_WriteString( const char* string, uint8_t x ) { while( *string != '\0' ) { DisplayArray[ (( 19 - x ) * 2 ) + 0 ] = pgm_read_byte(&( AsciiChar[ (( *string - 32 ) * 2 ) + 0 ])); // ulozi data do pole, zobrazi se to v preruseni casovace DisplayArray[ (( 19 - x ) * 2 ) + 1 ] = pgm_read_byte(&( AsciiChar[ (( *string - 32 ) * 2 ) + 1 ])); string++; x++; } }
Další funkce budou potřeba pro zobrazení čísel. Nevím, kdy tyto funce budou spuštěny, ani jak dlouho budou trvat. Prostě když program čítače chce zobrazit nové číslo, nebo text, tak funkci zavolá.
Vlastní ovládání obvodů displeje je náročné na čas, nová data do posuvných registrů musí být posílána pravidelně, aby displej neblikal. K tomu je na časovači procesoru nastavena perioda 4ms a časovač zavolá svoji obsluhu přerušení, ve které se z pole dat odešle jedna čtvrtina. Problém je, že znaky v poli dat jsou uspořádány postupně a do registrů je potřeba to posílat na přeskáčku.
for( DisplayCounter1 = 0; DisplayCounter1 < 5; DisplayCounter1++ ) // smycka posilani dat na posuvne registry { DisplayData = DisplayArray[ ((( DisplayCounter1 << 2 ) + DisplayCounter0 ) << 1 ) + 1 ]; for( CountInt = 0; CountInt < 8; CountInt++ ) { DisplayClk_clr; if ( (DisplayData&0x80) == 0x80 ) DisplayData_set else DisplayData_clr; DisplayData <<= 1; DisplayClk_set; } DisplayData = DisplayArray[ ((( DisplayCounter1 << 2 ) + DisplayCounter0 ) << 1 ) ]; for( CountInt = 0; CountInt < 8; CountInt++ ) { DisplayClk_clr; if ( (DisplayData&0x80) == 0x80 ) DisplayData_set else DisplayData_clr; DisplayData = DisplayData << 1; DisplayClk_set; } }
V programu je použito dost hloupé posílání dat na posuvné registry ve smyčkách s proměnnou CountInt. Přitom procesor má sériovou linku SPI a displej je připojen tak, aby bylo možné ji využít. Jenomže když jsem SPI v programu využil, tak diody v nepravidelných intervalech bliknou. Nevím proč.
Programování klávesnice
AD převodník klávesnice je spouštěn časovačem v intervalu 4ms stejně jako displej. AD převodník po ukončení převodu volá svoje přerušení, ve kterém se vyhodnotí, jestli bylo něco stisknuto
ISR( ADCA_CH0_vect ) { KeyNum = ADCA_CH0_RES; if( KeyNum < 400 ) KeyNum = 17; else if(( KeyNum > 400 ) && ( KeyNum < 460 )) KeyNum = 1; else // 6k8, odpory pro jednotlivá tlačítka R81 = 180k if(( KeyNum > 580 ) && ( KeyNum < 630 )) KeyNum = 2; else // 12k if(( KeyNum > 680 ) && ( KeyNum < 730 )) KeyNum = 3; else // 15k if(( KeyNum > 850 ) && ( KeyNum < 960 )) KeyNum = 4; else // 22k if(( KeyNum > 1190 ) && ( KeyNum < 1280 )) KeyNum = 5; else // 33k if(( KeyNum > 1530 ) && ( KeyNum < 1590 )) KeyNum = 6; else // 47k if(( KeyNum > 1730 ) && ( KeyNum < 1790 )) KeyNum = 7; else // 56k if(( KeyNum > 1980 ) && ( KeyNum < 2050 )) KeyNum = 8; else // 68k if(( KeyNum > 2200 ) && ( KeyNum < 2290 )) KeyNum = 9; else // 82k if(( KeyNum > 2500 ) && ( KeyNum < 2610 )) KeyNum = 10; else // 100k if(( KeyNum > 2780 ) && ( KeyNum < 2880 )) KeyNum = 11; // 120k else KeyNum = 0; if(( Status&0x10 ) && ( KeyNum > 1 )) KeyNum = 0; // kdyz je Standby, tak se reaguje jenom na klavesu Standby if(( KeyNum == KeyBuffer ) && ( KeyResult == 0 ) && ( KeyNum > 0 )) KeyCounter++; else { KeyCounter = 0; KeyBuffer = KeyNum; } if( KeyCounter == 5 ) { KeyCounter = 0; KeyResult = KeyNum; KeyTimer = 60; // cela na dalsi stisk } }
K naměřenému napětí je v proměnné KeyNum přiřazeno tlačítko. V proměnné KeyCounter jsou počítána jednotlivá měření, pět krát je měřeno a porováváno s předchozím tlačítkem, jehož hodnota je v KeyBuffer. Až po pátém měření je jistota, že stisk je stabilní a hodnota tlačítka je uložena do KeyResult. S touto hodnotou pracuje hlavní program čítače.