A nagy megszámolás

Számos módja van annak, hogy digitális számlálót építsünk

Egy próbapanelen összeépített digitális számláló, LCD kijelzője a 42-es számot mutatja

Van egy régóta húzódó hardveres projektem. Haladgat szépen-lassan, már csak a programozás részét kellene befejezni, de ritkán jön meg a kedvem hozzá. Így sajnos fokozottan fogékony vagyok a figyelemelterelésekre.

Szóval láttam egy videóban egy mechanikus számlálót, ami nem sokkal több, mint négy számjegy és egy gomb, amivel lehet növelni a számot. Meg egy tekerő, amivel le lehet nullázni az egészet.

Egy mechanikus kézi számláló

Valamivel később pedig belefutottam egy cuki kis LCD kijelzőbe. Három számot tud megjeleníteni és méreteiből adódóan felettébb próbapanel-kompatibilisnek tűnt.

IC-kre hasonlító LCD kijelzők

Talán érezzük már, hogy hova fog kifutni ez az egész. Építeni kellene egy digitális számlálót. Biztos nem túl bonyolult. Csak egy mikrokontroller, egy-két gomb, egy 7 szegmenses kijelző és néhány sor kód. Vagy mégse?

A cél hardver

Szokás szerint nem az egyszerű úton indultam el. Mint oly sokszor, most sem a digitális számláló elkészülése a cél. Az csak egy eszköz, hogy ne a másik projekten kelljen dolgoznom.

Annyira azért nem akartam megnehezíteni a dolgomat, hogy az egészet NAND kapukból rakom össze. Vannak alkatrészek, amik remekül megvalósítanak részfeladatokat a folyamatból. Például IC-k, amik tudnak számlálni vagy éppen értik a 7 szegmenses kijelzők szegmens formátumát.

Kis keresés után ráleltem a CD4026B nevű chip-re, ami 0-tól 9-ig tud számolni és a kimenete a 7 szegmenses kijelző szegmenseinek felel meg (a-tól g-ig).

                   ┌───┬──┬───┐
             CLOCK ┤ • └──┘   ├ VDD
     CLOCK INHIBIT ┤          ├ RESET
 DISPLAY ENABLE IN ┤          ├ UNGATED "C" SEGMENT OUT
DISPLAY ENABLE OUT ┤          ├ c
         CARRY OUT ┤ CD4026B  ├ b
                 f ┤          ├ e
                 g ┤          ├ a
               VSS ┤          ├ d
                   └──────────┘

A kijelző miatt három számjegyet célzok meg. A chip-en található CARRY OUT kimenet akkor lesz 1, ha a számláló 9-ről 0-ra vált, így egymás után lehet fűzni több CD4026B-t, hogy több számjegyünk legyen. Az alacsonyabb helyiértékű chip CARRY OUT-ját az eggyel magasabb helyiértékű chip CLOCK-jába kell kötni.

Kapcsolási rajz: három, egymás után kötött CD4026B chip

A gombot ráköthetnénk a legkisebb helyiértékű chip CLOCK bemenetére, de van a gomboknak az a rossz tulajdonsága, amit pergésnek neveznek. Egy gombnyomás során az érintkezők néha többször is egymáshoz érnek, így az elvárt egyszeri növelés helyett random mennyiséggel fog növekedni a számunk. Nem annyira jó működés egy számláló esetében.

Az Internet szerint rengeteg mód van arra, hogy ezt kivédjük, nekem egy Ben Eater videó rémlett fel a 8 bites számítógép építés sorozatából, ahol egy monostabil 555 időzítővel lett ez megoldva.

Kapcsolási rajz: monostabil 555 időzítő és CD4026B számláló

Ezen a ponton van egy jól működő gombunk és három egymás után kötött chip-ünk, amik együtt el tudnak számolni 0-tól 999-ig. De nem látjuk, hogy éppen hol tartanak.

A fentebb említett LCD kijelzőről kiderült, hogy sajnos nem olyan egyszerű vezérelni, mint mondjuk egy 7 szegmenses LED kijelzőt, meg egyébként sem érkezett meg időben, úgyhogy egy BC56-12-es modellt használtam helyette.

BC56-12 típusú, három karakteres LED kijelző

