Led-matriisi 8 x 8 - projekti
Nyt kuvattavassa projektissa rakennetaan 8 x 8 led-matriisi ja sille ohjaus Arduinolla. Matriisista tulee melko suuri (80 x 80 cm2), mutta ohjeita soveltamalla on toki mahdollista toteuttaa pienempi (tai suurempi) matriisi.
Projektin ohjeet karttuvat projektin edistymisen mukaan.
Huom. Kuvista saa esille suuremman version klikkaamalla kuvaa.
Aloitus - matriisin runko
Teen matriisin pohjan/rungon 2 mm paksusta muovilevystä (polykarbonaattilevy, muukin käy). Eikä levyn tarvitse olla läpinäkyvä; riippuu matriisin käyttötavasta, onko läpinäkyvyydestä hyötyä. Jos sitä ei kaipaa niin pohjalevyksi sopii vaikka tukeva pahvi tai ohut vaneri/kovalevy.
Sahaan levyn 80 cm x 80 cm kokoiseksi (alkujaan 100 x 100). Ostin levyn Motonetista. Levyn reunoihin kiinnitän myöhemmin 3 mm ruuveilla alumiiniset T-listat antamaan tukea ja suojaamaan ledejä sekä johdotuksia. Ostin T-listat Bauhausista.
Matriisin voisi toteuttaa myös kevyempänä siten, että tekisi vain kehikon puu- tai alumiinirimoista ja laittaisi siihen vaaka- ja pystyjohtimet (kuten edelläkin kuvatussa toteutuksessa) ja sitten kiinnittäisi ledit johtimien risteyskohtiin. Muilta osin toteutus olisi tässä jäljempänä kuvatun kaltainen.
Ledien paikat
Ennen reunalistojen kiinnittämistä merkkaan levyyn ledien paikat ja poraan tarvittavat reiät ledien johdoille. Asennan ledit 10 cm päähän toisistaan. Siten äärimmäisten ledien etäisyys on 70 cm, ja kun levyn leveys on 80 cm, niin laitimmaiset ledit tulevat 5 cm päähän levyn reunoista. Levyn päällä on suojamuovi, johon voi huoletta merkitä ledien paikat.
Seuraavaksi poraan merkittyihin kohtiin reiät ledien johtoja varten. Käytän 1 mm tai 1,5 mm terää. Poraamisen helpottamiseksi teen alumiinilistan pätkästä sapluunan, johon poraan kaksi reikää ledin johtimia vastaavasti. Poraan reiät 45 asteen kulmaan kuvan mukaisesti, mikä helpottaa johdotusta myöhemmin (sen sijaan että reiät olisivat samassa pysty- tai vaakalinjassa).
Ledien kiinnitys
Leikkaan (sahaan) reikälevystä pieniä kahden reiän käsittäviä palasia, yhden kutakin lediä varten, siis 64 kpl. Reikälevyn pitää olla sellaista, missä reikien välillä ei ole kontaktia. Reikälevyn olen aikoinaan ostanut Kouluelektroniikasta kuten myös tässä projektissa käyttämäni 5 mm perusledit. Reikälevyn palasen avulla juotan ledin paikalleen. Samalla palanen eristää juotoskohdan sen verran muovilevyn pinnasta, ettei juotoksen lämpö vahingoita levyä. Kiinnitän kaikki ledit näin juottamalla muovilevyyn.
HUOM. Ledit pitää asettaa niin, että niiden anodit (plus-johdot) ovat kaikki samaan suuntaan. Anodi on yleensä johtimista se pitempi. Katso kuva. Varmuuden saa kokeilemalla vaikka 3 voltin paristolla tai muulla sopivalla virtalähteellä.
Ledin voisi kiinnittää levyyn myös vaikka niin, että poraisi levyyn ledin kokoisen reiän (tässä tapauksessa siis 5 mm reiän) ja kiinnittäisi ledin siihen. Tällöin ledi pitäisi luultavasti liimata kiinni, jotta ledi pysyisi varmasti paikallaan, ja silloin sen vaihtaminen mahdollisessa rikkoutumistilanteessa olisi hankalaa. Lisäksi ledi olisi osittain levyn sisällä, jolloin ledin valo leviäisi jossain määrin koko levyn alueelle.
Kun ledi on juotettu paikalleen niin ennen seuraavaa vaihetta on hyvä varmistaa, että ledi toimii. Tämä käy helposti vaikka 3 V:n paristolla. Tietysti myös jo ennen juottamista on hyvä varmistaa, että ledi on ehjä.
Muutama sana ledeistä. Ledi on puolijohde, joka säteilee valoa kun siihen kytketään jännite. Jännitteen napaisuudella on väliä, ts. pariston tmv. virtalähteen plus-napa pitää kytkeä ledin anodiin ja miinus-napa ledin katodiin, jotta ledi valaisisi. Toisin päin ledi pysyy pimeänä (mutta ei vahingoidu). Tavanomaisen ledin ns. kynnysjännite on yleensä hieman alla 3 V, ja 3 V:lla ledi on jo varsin kirkas. Ledi kestää melko hyvin ylijännitettä kunhan ylijännite on lyhytaikainen. Tätä ominaisuutta hyödynämme tässä projektissa. Siitä lähemmin Arduino-osuudessa. Liian suuri tai liian kauan kestävä ylijännite polttaa ledin. Tässä projektissa käytämme halkaisijaltaan 5 mm ledejä, väriltään punaisia. Niillä saa melko hyvän kirkkauden kohtuullisella virralla. Muita hyvän hyötysuhteen ledejä ovat mm. sininen ja valkoinen.
Ledien johdotus
Kun yhden vaakarivin kaikki ledit on juotettu kiinni, niin seuraavaksi katkaisen rivin kaikkien ledien anodijohtimet aivan lyhyiksi ja juotan niihin ledit yhdistävän kuparijohdon. Johto voi olla ilman eristystä ja mielellään suht. ohut, jolloin se ei erotu turhan selvästi. Katso kuva, Toimin samalla tavalla kaikkien kahdeksan vaakarivien kanssa.
Seuraavaksi teen saman pystyriville. Katkaisen pystyrivin ledien katodijohtimet n. 0,5 - 1 cm pituisiksi ja yhdistän saman pystyrivin ledien katodit toisiinsa kuparijohtimella. Pitää olla tarkkana, että anodi- ja katodijohtimet eivät kosketa missään kohtaa toisiinsa. Katodijohtimeen voi laittaa pienen eristepätkän varmistamaan tätä. Katso kuva. Toistan tämän jokaisen kahdeksan pystyrivin kanssa. Oheinen kuva esittää matriisia kun nämä juotostyöt on tehty. Olen tässä vaiheessa myös kiinnittänyt levyyn reunalistat (T-listat).
Nyt on myös hyvä hetki tarkistaa, että juotokset ovat oikein ja että ledit ovat kunnossa. Sitä varten kiinnitetään pariston plus-napa vuorollaan kuhunkin vaakariviin ja pariston miinus-napa kuhunkin pystyriviin. Rivien leikkauskohdassa olevan ledin (ja vain sen) tulee syttyä. Mahdolliset viat on syytä korjata ennen jatkamista.
Arduino-liitos
Tulen käyttämään matriisin ledien ohjaukseen Arduino Uno -mikrokontrolleria (kuva). Unossa on periatteessa 20 output-liitäntää, joilla voi ohjata (sytyttää/sammuttaa) esim. juuri ledejä. Matriisissamme on 64 lediä, joten jokaiselle ledille ei riitä omaa ohjaussignaalia. Siksi aiemmin tehtiin johdotus niin, että kahdella signaalilla voidaan ohjata aina kahdeksaa lediä yhtäaikaa, joten tarvitsemme yhteensä 16 ohjaussignaalia. Tämä onnistuisi Unolla hyvin, mutta silloin tarvittaisiin 18 johdinta matriisin ja Unon välille (16 ohjausignaalia sekä plus- ja minus-jännitteet). Haluamme kuitenkin minimoida matriisin ja Arduinon välisten johtimien määrän, ja siksi käytämme shift register -nimisiä komponetteja Arduinon ja matriisin välillä. Niiden ansiosta 16 signaalia saadaan supistettua kolmeksi signaaliksi eli tarvitaan yhteensä vain viisi johdinta. Palaamme shift register -komponenttien toimintaan tarkemmin myöhemmin, ja tässä vaiheessa vain valmistamme tarvittavan piirilevyn komponetteineen.
Oikealla olevat viisi johdinta liitetään Arduinoon: +5V Arduinon +5V-liitäntään, gnd (ground, maa, 0V) Arduinom gnd:hen, D (data), L (latch) ja C (clock) esim. Arduinon portteihin 2, 3 ja 4. Led-matriisin vaakariveiltä (rows) tulevat johtimet kytketään liitäntöihin r0-r7 ja pystyriveiltä ('sarakkeilta', columns) tulevat liitäntöihin c0-c7.
Lyhyesti siirtorekisterin (shift register) toiminnasta. Tässä käytettävät siirtorekisterit ovat tyyppiä 74HC595. Tämä mikropiiri pystyy tallettamaan kahdeksan tilatietoa, bittiä. Kun kellosignaali (clock, liityntä C) muuttuu nollasta +5V:iin niin dataliitynnän (D, data) arvo kopioituu siirtorekisterin ensimmäiseen talletuspaikkaan. Samalla siinä ennestään ollut tieto siirtyy rekisterin toiseen talletuspaikkaan, jossa ollut tieto siirtyy kolmanteen talletuspaikkaan jne. Tästä nimitys siirtorekisteri. Kahdeksalla kellopulssilla voidaan näin siirtää kahdeksan bitin tiedot rekisteriin.
Bittien tiedot ovat nyt rekisterin sisällä mutta ne eivät vielä 'näy' ulospäin. Bittien uudet arvot eli tilat saadaan näkymään mikropiirin ulostuloissa kun L-liitäntä (latch) muuttuu 0V:sta +5V.iin. Varsinaisten siirtorekisterien ja ulostulojen välillä on siis tavallaan muistipaikka, johon siirtorekisterin arvo pitää vielä kopioida L-signaalilla, jotta arvo näkyisi ulostuloliitännässä. Samalla tämä tieto ei muutu kun rekisterin sisältö muuttuu. Vasta latch-signaalin muutos aiheuttaa uusien tilatietojen näkymisen ulostuloliitännöissä.
Tässä projektissa käytämme kahta siirtorekisteriä kytkettynä sarjaan niin, että ensimmäisen rekisterin viimeisen bitin tieto on liitetty toisen rekisterin data-tuloon. Kumpikin rekisteri saa samat kello- ja latch-signaalit. Näin voimme 16 kellosignaalilla ladata rekistereihin 16 bittiä (tilatietoa). Arduinoon tehtävä ohjelma hoitaa signaalien asettamiset. Palaamme siihen myöhemmin.
Seuraava kuva näyttää matriisin ja ohjaimen välisen liitännän, ja sitä seuraava kuva esittää kokonaisuuden, jossa Arduino on liitetty ohjaimeen viidellä johtimella. Lopuksi näytetään vielä video toimivasta järjestelmästä. Seuraavassa kappaleessa käsittelemme sitten Arduinon ohjelmointia.
Arduino-ohjelma
Tässä osiossa tarkastellaan tarvittavaa Arduino-ohjelmaa. Arduinoa ohjelmoidaan C:n kaltaisella ohjelmointikielellä. Ohjelmointia varten PC:lle pitää asentaa Arduinon kehitysympäristö. Sellainen voi ladata ilmaiseksi osoitteesta https://www.arduino.cc/ ja sieltä kohdasta Software. Tätä kirjoitettaessa uusin versio on nimeltään Arduino IDE 1.8.16. Tässä ohjeessa ei ole mahdollista käsitellä yksityiskohtaisesti Arduinon ohjelmointia, mutta tuosta em. sivustosta löytyy yllin kyllin opastusta.
Kun kehitysympäristö on asennettu, niin Arduino liitetään PC:hen usb-portin kautta. Arduino 'näkyy' PC:lle COM-porttina (sarjaliikenneporttina). Kun kehitysympäristön käynnistää ja valitsee sen valikosta kohdan Tools, niin näkee, mitä COM-portteja PC tuntee. Niistä pitää valita se, joka vastaa Arduinoa (yleensä joku muu kuin COM1). Saman Tools-valikon alta valitaan se Arduino-malli, joka on käytössä. Nämä ohjeet koskevat mallia Arduino Uno, mutta toki ohjeet pätevät suurimmalle osalle muitakin malleja.
Kun kehitysympäristö käynnistetään, niin aukeaa 'tyhjä' ohjelma, johon voi alkaa rakentaa (koodata) omaa ohjelmaa. Arduino-ohjelma muodostuu kahdesta funktiosta: setup() ja loop(). Kutsumme tässä niitä funktioiksi, yhtä hyvin voisi käyttää termiä aliohjelma tai metodi. Funktiota setup() kutsutaan, kun Arduinoon kytketään virta. Se siis suoritetaan vain kerran ohjelman aluksi. Tyypillisesti siinä asetetaan alkuarvoja, esim. määritellään, ovatko Arduinon portin (pin) input- vai output-tyyppisiä. Input-portin tilaa voidaan tutkia (onko se HIGH eli +5V vaiko LOW eli 0V), kun taas output-portin tilaksi voidaan asettaa joko HIGH (+5V) tai LOW (0V). Portin tyyppi asetetaan komennolla pinMode(pin, tila), missä pin = portin numero (0-19) ja tila = INPUT tai OUTPUT. Tässä projektissa käytämme kolmea OUTPUT-tilassa olevaa porttia, nimittäin portteja 2, 3 ja 4.
Funktiota loop() kutsutaan setup()-funktion jälkeen ja siinä pyöritään luupissa, ts, siinä oleva koodi suoritetaan ja sen jälkeeen aloitetaan saman koodin suoritus alusta, ja näin jatketaan loputtomasti, ellei koodissa tehdä jotain, mikä lopettaa suorituksen. Funktiossa loop() siis 'luupataan' ikuisesti. Varsinainen Arduino-toiminta siis tapahtuu loop()-funktiossa.
Aivan ohjelman alussa (ennen setup()-funktiota) tyypillisesti määritellään tarvittavat muuttujat ja vakiodatat. Ne on oltava määriteltyinä ennen kuin koodissa voidaan niihin viitata. Esim. tässä määrittelemme käytettävät portit seuraavasti: int latchPin = 2; int clockPin = 3; int dataPin = 4; minkä jälkeen voimme koodissa käyttää noita nimiä, kun haluamme viitata ao. prttiin, esim. asettaa portin output-tilaan: pinMode(latchPin, OUTPUT); tai laittaa portin tilaksi HIGH (+5V): digitalWrite(dataPin, HIGH);
Arduinon erikoiskomentojen (funktioiden) pinMode() ja digitalWrite() lisäksi tarvitsemme vain yhden muun Arduino-spesifisen komennon (funktion), nimittäin shiftOut(dataPin, clockPin, bitOrder, value), jolla ohjaamme shift-rekisterin toimintaa. Parametrit dataPin ja clockPin vastaavat aiemmin määrittelemiämme muuttujia, parametri bitOrder kertoo, missä järjestyksessä bitit siirretään muuttujasta value, joka siis sisältää datan, joka halutaan tallettaa shift-rekisteriin. Data eli muuttujan value arvot (bitit) näkyvät sitten shift-rekisterin porteissa, kun annamme vielä komennon digitalWrite(latchPin, HIGH);. Jokseenkin kaikki muu koodi ohjelmassamme on ohjelmointikieli C:n peruskomentojen kaltaista.
Arduino-ohjelman tiedostotyyppi on .ino, siis ohjelman nimi on esim. EkaKokeilu.ino, ja ohjelma pitää tallettaa
saman nimiseen kansioon kuin mikä on ohjelman nimi (toki kansion nimi ilman .ino-tarkennetta). Viereinen kuva esittää kehitysympäristöä
ja 'tyhjää' ohjelmaa. Ylhäällä äärimmäisenä vasemalla on 'väkänen', jota klikkaamalla tehty ohjelma käännetään ja
mahdollisista virheistä raportoidaan. Sen vieressä oikealla on 'nuoli', jota klikkaamalla ohjelma käännetään ja jos
virheetön niin ohjelma ladataan Arduinoon, jossa sen suoritus käynnistyy automaattisesti, ensin siis setup()-funktio ja
sitten loop()-funktio loputtomasti.
Ledien ohjaus
Ledit (64 kpl) on siis kytketty matriisiksi. Jokaisella vaakarivillä sen kahdeksan ledin anodit (plus-johtimet) on juotettu kiinni samaan vaakajohtimeen. Vastaavasti jokaisen pystysarakkeen kahdeksan ledin katodit (miinus-johtimet) on juotettu kiinni samaan pystyjohtimeen. Kun kytkemme esim. ylimmän rivin vaakajohtimeen plus-jännitteen ja äärimmäisenä oikealla (matriisin edestä katsottuma) olevaan pystyjohtimeen miinus-jännitteen (tai oikeammin nollajännitteen), niin johtimien risteyskohdassa eli oikeassa yläkulmassa olevan ledin johtimien välille syntyy jännite-ero, ja kun jännite-ero on riittävä (n. 3V), niin ledi alkaa tuottaa valoa. Näin käymme läpi vuorollaan kunkin vaakarivin (row), siis vuorollaan kuhunkin vaakariviin ohjataan plus-jännite. Samalla pystyriveihin eli sarakkeisiin (column) laitetaan nollajännite niiden ledin kohdalle, joiden halutaan tuottavan valoa, ja plus-jännite niiden ledien kohdalle, joiden halutaan pysyvän pimeinä. Kun ledin anodissa ja katodissa on molemmissa sama plus-jännite, niin ledin johtimien välillä ei ole jännite-eroa, jolloin ledi pysyy pimeänä. Halutut plus- ja nollajännitteet saamme shift-rekisterien porteista. Ensimmäisen shift-rekisterin kahdeksan porttia vastaavat kahdeksaa vaakariviä ja toisen shift-rekisterin kahdeksan porttia vastaavat kahdeksaa pystysaraketta. Shift-rekisterien porttien tilat asetetaan aiemmin mainitulla shiftOut(dataPin, clockPin, bitOrder, value) -funktiolla.
Seuraavaksi tarkastelemme joitakin keskeisiä toteutukseen kuuluvia itse koodattuja funktioita. Aloitetaan funktiosta void ShowCurPic(int d). Taulukko byte curPic[8] sisältää tiedot näytettävästä kuviosta (current picture). Se on siis kahdeksan tavun (byte) kokoinen taulukko. Kunkin tavun kahdeksan bittiä vastaavat yhden vaakarivin ledien tiloja. Kun bitti on 1, niin ledin halutaan tuottavan valoa, ja vastaavasti nolla-bitti tarkoittaa pimeää lediä. Yhden tavun bitit vastaavat siis vaakarivin ledejä, ja kukin tavu vastaa ao. pystysaraketta. Funktio void ShowCurPic(int d) näyttää siis taulukon curPic[] sisällön sytyttämällä ne ledit, joiden kohdalla bitin arvo on 1. Parametri int d kertoo, kuinka kauan kuvio näytetään (millisekuntteina). Kuhunkin riviin kytketään vuorollaan plus-jännite 1000 mikrosekunnin ajaksi. Siten kukin valoa tuottava ledi saa virtaa vain 1/8 kokonaisajasta, mutta kun jännite-ero ledin johtimien yli on +5V eli ylijännitettä, niin ledi valaisee riittävän kirkkaasti. Muistammehan, että ledi sietää ylijännitettä kunhan se ei vaikuta liian kauan. Funktion ShowCurPic() sisällä 'pyöritään' niin kauan että d-millisekunttia on kulunut.
Funktiolla ClearCurPic() nollataan taulukko curPic[]. Funktiolla void LoadCurPic(byte *p) ladataan taulukkoon curPic[] kuvio (kahdeksan tavua) pointterin p osoittamasta paikasta.
Funktioilla ScrollInCurPic(), ScrollOutCurPic() ja ScrollInOutCurPic() näytetään taulukon curPic[] sisältö vaiheittain oikealta vasemmalle niin, että esim. funktion ScrollInCurPic() tapauksessa kuvio tulee näkyviin asteittain, yksi pystyrivi kerrallaan. Vastaavasti funktio ScrollOutCurPic() poistaa kuvion pystyrivi kerrallaan, ja funktio ScrollInOutCurPic() tekee molemmat asiat. Parametri d1 kertoo vaiheiden välin (millisekunttia) ja d2 kertoo, kuinka kauan 'valmista' kuvaa näytetään (millisekunttia).
Funktio void ShowText(String s, int d1, int d2) näyttää merkkijonon (tekstin). Merkkijono annetaan parametrina s, ja parametri d1 kertoo, kuinka kauan yhtä merkkiä näytetään, ja parametri d2 kertoo, kuinka pitkä tauko pidetään merkkien välillä (molemmat millisekuntteina). Ohjelman alussa on määritelty taulukkoon byte data[] ohjeman tuntemat merkit eli niiden bittiesitykset (kukin merkki kahdeksan tavua). Kirjaimista ohjelma tuntee vain isot kirjaimet. Ääkköset ja muut erikoismerkit pitää esittää parametrissa s muodossa ^nn, missä nn on ao. merkin järjestysnumero data[]-taulukossa; esim. Ä = ^60.
Funktio void FullScrollText(String s, int d1, int d2) tekee saman mutta käyttää em. vieritystä merkkien tuomiseen ja viemiseen.
Lisäksi on koodattu joitakin funktioita erikoisesityksiä varten, mm. void HeartBeat(int d1, int d2), joka esittää sydämmenlyöntejä, void ShowSpiral(int s, int d, int l), joka piirtää kasvavan spiraalin, ja void LedTest(int d1, int d2), joka sytyttää yksitellen kunkin ledin.
Koko Arduino-ohjelma löytyy täältä: Arduino-ohjelma.