10. LED-matriisi ja 74HC595 siirtorekisteri

Arduino-oppaan kymmenes osa käsittelee hieman laajempaa ja monimutkaisempaa kokonaisuutta. Tällä kertaa en kuitenkaan käy kaikkia asioita niin perusteellisesti läpi ja jätänkin tutkimisen ja ihmettelyn enemmän lukijan vastuulle. Selitän kuitenkin mielestäni hankalimmat kohdat matriisinäytön ohjauksesta sekä siirtorekisterin käyttämisestä.

Tätä esimerkkiä varten tarvitset:

  • Arduino kehitysalusta
  • 8x8 LED-matriisi
  • 74HC595 siirtorekisteri IC-piiri
  • Koekytkentäalusta sekä johtimia

Kaikki yllä olevat osat löytyvät Prenta Oy:n Arduino Uno rakentelusarjasta.

LED-matriisin kytkeminen Arduinoon

Alla olevassa kuvassa nähdään, kuinka LED-matriisi voidaan kytkeä Arduinoon. LED-matriisin voi kytkeä myös monella muullakin tapaa, tämä on vain yksi esimerkki muiden joukossa. Esimerkiksi Arduinon sivuilla osoitteessa https://www.arduino.cc/en/Tutorial/RowColumnScanning on kerrottu, kuinka Arduino saadaan ohjaamaan matriisia ilman 74HC595 piiriä.

Tässä esimerkissä on kuitenkin kytketty siirtorekisteri ohjaamaan LED-matriisin sarakkeita ja Arduino ohjaa IO-pinneillä suoraan matriisin rivejä.

Klikkaamalla alla olevaa kytkentäkuvaa saat avattua sen suuremmaksi uuteen ikkunaan.

LED-matriisi ja sen toiminta

LED-matriisi on toiminnaltaan melko yksinkertainen, mutta sen ohjaus on hieman mutkikkaampi. Kyseisessä komponentissa on 64 lediä kytketty toisiinsa niin, että kunkin ledin anodi (+) yhdistyy yhdellä rivillä ja katodi (-) toisella rivillä. Näin ollen kultakin riviltä tai sarakkeelta voi kerrallaan loistaa vain yksi LED, kun ohjataan vain kahta LED-matriisin kytkentänastaa.

Tietenkin koko rivin tai sarakkeen saa myös syttymään, kun kytkee kaikki pinnit yhteen, mutta se yleensä ei ole tarkoituksen mukaista. LED-matriisilla onkin tarkoitus näyttää kuvioita, tekstiä ja numeroita. Näitä löytyy esimerkiksi Koneen hisseistä myöskin:

LED-matriiseja on saatavilla eri kokoisina ja näköisinä ja eri värisinäkin. Esimerkiksi Adafruit tarjoaa monenlaista LED-matriisia ja löytyypä niitä muistakin verkkokaupoista, esimerkiksi: http://www.tme.eu/fi/katalog/led-naytot-matriisit_112922/.

Koska LED-matriisissa voi loistaa kerrallaan vain yksi LED, niin tällöin meidän tarvitsee keksiä tapa, millä saadaan matriisi näyttämään siltä, että siinä loistaa useampi LED yhtäaikaa. Tämä tapa on multipleksaus.

Multipleksaus

Multipleksaamisella tarkoitetaan toimintaa, missä useampaa eriarvoista analogista tai digitaalista signaalia yhdistetään samassa väylässä toisiinsa niin, että ne ovat ikään kuin yhtä ja samaa signaalia, mutta kuitenkin toisistaan erillään.

LED-matriisin multipleksauksessa muodostetaan ihmiselle näkymä siitä, että näytöllä olisi kuva, joka näyttäisi muodostuvan useamman ledin loisteesta. Oikeasti näin ei ole, vaan kutakin lediä näytetään vain pienen hetken verran jolloin saadaan syntymään vaikutelma kuvasta. Kyseessä on siis illuusio, minkä aivomme tulkitsevat kuvaksi.