Róla annyit érdemes tudni, hogy mind a három számjegy ugyanazokat a szegmens bemeneteket használja. Van ezen kívül három másik bemenet, amivel azt választhatjuk ki, hogy éppen melyik számjegy aktív. Szóval ha három különböző számjegyet akarunk egyszerre megjeleníteni, akkor nagyon gyorsan kell váltogatnunk a három szám között, hogy a szemünknek úgy tűnjön, mintha a három számjegy egyszerre világítana.

Két fajta változat létezik ebből a fajta kijelzőből: közös anódos és közös katódos, attól függően, hogy a szegmens LED-eknek az anód vagy a katód végük van összekötve. A mi változatunk közös katódos.

A számok közötti gyors váltakozáshoz szükségünk lesz egy órajelre. Legnagyobb szerencsénkre van egy másik Ben Eater videó, amiből megtanulhatunk órajelet generálni egy astabil 555 időzítő segítségével. Ezt az egy órajelet valahogy még három felé kell osztanunk, hogy kiválaszthassuk vele az aktív számjegyet. Én egy másik számlálót, a CD4017B-t használtam erre.

    ┌───┬──┬───┐
  5 ┤ • └──┘   ├ VDD
  1 ┤          ├ RESET
  0 ┤          ├ CLOCK
  2 ┤          ├ CLOCK INHIBIT
  6 ┤ CD4017B  ├ CARRY OUT
  7 ┤          ├ 9
  3 ┤          ├ 4
VSS ┤          ├ 8
    └──────────┘

Ez a számláló kijelző szegmensek helyett 10 különböző kimeneten jelzi, hogy melyik számnál tart éppen. Az első három számot fogjuk felhasználni arra, hogy legyen három, egymást kölcsönösen kizáró jelünk, a negyedik számot pedig arra, hogy RESET-eljük a chip-et, hogy újra nulláról induljon.

Kapcsolási rajz: astabil 555 időzítő és CD4017B számláló

Tehát az egyik oldalon vannak az egymás után fűzött számlálóink a gombbal, a másik oldalon van egy órajelünk három felé osztva, amivel kiválaszthatjuk az aktív számjegyet.

A számlálóinkon van egy ígéretes nevű DISPLAY ENABLE IN bemenet, amiről joggal gondolhatjuk azt, hogy hasznos lehet a kijelző meghajtása során. De nem az.

A DISPLAY ENABLE IN kikapcsolása esetén a kimenetek alacsony állapotba kerülnek. Ha össze vannak kötve más kimenetekkel, amik magas állapotban vannak (mert egy szegmens egy másik számjegyben be van kapcsolva), akkor abból rövidzárlat lesz. Így nem tanácsos összekötni a számlálóink kimeneteit.

Talán néhány (21 darab) dióda meg tudta volna oldani a problémát, de én az erre a célra kitalált 74HC541 chip-et választottam:

     ┌───┬──┬───┐
OE1' ┤ • └──┘   ├ VDD
  A0 ┤          ├ OE2'
  A1 ┤          ├ Y0
  A2 ┤          ├ Y1
  A3 ┤          ├ Y2
  A4 ┤ 74HC541  ├ Y3
  A5 ┤          ├ Y4
  A6 ┤          ├ Y5
  A7 ┤          ├ Y6
 VSS ┤          ├ Y7
     └──────────┘

Az A0-7 pin-eken jön a bemenet, amit megkapunk az Y0-7 pin-eken, ha a kimenetek engedélyezve vannak (OE1' és OE2'). Ha a kimenet nincs engedélyezve, akkor nagy impedanciás módba kerülnek az Y0-7 kimenetek és nem zavarják egymást.

Kapcsolási rajz: CD4026B és 74HC541 chip-ek vezetékezése

Szóval a három CD4026B számlálónk a-g kimenetét rákötjük egy-egy 74HC541 chip bemenetére (a képen a kék vezetékek), a három 74HC541 kimenetét (a képen a zöld vezetékek) pedig összekötjük és rákötjük a kijelzőre.

Az órajelet három felé osztó CD4017B-ből érkező jeleket szeretnénk arra használni, hogy a megfelelő 74HC541 IC és LED számjegy legyen csak aktív. De mindkét helyen alacsony jelre van szükségünk, a CD4017B pedig magas jelet ad az aktív számjegyre. Szerencsére erre is léteznek integrált áramkörök, mint például a 74HC240, ami a bemenő jelet negálja.

     ┌───┬──┬───┐
