Formázott számkijelzés 7 szegmenses kijelző soron

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
}

Mennyire volt hasznos amit olvastál? Értékelés után szövegesen is leírhatod megjegyzéseidet és véleményedet!

Kattints egy csillagra az értékeléshez!

Szövegesen is leírhatod véleményedet! Ha kérdésed van, ne felejtsd el megadni az email címedet!