Multipleksausta voidaan kutsua myös skannaukseksi, mikä tarkoittaa sitä, että muistista skannataan kunkin rivin sytytettyjä ledejä ja ohjataan ne päälle tarpeen mukaan. Käytännössä koodi täytyykin tällä skannaus menetelmällä rakentaa.

Ehkä hankalasti selitetty, joten katsotaanpa auttaisiko kuvat paremmin tähän selitykseen:

Multipleksaus ledeille

Yllä olevassa animaatiossa nähdään multipleksaus käytännössä. Jos tarkkaavaisesti katsot, niin sytytetyistä ledeistä muodostuu peilikuva F-kirjaimesta. Multipleksauksen avulla se saadaan näkymään niin, että F-kirjain olisi näytössä koko ajan, vaikka todellisuudessa vain yhden rivin tai sarakkeen ledit voivat olla sytytettyinä joko yksitellen, tai koko rivi/sarake kerrallaan.

Multipleksauksen tarkoituksena on siis vähentää IO-nastojen määrää. Ilman multipleksausta tarvitsisimme 8x8=64 ohjauspinniä kaikkien ledien ohjaamiseksi - ja siihenhän ei Arduino pysty.

Lähteet ja lisäinfot multipleksaukseen liittyen:

http://www.franksworkshop.com.au/Electronics/RGB/RGB.htm (gif)
http://en.wikipedia.org/wiki/Multiplexing
http://www.appelsiini.net/2011/how-does-led-matrix-work

74HC595 siirtorekisteri ja sen toiminta

74HC595 IC-piiri on 8-bittinen siirtorekisteri, jota ohjataan kolmella IO-linjalla. Piirin avulla saadaan sarjamuotoinen data näkymään piirin IO-nastoissa rinnakkaismuotoisena 8-bitin kuviona.

Kun 74HC595 piirin 8-bittiä kytketään LED-matriisiin joko riveihin tai sarakkeisiin, saadaan vähennettyä ns. "IO"-kuormaa Arduinolta matriisin ohjaamiseksi.

Yllä olevan logiikkasymbolikuvan nastat Q1 - Q7 muodostavat 8-bittiä, jotka kytketään LED-matriisille. SHCP-signaali on piirin siirtorekisterin kellopulssi, STCP-signaali on piirin lähtöjen kellopulssi, eli toisin sanoen "latch"-signaali. OE -signaali on piirin "output enable" eli lähdön sallinta. MR -signaali on puolestaan piirin reset, jolla lähdöt saadaan halutessa nollattua. DS-tuloon syötetään sarjamuotoinen data yhdessä SHCP-kellopulssin kanssa. Kun dataa on syötetty 8-bittiä, niin STCP-signaali voidaan aktivoida ja lähdöt Q1-Q7 asettuvat syötettyyn arvoon. Q7S-signaalista saadaan sama sarjamuotoinen data myös ulos, jos kyseisiä rekisteripiirejä kytketään useampia peräkkäin "cascading".

Lisää infoa ja tarkemmat piirin speksit löytyvät piirin datalehdestä alta.

Piirin datasheet: http://www.nxp.com/documents/data_sheet/74HC_HCT595.pdf

Rullaava teksti sekä demo

Alla kuva kytkennästä, sekä videopätkä LED-matriisinäytön toiminnasta.

matriisi_ja_siirtorekisteriKuva.JPG

Alla näkyvällä videolla nähdään koodin toiminta käytännössä.

Koodiin olen pyrkinyt kommentoimaan mitä tapahtuu missäkin kohtaa, mutta kaikkea (itsestään selvää) en ole kommentoinut. Mikäli kysymyksiä sataa palautelaariin, niin päivitellään tänne sivulle ongelmakohdat vastauksineen.

Koodin käytöstä...