1OE' ┤ • └──┘   ├ VDD
 1A1 ┤          ├ 2OE'
 2Y4 ┤          ├ 1Y1
 1A2 ┤          ├ 2A4
 2Y3 ┤          ├ 1Y2
 1A3 ┤ 74HC240  ├ 2A3
 2Y2 ┤          ├ 1Y3
 1A4 ┤          ├ 2A2
 2Y1 ┤          ├ 1Y4
 VSS ┤          ├ 2A1
     └──────────┘

Rákötjük a CD4017B-ből érkező három kimenetünket mondjuk az 1A1, 1A2 és 1A3 bemenetekre és megkapjuk az ellentétét az 1Y1, 1Y2 és 1Y3 kimeneteken.

Ezzel meg is van minden részegység, amire szükségünk van egy működő számlálóhoz. Már csak össze kell drótoznunk mindent és kész is vagyunk.

                                                              ╔═════════╗
                      ┌───────────┬───────────┬───────────┬───╢ BC56-12 ║
                      │           │           │           │   ╚═════════╝
                      │           │           │           │
                 ╔════╧════╗ ╔════╧════╗ ╔════╧════╗ ╔════╧════╗
                 ║ 74HC541 ║ ║ 74HC541 ║ ║ 74HC541 ║ ║ 74HC240 ║
                 ╚════╤══╤═╝ ╚════╤══╤═╝ ╚════╤══╤═╝ ╚═╤══╤════╝
                      ┃  └────────╂──┴────────╂──┴─────┘  │
                      ┃           ┃           ┃      ╔════╧════╗
                      ┃           ┃           ┃      ║ CD4017B ║
                      ┃           ┃           ┃      ╚════╤════╝
                      ┃           ┃           ┃           │
╔══════╗ ╔═════╗ ╔════╧════╗ ╔════╧════╗ ╔════╧════╗   ╔══╧══╗
║ Gomb ╟─╢ 555 ╟─╢ CD4026B ╟─╢ CD4026B ╟─╢ CD4026B ║   ║ 555 ║
╚══════╝ ╚═════╝ ╚═════════╝ ╚═════════╝ ╚═════════╝   ╚═════╝

Az elkészült digitális számláló két próbapanelen

A képen még látható, hogy be van kötve egy extra gomb a három CD4026B RESET pin-jeire. Induláskor előfordul, hogy random értékekről indulunk, ezért jó ha van kéznél egy nullázó gomb.

Ugyan a végeredmény remekül néz ki, azért elég kényelmetlen lenne kézi számlálóként használni, így tovább nézelődtem alternatív megoldások után.

Segít a memória

A YouTube Algoritmus ezen a ponton már valószínűleg tökéletesen tisztában volt azzal, hogy miben mesterkedem. Volt olyan kedves és felajánlott még egy Ben Eater videót megtekintésre, ami pont egy 7 szegmenses LED kijelző meghajtásáról szól EEPROM segítségével.

Az ott használt alkatrészek ugyan nem teljesen felelnek meg a céljainknak, de az alapötletet fel tudjuk használni: az EEPROM-ban letároljuk előre, hogy adott szám és adott számjegy esetén a 7 szegmens közül melyikeket kell bekapcsolni.

Tehát az EEPROM bemenete az lesz, hogy melyik számjegyet jelenítjük meg éppen (3 pin) és melyik számnál járunk éppen (10 pin, 10 bit, 0 és 1023 közötti számok). A kimenet pedig a hét szegmens állapota (7 pin). Az AT28C64B pont megfelel ezeknek a feltételeknek, 13 bemenete és 8 kimenete van.

     ┌───┬──┬───┐
     ┤ • └──┘   ├ VDD
 A12 ┤          ├ WE'
  A7 ┤          ├ 
  A6 ┤          ├ A8
  A5 ┤          ├ A9
  A4 ┤          ├ A11
  A3 ┤          ├ OE'
  A2 ┤ AT28C64B ├ A10
  A1 ┤          ├ CE'
  A0 ┤          ├ I/O7
I/O0 ┤          ├ I/O6
I/O1 ┤          ├ I/O5
I/O2 ┤          ├ I/O4
 VSS ┤          ├ I/O3
     └──────────┘

