Tartalom:
- Pozitív és negatív számadatok megjelenítése 7 szegmenses kijelző soron
- Beállítható tizedes jegy szám, bekapcsolható zéró elnyomás az értékes jegyek előtt
- Negatív előjel kijelzése az első értékes jegy előtt
- Pozitív és negatív túlcsordulás jelzése (a szám nem fér ki)
- Teljes forráskód, példa program a használathoz
—————————————————————————————————
Egy régebbi barkácsolásból visszamaradt 5db 74HC595 shiftregiszterrel meghajtott 7 szegmenses LED kijelző. Óriás méretűek, legalább 2-3cm magas a karakterkép, de ez most lényegtelen. Fel szerettem volna használni ezt az 5 kijelzőt egy pozitív illetve negatív szám kijelzésére alkalmas számkijelző építésére. A shift regisztereket eredetileg a kijelzők hátoldalára építettem, és a „levegőben” összevezetékeztem. Meglehetősen borzalmasan néz ki, de működik, nem is volt nagy munka. Nyákot nem kellett gyártani, a kijelzőket műanyag patronos ragasztóval „szereltem” össze:
Nagy előny, hogy a kijelzők szegmenseit a 74HC595 shift regiszter folyamatos árammal látja el amikor világítani kel a szegmensnek (a 74HC595 működéséről itt bővebben olvashatsz). Ez lényegesen nagyobb fényerőt eredményez, mint pl. egy MAX7219 IC használata esetén, ami időosztásos módon hajtja meg a szegmenseket és az eredő fényerő így sokkal kisebb.
Ha már elkészült a hardver, írtam egy függvényt, ami kijelez egy számot. Nagyon kényelmes a használata, mert paraméterként egy long típusú változóban át kell adni a kijelzésre szánt számadatot, és ezzel készen is vagyunk. Tizedes érték megjelenítésre is alkalmas, ekkor azonban előtte „egész”-re kell felszorozni, és egy paraméterben beállítható a tizedesjegyek száma, azaz a tizedespont megjelenésének helye. Van egy harmadik paraméter is, amivel beállítható a vezető zeró elnyomás, azaz a szám elején lévő felesleges nullák kikapcsolhatók. Biztos vagyok benne, hogy számtalan hasonló függvény létezik, de szórakoztató volt megírni. Egy ilyen piti feladat végrehajtása után már tudom, hogy miért kellett a holdraszálláshoz közel 10 év és több tízezer ember munkája.
A függvény megírása nem is volt rövid munka, sokat kínlódtam, hogy minden szituációban jól működjön. Különösan a negatív számok és zéró elnyomás esetén volt sok eset amit mind végig kellett gondolni, és helyesen leprogramozni. Azt hiszem, hogy most jól működik. Mivel elég sok munka van benne, érdemesnek tartom arra, hogy megosszam, talán másnak is hasznos. A példa programban a loop()-ban található az a tesztelő programrész, amivel a legtöbb kritikusnak ítélt szituációt leteszteltem. Pár órám ráment, mire minden helyesen működött. A kommentekben található instrukció arra vonatkozóan, hogyan kell átalakítani a programot, ha más 74HC595 kivezetésekre kerültek a szegmensek.
A függvény +99.999 és -9.999 közötti számot tud megjeleníteni. Ha a paraméterben átadott szám nagyobb illetve kisebb mint a megjeleníthető, akkor „>>>” és „<<<” jelekhez hasonló jelzés jelenik meg a kijelzőn. Beállítható, hogy a felesleges vezető nullákat ne jelenítse meg, pl. 00021 helyett 21 lesz a látható eredmény. A tizedes pont helye, azaz a kijelzett szám tizedes jegyeinek száma beállítható. Pl. 0,21 kijelzéséhez a függvénynek át kell adni paraméterként a 21-et tartalmazó változó értéket, második paraméterként 2-őt, mert két tizedesjegyet akarunk látni, illetve harmadik paraméterként a zéró elnyomást jelezni kell 1-el:
sseg_disp(21,2,1);
Zéró elnyomás esetén figyelemebe veszi a tizedespontot, tehát ha a tizedes pont miatt kell vezető nulla, akkor azt oda helyezi. Pl. az előző példa szerinti 0.21-nél is ez történik, nem csinált belőle .21-et! Ezekkel az esetekkel vesződtem sokat, hogy mind jól működjön.
Néhány fotó a működésről. Olyan nagy volt a fényerő, hogy a fotókat sötétíteni kellett, illetve mindegyik másképpen színeződik, így kicsit csúnya lett:
Remélem a példaprogram kommentjei alapján használható a függvény:
/******************************************************************************************* * Az alábbi memóban némi instrukció található ahhoz, hogy a példa program * * miért éppen a megadott adatokat küldi a 74HC595 shift regiszterbe ahhoz * * hogy a megfelelő számjegy jelenjen meg a kijelzőn. * * Szegmensek kódolása: * * --a-- * * f b * * --g-- * * e c * * --d-- dp * * * * Az alábbi módon sikerült nekem bekötnöm a LED kijelzők szegmenseit. * * Tehát ha beírok egy 74HC595 regiszterébe egy alábbi értéket, akkor * * a megadott szegmens világít. * * dec érték bin. érték világító szegmens * * abfgd ce * * 1 00000001 e * * 2 00000010 c * * 4 00000100 dp * * 8 00001000 d * * 16 00010000 g * * 32 00100000 f * * 64 01000000 b * * 128 10000000 a * * * * Az alábbi táblázat azt adja meg, hogy az általam megvalósított bekötéssel, melyik * * számjegyet melyik bitsorozat regiszterbe léptetésével lehet megjeleníteni. * * Számjegy világító szegmensek bin érték dec.érték * * -------- -------- --------- --- * * abfgd ce * * 0 afedcb 11101011 235 * * 1 bc 01000010 66 * * 2 abged 11011001 217 * * 3 abgcd 11011010 218 * * 4 fgbc 01110010 114 * * 5 afgcd 10111010 186 * * 6 afgecd 10111011 187 * * 7 abc 11000010 194 * * 8 abfgecd 11111011 251 * * 9 afbgcd 11111010 250 * * space 00000000 0 * * - g 00010000 16 * * < egd 00011001 25 * * > gcd 00011010 26 * *******************************************************************************************/ const byte SH_CP = 8; //chip 11-es láb, órajel bemenet (felfutó élre lépteti be az adatot) const byte ST_CP = 9; //chip 12-es láb, Latch bemenet (beléptetett adat kimenetre írása, tárolása felfutó éllel) const byte OE_negalt = 10; //chip 13-as láb, kimenet engedélyező (pwm fényerő szabályozáshoz) const byte DS = 11; //chip 14-es láb, adatbemenet const byte disp[]={235,66,217,218,114,186,187,194,251,250,0,16,25,26}; //karakterképek a disp nevű tömbbe töltése //10-es index értékű elem a space, 11 a negatív jel long i; //teszteléshez használt változó void setup() { Serial.begin(9600); pinMode(7, OUTPUT); //74LS595 reset lábához kötött kimenet digitalWrite(7,LOW);delay(10);digitalWrite(7,HIGH);delay(10); //adunk egy reset jelet (LOW) a chip-nek. //elvileg a reset bemenetet magas szintre is lehet kötni, //nem szükséges a reset használata. Törölni az összes bit //0-ra állításával is lehet. pinMode(SH_CP, OUTPUT); //74HC595 órajel bemenetére kötött kimenet minden felfutóélnél belépteti a DS-en lévő értéket pinMode(ST_CP, OUTPUT); //74HC595 Latch bemenetére kötött kimenet lefutóéllel tárolja a beléptetett adatot pinMode(OE_negalt, OUTPUT); //74HC595 órajel bemenetére kötött kimenet LOW szinttel engedélyezi a kimeneteket, magas szint esetén //tristate állapotba kerül a led meghajtó kimenet, így egyetlen szegmens sem világít. Fényerőszabályozáshoz //használatos bemenete a chip-nek. analogWrite(OE_negalt,0); //pwm jelet adunk a chip OE bemenetére, 0 max. fényerő, 255 a minimális fényerő, mivel 0-nél világitanak a szegmensek pinMode(DS, OUTPUT); //74HC595 adatbemenetére kötött kimenet, erre léptetjük rá sorban az egyes biteket } /************************************************************************************************** * Ez a loop() egy tesztelésre írt program részemről. Ezzel mutatom be, illetve teszteltem, * * hogy a megjelenítés minden szituációban jól működik. Különösen a zéró elnyomás tizedes * * jegyekkel történő kombinálását kellett tesztelni, mert elég sok esetet kellett végig gondolni! * * Remélem minden szituációt végig próbáltam. * **************************************************************************************************/ void loop() { i=100000; //felső értékhatár átlépése teszt sseg_disp(i,0,1); delay(1000); i=-10000; //als értékhatár átlépése teszt sseg_disp(i,0,1); delay(1000); i=0; sseg_disp(i,0,0); //nulla megjelenítés tizedespont nélkül, bevezető zéró elnyomás nélkül delay(1000); sseg_disp(i,1,0); //nulla megjelenítés, tizedespont a második digiten, bevezető zéró elnyomás nélkül (egy tizedesjegyű szám) delay(1000); //a többi digiten való tizedespont megjelenítést nem érdemes tesztelni, mert nem befolyásolja a megjelenítést a tizedespont helye sseg_disp(i,0,1); //nulla megjelenítés tizedespont nélkül, bevezető zéró elnyomással delay(1000); sseg_disp(i,1,1); //nulla megjelenítés, tizedespont második digiten, bevezető zéró elnyomással delay(1000); //az első digiten nincs értelme a tizedespontnak sseg_disp(i,2,1); //nulla megjelenítés, tizedespont harmadik digiten, bevezető zéró elnyomással delay(1000); sseg_disp(i,3,1); //nulla megjelenítés, tizedespont negyedik digiten, bevezető zéró elnyomással delay(1000); //az ötödik digiten nincs értelme megjeleníteni a tizedespontot i=-1; sseg_disp(i,0,1); //nulla megjelenítés tizedespont nélkül, bevezető zéró elnyomással delay(1000); sseg_disp(i,1,1); //nulla megjelenítés, tizedespont második digiten, bevezető zéró elnyomással delay(1000); //az első digiten nincs értelme a tizedespontnak sseg_disp(i,2,1); //nulla megjelenítés, tizedespont harmadik digiten, bevezető zéró elnyomással delay(1000); sseg_disp(i,3,1); //nulla megjelenítés, tizedespont negyedik digiten, bevezető zéró elnyomással delay(1000); //az ötödik digiten nincs értelme megjeleníteni a tizedespontot for (i=5;i<16;i++) { //Kijelezett érték nő, nincs tizedespont, így vezető nulla elnyomás történik Serial.println(i); sseg_disp(i,0,1); delay(500); } for (i=5;i<16;i++) { //Kijelezett érték nő, de tizedes pont helye miatt van vezető nulla Serial.println(i); sseg_disp(i,1,1); delay(500); } for (i=5;i<16;i++) { //még arrébb raktuk a tizedespontot Serial.println(i); sseg_disp(i,2,1); delay(500); } for (i=-15;i<-5;i++) { //negatív szám kijelzése, nincs tizedespont, így vezető nulla elnyomás történik Serial.println(i); sseg_disp(i,0,1); delay(500); } for (i=-15;i<-5;i++) { //negatív szám kijelzése, de tizedes pont helye miatt van vezető nulla Serial.println(i); sseg_disp(i,1,1); delay(500); } for (i=-15;i<-5;i++) { //negatív szám, még arrébb raktuk a tizedespontot Serial.println(i); sseg_disp(i,2,1); delay(500); } } /***************************************************************************** * Ez a függvény egy jelen esetben 5 digites 74HC595 shift regiszter * * láncolatra léptet ki egy megadott számadatot. A szám tartománya * * -9999-től +99999-ig terjed. A tizedespont egy külön paraméterben * * meghatározott fix helyen jelenik meg. Erre oda kell figyelni, átadni * * egész értékű számot lehet (long). Beállítható a bevezető nullák elnyomása,* * ekkor a kisebb számok elején lévő nullák nem jelennek meg. * * Bemenő paraméterek: * * szam - long érték -9999 és +99999 között, ezt jelenítjük meg * * dp - a tizedesjegyek száma. 0 esetén nincs tizedesjegy a kijelzett * * számban, 1 esetén egy tizedesjegy, 2 esetén két tizedesjegy stb.* * zeroelnyomas - 0 esetén megjelennek a vezető nullák, míg 1 esetén * * a kisebb számok vezető nulláit nem jeleníti meg * * Ha be van állítva tizedespont, akkor a tizedes pont * * digitjéig mindenképpen megjelenik a vezető nulla pl.: * * -0.01 * *****************************************************************************/ void sseg_disp(long szam,byte dp,bool zeroelnyomas) { byte c4; byte c3; byte c2; byte c1; byte c0; bool minusz=false; if (szam<99999 and szam>-9999) { if (szam<0) {minusz=true; szam=-1*szam;} c4=szam/10000; //tízezres helyiérték számjegyének kiszámítása c3=(szam-(c4*10000))/1000; //ezres helyiértéken lévő szemjegy kiszámítása c2=(szam-(c4*10000)-(c3*1000))/100; //százas helyiértéken lévő szemjegy kiszámítása c1=(szam-(c4*10000)-(c3*1000)-(c2*100))/10; //tizes helyiértéken lévő szemjegy kiszámítása c0=szam-(c4*10000)-(c3*1000)-(c2*100)-(c1*10); //egyes helyiértéken lévő szemjegy kiszámítása if (minusz) { //negatív szám vezető nulláinak és mínusz jelnek a kezelése az alábbi ágon if (!zeroelnyomas) {c4=11;} //ha nincs vezető nulla elnyomás, a bal oldali digit akkor is "-" jelet tartalmaz else { //van vezető nulla elnyomás, így változtatni kell a karaktereken if (c3!=0 or dp>=3) {c4=11;} //a legnagyobb helyiérték nulla, és nincs tizedespont, tehát mínuszjelet rakunk if (c3==0 and dp<3) {c4=10;c3=11;} //az eggyel kisebb helyiérték is nulla, ott sincs tizedespont, így a legnagyobb helyiérték nem világít, ez pedig minusz if (c3==11 and c2==0 and dp<2) { //az eggyel kisebb helyiérték is nulla, és tizedespont sincs, így a legnagyobb és azt követő helyiérték nem világít, és ez a negatív c4=10;c3=10;c2=11; } if (c3==10 and c2==11 and c1==0 and dp<1) { //még az utolsó előtti helyiérték is nulla és nincs tizedespont, így eddig a helyiértékig semmi nem világít, és ez a mínusz jel c4=10;c3=10;c2=10;c1=11; } } } else { //pozitív szám vezető nulláinak kezelése az alábbi else ágon if (zeroelnyomas) { //csak akkor kell csinálni valamit, ha van vezető nulla elnyomás if (c4==0 and dp<4) {c4=10;} //legnagyobb helyiérték nulla, nincs ott tizedespont sem, így nem világít a digit if (c4==10 and c3==0 and dp<3) { //eggyel kisebb helyiérték is nulla és nincs tizedespont, tehát ez sem világít c4=10;c3=10; } if (c4==10 and c3==10 and c2==0 and dp<2) { //eggyel kisebb helyiérték is nulla és nincs tizedespont, tehát ez sem világít c4=10;c3=10;c2=10; } if (c4==10 and c3==10 and c2==10 and c1==0 and dp<1) { //utolsó előtti helyiérték is nulla és nincs tizedespont, tehát ez sem világít c4=10;c3=10;c2=10;c1=10; } } } } else { if (szam>99999) {c4=12;c3=12;c2=12;c1=10;c0=10;} //ha a szám nagyobb mint 99999, akkor "<<< " jelzi a pozitív túlcsordulást if (szam<-9999) {c4=10;c3=10;c2=13;c1=13;c0=13;} //ha a szám kisebb mint -9999, akkor " >>>" jelzi a negatív túlcsordulást } digitalWrite(ST_CP,0); //Latch bemenetre 0-at kapcsolunk, ekkor lehet beléptetni az adatokat //sorban beléptetjük az adatokat a kijelző láncolatba. Mivel nálam jobbról lépnek be az adatok, először a lánc legvégén //lévő chip adatait kell kiléptetni. Mivel a láncolatom 5 db chip-ből áll, 5 shiftout() függvénnyel lép ki egy teljes kijelző tertalom. //Amennyiben egy adott digitnél tizedespont is kell, a tizedespontot egy bitenkénti vagy művelettel állítjuk be a kiléptetésre //kerülő adatban. if (dp==4) {shiftOut(DS, SH_CP, MSBFIRST, disp[c4]|0b00000100);} else {shiftOut(DS, SH_CP, MSBFIRST, disp[c4]);} //balról az első digit beléptetése if (dp==3) {shiftOut(DS, SH_CP, MSBFIRST, disp[c3]|0b00000100);} else {shiftOut(DS, SH_CP, MSBFIRST, disp[c3]);} //balról második digit beléptetése if (dp==2) {shiftOut(DS, SH_CP, MSBFIRST, disp[c2]|0b00000100);} else {shiftOut(DS, SH_CP, MSBFIRST, disp[c2]);} //balról harmadik digit beléptetése if (dp==1) {shiftOut(DS, SH_CP, MSBFIRST, disp[c1]|0b00000100);} else {shiftOut(DS, SH_CP, MSBFIRST, disp[c1]);} //balról negyedik digit beléptetése shiftOut(DS, SH_CP, MSBFIRST, disp[c0]); //jobbról az első digiten nem lehet tizedespont digitalWrite(ST_CP,1); //Latch bemenetet vissza állítjuk 1-re, a beléptetett adatokat a chip tárolja, és megjelenik a kimeneteken a beléptetett állapot }