Koodilla ei voi tulostaa ääkkösiä, mutta omia bittikarttoja voi tulostella käyttämällä luotuja funktioita. Bittikarttojen suunnitteluun voi käyttää esimerkiksi tällaista online -työkalua: http://blog.riyas.org/2013/12/online-led-matrix-font-generator-with.html

drawScrollingText(...) -funktiolla voidaan tulostaa tekstiä ja merkkien määrää on rajoitettu 30 merkkiin kerrallaan - tätä voi toki koodista muutella haluamakseen. Parametrina annetaan ensin teksti, joka halutaan näyttää ja sen jälkeen nopeus. Suurempi arvo tarkoittaa hitaammin liikkuvaa tekstiä ja pieni arvo tietenkin toisin päin.

updateDisplay() -funktiolla päivitetään näyttö vastaamaan muistia, tätä tarvitaan varsinkin silloin kun bittikartta on ladattu muistiin näytölle tulostusta varten. Samoin, jos jotakin kuvaa haluaa näyttää tietyn ajan, niin updateDisplay():ta täytyy kutsua.

loopImages(...) -funktiota käytetään silloin, kun halutaan näyttää useampi eri kuva peräkkäin. Parametrina annetaan byte-taulukko, missä kuvat sijaitsevat sekä viive, miten pitkään kutakin kuvaa näytetään.

drawBitmap(...) -funktiolla voidaan piirtää näytölle yksittäinen bittikartta. Parametrina annetaan näytettävä kuva ja arvo true. UpdateDisplay() -funktiota on kutsuttava tämän jälkeen, jotta kuva saadaan näkyviin.

blinkDisplay(...) vilkuttaa näyttöä halutun määrän (ensimmäinen parametri) halutulla nopeudella (toinen parametri).

displayMemoryReset() nollaa näytön.

setPixel(...) asettaa yksittäisen ledin joko päälle tai pois. Parametreina annetaan haluttu paikka X, Y sekä arvo true tai false. Koordinaatisto toimii siten että ensimmäisen rivin ensimmäinen LED on koordinaatiltaan x=0 ja y=0. Viimeinen LED puolestaan x=7 ja y=0. Myös tämän jälkeen on kutsuttava updateDisplay() funktiota.

shiftDisplayTo(...) puolestaan liikuttaa olemassa olevaa kuvaa johonkin suuntaan (ylös, alas, vasen, oikea). Funktio ei ole täydellinen, eli jos kuvaa liikutetaan niin näytön ulkopuolelle joutunut tieto tuhoutuu.

Voit ladata demon lähdekoodin kokonaisuudessaan tästä: _8x8LED_siirtorekisteri.zip.

void loop() {

  drawScrollingText("Terve Maailma! ",8);
  updateDisplay(80);
  
  blinkDisplay(2,50);  
  
  displayMemoryReset();
  
  drawScrolling(img3,10);
  
  // Juoksevat ledit
  demo1();
  
  // Näytetään putkeen kolme "kuvaa"
  loopImages(imageSet,3,100);

  // Vilkutetaan näyttöä
  drawBitmap(img3, true);
  updateDisplay(60);
  blinkDisplay(2,50);  
  displayMemoryReset();
  
  // Muodostetaan random pikseleitä
  for(int i = 0; i < 50; i++)
  {
    setPixel(random(7),random(7), true);
    updateDisplay(10);
  }
  
  // liikutetaan kuvaa
  // 1 = oikealle, 0 = vasemmalle, 2 = ylös, 3 = alas (ensimmäinen parametri)
  drawBitmap(img4, true);
  shiftDisplayTo(0,2); 
  updateDisplay(100);
  shiftDisplayTo(1,2); 
  updateDisplay(100);
  shiftDisplayTo(2,1); 
  updateDisplay(100);
  
  blinkDisplay(2,50);  

}

Tähän päättyy Arduino oppaan kymmenes osa.