Az áramkör eleje nagyon ismerős lesz, először is egy monostabil 555 időzítő a gombnyomás pergés mentesítéséhez, egy astabil 555 időzítő az órajelhez és egy CD4017B IC, amivel a három számjegyből választjuk ki az egyiket. Számlálónak a CD4040B-t fogjuk használni, ami 12 bitnyi bináris kimenetet produkál (0-tól 4095-ig tud számolni).

    ┌───┬──┬───┐
Q12 ┤ • └──┘   ├ VDD
 Q6 ┤          ├ Q11
 Q5 ┤          ├ Q10
 Q7 ┤          ├ Q8
 Q4 ┤ CD4040B  ├ Q9
 Q3 ┤          ├ RESET
 Q2 ┤          ├ CLOCK
VSS ┤          ├ Q1
    └──────────┘

Az AT28C64B-be töltött adat végzi el a konvertálást a bináris számláló és a LED kijelző között. A LED kijelző pedig most egy BA56-12 lesz, hogy ne kelljen invertálni az órajelet (a közös anód miatt a kiválasztott számjegy magas állapotban kell, hogy legyen, a világításra ítélt szegmens pedig alacsonyban).

Először is meg kell töltenünk adattal az EEPROM-ot. Ehhez egy Raspberry Pi Pico-t használtam, szerencsére pont van rajta elég GPIO pin.

Két Raspberry Pi Pico és az EEPROM, amit felprogramoznak

Írtam hozzá egy kis programot, de lusta voltam értelmezni az AT28C64B időzítési diagramjait, inkább elég nagy ráhagyásokkal dolgoztam, ami a sleep-eket illeti. Így elég lassú lett, cserébe viszont nem is annyira megbízható. Egymás után többször is le kellett futtatnom, hogy a megfelelő értékeket írja be.

#define A0 10
// ...
#define A12 2
#define IO0 11
// ...
#define IO7 18
#define WE 27
#define OE 20

const uint8_t address[13] = { A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12 };
const uint8_t io[8] = { IO5, IO7, IO1, IO4, IO3, IO6, IO2, IO0 };

const uint8_t numbers[10][8] = {
    {0, 0, 0, 0, 0, 0, 1, 1},
    {1, 0, 0, 1, 1, 1, 1, 1},
    {0, 0, 1, 0, 0, 1, 0, 1},
    {0, 0, 0, 0, 1, 1, 0, 1},
    {1, 0, 0, 1, 1, 0, 0, 1},
    {0, 1, 0, 0, 1, 0, 0, 1},
    {0, 1, 0, 0, 0, 0, 0, 1},
    {0, 0, 0, 1, 1, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 0, 1},
    {0, 0, 0, 0, 1, 0, 0, 1},
};

Egy kis konfigurációval indítunk. Szükségünk van arra, hogy az AT28C64B pinjei melyik Pico pin-eknek felelnek meg. Aztán definiáljuk a cím- és I/O pin-ek sorrendjét és végül kell egy megfeleltetés, hogy melyik számot melyik szegmensek reprezentálják.

A cím- és I/O pin-ek sorrendje itt attól függ, hogy a végleges helyén hogyan fogjuk összedrótozni az AT28C64B-t a bemeneteivel és a kimenetével. A cím esetén az A0-A9 pinre fog érkezni a szám, ahol a számláló tart. Az A10-A12 pinek pedig a számjegy kiválasztására lesznek használva. Az I/O pin-ek azért vannak össze-vissza, hogy legyen elég hely a vezetékeknek az EEPROM és a kijelző között.

int main()
{
    stdio_init_all();

    gpio_init(WE);
    gpio_set_dir(WE, GPIO_OUT);
    gpio_put(WE, true);

    gpio_init(OE);
    gpio_set_dir(OE, GPIO_OUT);
    gpio_put(OE, true);

    for (const uint8_t pin : address)
    {
        gpio_init(pin);
        gpio_set_dir(pin, GPIO_OUT);
        gpio_put(pin, false);
    }
    for (const uint8_t pin : io)
    {
        gpio_init(pin);
        gpio_set_dir(pin, GPIO_OUT);
        gpio_put(pin, false);
    }

    // ...
}

Az inicializálás során mindent kimenetre állítunk és mindent kikapcsolunk. A WRITE ENABLE és OUTPUT ENABLE pin-ek esetén ez magas állapotot jelent. Ezek után folytathatjuk a main() függvény tartalmát az adatok beírásával.

printf("write\n");
for (int i = 0; i < 1000; ++i)
{
    for (int j = 0; j < 10; ++j)
    {
        gpio_put(address[j], (i & static_cast<int>(pow(2, j))) > 0);
    }

    for (int j = 0; j < 3; ++j)
    {
        gpio_put(address[10], false);
        gpio_put(address[11], false);
        gpio_put(address[12], false);
        gpio_put(address[10 + j], true);

        const int digit = i / static_cast<int>(pow(10, j)) % 10;

        for (int k = 0; k < 8; ++k)
        {
            gpio_put(io[k], numbers[digit][k]);
        }

        sleep_ms(5);
        gpio_put(WE, false);
        sleep_ms(5);
        gpio_put(WE, true);
        sleep_ms(5);
    }
    if (i % 10 == 0)
    {
        printf(".");
    }
}
printf("\ndone.\n");

A cím első 10 bitje a szám, amit meg akarunk jeleníteni. Az utolsó 3 bit az éppen aktív számjegyet jelöli. Az eltárolt érték az adott helyi értéken lévő számjegy 7 szegmenses reprezentációja lesz. Ehhez eggyel/tízzel/százzal osztjuk el az eredeti számot és megnézzük a tízzel osztás során képződő maradékát.

A cím és az I/O pin-ek értékeinek beállítása után be- majd újra kikapcsoljuk az WRITE ENABLE pin-t és megyünk tovább a következő számjegyre majd számra.

Az EEPROM felprogramozása után már csak össze kell kötnünk mindent.

         ╔═════╗ ╔═════════╗
         ║ 555 ╟─╢ CD4017B ╟─┐
         ╚═════╝ ╚═════════╝ │ ╔══════════╗ ╔═════════╗
                             ├─╢ AT28C64B ╟─╢ BA56-12 ║
╔══════╗ ╔═════╗ ╔═════════╗ │ ╚══════════╝ ╚═════════╝
║ Gomb ╟─╢ 555 ╟─╢ CD4040B ╟─┘
╚══════╝ ╚═════╝ ╚═════════╝

Az EEPROM-os változata a digitális számlálónak egy próbapanelen

Ez a verzió ugyan fele akkora lett, mint az előző, de azért vannak hibái. A használt számláló chip 12 bites, amiből 10 bitet használunk. 10 biten 0-tól 1023-ig tudunk elszámolni, de a kijelzőn csak három számjegy látszik. Úgyhogy a kedves felhasználó azt fogja tapasztalni, hogy 999 után 23-ig fog számolni, aztán újra 999-ig, aztán újra 23-ig és így tovább.

Ezen kívül a CD4017B valószínűleg nem tud elég áramot adni, hogy rendesen meg legyenek hajtva a LED-ek, ezért olyan halovány a kijelző.

Valószínűleg egyik probléma sem megoldhatatlan, de extra komponenseket jelentenek, amik tovább növelik a méretet. Mi a helyzet akkor, ha valami kisebbet szeretnénk?

Szoftveres megoldások

Utolsó ötletem a legelőször elvetett volt: egy mikrokontroller. Ugyan egy Raspberry Pi Pico túlzás lenne egy ilyen kicsi feladathoz, de kereshetünk valamit, ami jobban passzol.

Amire szükségünk van: 7 kimenet a szegmensekhez, 3 kimenet a számjegy választáshoz és két bemenet a gomboknak. Az ATtiny24A pont jónak is tűnik. 12 pin-ből 11-et tudunk használni a saját céljainkra, a tizenkettedik pedig fixen a RESET, ami pont jó, mert arra van szükségünk.

       ┌───┬──┬───┐
   VDD ┤ • └──┘   ├ VSS
   PB0 ┤          ├ PA0
   PB1 ┤          ├ PA1
RESET' ┤ ATtiny24 ├ PA2
   PB2 ┤          ├ PA3
   PA7 ┤          ├ PA4
   PA6 ┤          ├ PA5
       └──────────┘

Az áramkör ennél egyszerűbb talán már nem is lehet, csak az ATtiny24A, két gomb és a LED kijelző (újra egy BA56-12, de ez esetben bármelyiket használhattuk volna, csak a kódon változtat).

Kapcsolási rajz: ATtiny24A és az LCD kijelző

Sajnos a kijelzőhöz nem volt megfelelő komponens, úgyhogy csak a helye van ott

Az egyszerűség oka pedig az, hogy mindent szoftverből kell megoldanunk. Ehhez fel kell programoznunk az ATtiny-t. Először egy Raspberry Pi-t próbáltam használni, de valamiért nem működött, úgyhogy végül egy Arduino UNO-val mentem.

ATtiny24A programozása Arduino UNO segítségével

Nem a legegyszerűbb dolog programot juttatni az ATtiny-re, de nem mennék bele a részletekbe, itt van rá egy részletes leírás. Ugorjunk inkább a programozásra.

const byte digits[3] PROGMEM = {0, 3, 4};
const byte segments[7] PROGMEM = {1, 5, 7, 9, 10, 2, 6};

const byte numbers[10][7] PROGMEM = {
  {0, 0, 0, 0, 0, 0, 1},
  {1, 0, 0, 1, 1, 1, 1},
  {0, 0, 1, 0, 0, 1, 0},
  {0, 0, 0, 0, 1, 1, 0},
  {1, 0, 0, 1, 1, 0, 0},
  {0, 1, 0, 0, 1, 0, 0},
  {0, 1, 0, 0, 0, 0, 0},
  {0, 0, 0, 1, 1, 1, 1},
  {0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 1, 0, 0},
};

const byte buttonPin = 8;

Maga a program ismét egy kis inicializációval indul. Megadjuk a számjegy és szegmens pin-eket, valamint a korábban már használt megfeleltetést a számjegy és a szegmensek között. A nagyobb adatokat program memóriában tároljuk (PROGMEM), hogy futás közben ne foglalják a helyet. Cserébe kicsit nehezebb lesz elérni őket.

void setup() {
  for (byte i = 0; i < 3; ++i) {
    pinMode(pgm_read_byte(&digits[i]), OUTPUT);
    digitalWrite(pgm_read_byte(&digits[i]), LOW);
  }
  for (byte i = 0; i < 7; ++i) {
    pinMode(pgm_read_byte(&segments[i]), OUTPUT);
    digitalWrite(pgm_read_byte(&segments[i]), HIGH);
  }

  pinMode(buttonPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(buttonPin), increment, RISING);  
}

A számjegy választókat és a szegmenseket lekapcsoljuk, a gomb pin-jére pedig rakunk egy megszakítást. A pgm_read_byte a korábban említett nehezebb elérése a program memóriában tárolt adatoknak.

volatile byte d0 = 0;
volatile byte d1 = 0;
volatile byte d2 = 0;

volatile bool pressed = false;
volatile unsigned long pressTime;

void increment() {
  if (!pressed) {
    pressed = true;
    pressTime = millis();

    d2 += 1;
    if (d2 > 9) {
      d2 = 0;
      d1 += 1;
      if (d1 > 9) {
        d1 = 0;
        d0 += 1;
        if (d0 > 9) {
          d0 = 0;
        }
      }
    }
  }
}

A megszakítás eltárolja a megnyomás idejét és megnöveli a számjegyeket, ha még nem volt megnyomva a gomb. Ez lesz a pergés elleni védelmünk alapja.

A számjegyek külön tárolása és egyesével növelése nem nevezhető éppen elegánsnak, de megspórolhatunk vele néhány osztást és maradék számítást a kijelző vezérlése során.

void loop() {
  if (pressed) {
    noInterrupts();
    unsigned long t = pressTime;
    interrupts();
    if (millis() - t > 150) {
      pressed = false;
    }
  }

  for (byte i = 0; i < 7; ++i) {
    digitalWrite(pgm_read_byte(&segments[i]), pgm_read_byte(&numbers[d0][i]));
  }
  digitalWrite(pgm_read_byte(&digits[0]), HIGH);
  delay(5);
  digitalWrite(pgm_read_byte(&digits[0]), LOW);

  for (byte i = 0; i < 7; ++i) {
    digitalWrite(pgm_read_byte(&segments[i]), pgm_read_byte(&numbers[d1][i]));
  }
  digitalWrite(pgm_read_byte(&digits[1]), HIGH);
  delay(5);
  digitalWrite(pgm_read_byte(&digits[1]), LOW);

  for (byte i = 0; i < 7; ++i) {
    digitalWrite(pgm_read_byte(&segments[i]), pgm_read_byte(&numbers[d2][i]));
  }
  digitalWrite(pgm_read_byte(&digits[2]), HIGH);
  delay(5);
  digitalWrite(pgm_read_byte(&digits[2]), LOW);
}

Programunk fő részében kezeljük a megnyomott gombot: ha elég idő telt el a gomb megnyomása óta (esetünkben 150 mililszekundum), akkor engedjük újra megnyomni a gombot. Nem tökéletes megoldás (mi van mondjuk olyan esetben, ha valaki hosszabb ideig tartja nyomva a gombot és a felengedés okoz pergést?), de itt és most bőven elég.

Ezen kívül itt kezeljük a LED kijelzőt is. Ebben a részben talán nincs semmi meglepő. A numbers tömb megfeleltetése alapján beállítjuk a megfelelő kimenetet a szegmens pin-eken minden egyes számjegyre. A számjegyeket csak kis időre kapcsoljuk be és gyorsan váltakozik az éppen megjelenített számjegy, hogy úgy tűnjön, mintha mindhárom számjegy egyszerre lenne látható.

A delay lehet, hogy egy kicsit magas, azzal érdemes lehet még játszani. Az alábbi képen látszik is, hogy nem egységes fényerejűek a számjegyek, valószínűleg túl alacsony volt még a frissítési gyakoriság.

A digitális számláló mikrokontrolleres változata fél próbapanelen

Sikerült újra megfeleznünk a számláló áramkörünk méretét és azt hiszem ez a legkisebb méret, amit próbapanelen el tudunk érni.

Ugyan a cél nem egy használható méretű digitális kézi számláló volt, de azért nem baj, hogy a végére sikerült valami olyasmit összerakni, ami megfelelően csomagolva egy használható eszköz is lehetne.

Végelszámolás

A három elkészült digitális számláló egymás alatt

Három és fél próbapanel, tizenhat IC, méretre vágott vezetékek százai, vagy fél tucat bütyköléssel töltött este, egy (rövidzárlat okozta túlmelegedésből adódó) égési sérülés és a végeredmény: három digitális számláló.

  • egy cél-chip-eket használó óriási méretű megoldás, ahol a legnagyobb kihívás a sok vezeték volt
  • egy előre programozott EEPROM-os változat a maga különc működésével
  • egy mikrokontroller vezérelt, ahol a limitált hardver hajlamos megviccelni az óvatlan programozókat

Bár méretileg csökkentek a megoldások, az első változatban jelen lévő és szemmel is jól látható komplexitás nem veszett el a lépések során, csak átvándorolt a memóriába, majd a program kódba.

Különszám

Bredbord kényes egyensúlyát egy gombnyomás rázta meg. A pergés okozta zaj elérte 555 bemenetét és a monostabil időzítőben cikázó feszültség megnyitotta az utat a feltöltődés felé. A zaj tüskéi továbbra is bele-belemartak, de 555 kitartotta a jelet míg a növekvő feszültség olyan mértékű lett, hogy egy kisülés kíséretében el kellett engednie. Büszkeséggel tekintett utána, ahogy egybeolvadt az ismeretlennel. Lélekben azonban már a következő ostromra készült.

CD4026B az elkerülhetetlenség nyugalmával várta a rendületlenül felé közeledő órajel ketyegését. Reteszeken és kapukon keresztülszáguldva megváltoztatta belső állapotát. A számláló kilencese átfordult nullába. Visszajutott oda, ahonnan indult, egy újabb kezdethez a végtelen körforgásban. A túlcsordulás ugyan a semmibe vezette a jelet, de Bredbord már kibillent egyensúlyából, ezzel CD4026B olyan megállíthatatlan folyamatokat indított el, amik túlmutatnak létezésén.

Hét részre szakadva terjedt tovább a változás a szegmens lábakon BC56-12 LED-jei felé. Néhányuk a vak semmibe zuhanva hosszú álomba merültek. Mások a feszültség izgalmától fénylőn ébredtek új életre. Az általuk kirajzolt minta isteni kinyilatkoztatásként ragyogott fel: átmenetileg ugyan, de ismét helyreállt az egyensúly.

This post is also available in English: The great count-up

Hozzáfűznél valamit?

Dobj egy emailt a blog kukac deadlime pont hu címre.

Feliratkoznál?

Az RSS feed-et ajánljuk, ha kedveled a régi jó dolgokat.