Niet de meest geavanceerde LED kubus maar wel eentje die relatief eenvoudig te maken en te begrijpen is omdat er nauwelijk extra elektronica nodig is om de kubus aan te sturen met een Arduino. Geen moeilijke (seriele) protocollen dus maar gewoon digitale I/O pennen ‘hoog’ (= “1” = “true”) en ‘laag’ (= “0” = “false”) schakelen. En voor wie hem zelf wil bouwen; het elektrisch schema, de source code en zelfs een Fritzing PCB layout, ze zijn hier allemaal te downloaden.
De hardware
Maar eerst een kort stukje elektronica-theorie. Een LED geeft pas licht als je er in de juiste richting stroom doorheen laat lopen. In het schema rechts is een LED aangesloten op twee digitale I/O pennen van de Arduino; 12 en 2 (= arbitraire keuze). Wanneer we pin 12 ‘hoog’ schakelen en pin 2 ‘laag’ dan loopt de stroom in de juiste richting door de LED waardoor deze licht geeft. Bij elke andere combinatie van ‘hoog’ en ‘laag’ staat de LED uit. De weerstand van 220[Ω] dient ervoor om de LED-stroom te beperken tot ca 10[mA], voor de meeste LEDs een prima waarde.
Voor het aansturen van LEDs heeft een Arduino Uno maximaal 14 digitale I/O pennen maar let op: pennen 0 en 1 zijn al in gebruik voor de USB interface. De uitdaging is nu om met de 12 beschikbare I/O pennen zoveel mogelijk LEDjes te kunnen schakelen, liefst natuurlijk alle 3x3x3=27 van de LED kubus.
En met de nevenstaande schakeling lukt dat prima mits je accepteert dat er in software iets extra’s nodig is om leuke licht-patronen te kunnen maken, maar da’s bij LED aansturingen heel gebruikelijk (meer daarover later bij het bespreken van de software).
In ons ontwerp hebben we de kubus verdeeld in drie horizontale vlakken. Voor het gemak zijn de vlakken met verschillende kleuren in het schema getekend, al zul je in de praktijk natuurlijk allemaal dezelfde kleur LEDs kiezen. De I/O pennen 5 t/m 13 sturen elk een van de negen verticale kolommen van ieder drie LEDs aan. De resterende I/O pennen (2 t/m 4) worden gebruikt voor het aan-/uitschakelen van de drie horizontale vlakken. Dus, om 1 specifieke LED uit de kubus aan te kunnen zetten moet een specifieke kolom ‘hoog’ (=’1′) ingesteld worden en 1 specifiek vlak ‘laag’ (=’0′). En om te voorkomen dat andere LEDs ook gaan branden moeten alle overige kolommen ‘laag’ en alle overige vlakken ‘hoog’ gemaakt worden.
Bewust meerdere LEDjes tegelijkertijd laten branden kan natuurlijk ook. Bijvoorbeeld door meerdere kolommen hoog (=”1″) te maken. Straks zullen we hiervan in onze software bewust gebruik gaan maken. Maar omdat er in het uiterste geval per vlak 9 LEDjes tegelijkertijd aan kunnen staan kan de totale stroom per vlak oplopen tot zo’n 90[mA]. Een Arduino pen kan volgens specificaties max. 40[mA] aan. Vandaar dat er per vlak nog een kleine schakeltransistor (2N2222A of BC546B) nodig is, zie het elektrisch schema. Deze transistor heeft echter een ‘inverterende’ werking. Dwz, een vlak wordt ‘laag’ (=’0′) gemaakt door de betreffende I/O pen juist ‘hoog’ (=’1′) te maken. Dat lijkt even wat verwarrend maar het went snel :-).
Voor de liefhebbers is hier ook nog een PCB layout (let op: ongetest) om LED kubus als Arduino shield te kunnen bouwen. Het eerste LED vlak wordt rechtstreeks op de PCB gemonteerd. Voor het verbinden van de 2e en 3e LED vlakken met de bijbehorende schakeltransistoren zijn enkele soldeerpads voorzien.
Een uitleg over de montage is te vinden in een andere blog.
De software
Optimalisatie in de hardware gaat vaak gepaard met een extra inspanning in de software (en andersom). En omdat we in dit LED kubus ontwerp bezuinigd hebben op het aantal I/O pennen moeten we in de software nu dus iets extra’s doen om alle willekeurige LED patronen te kunnen blijven maken. Met het huidige hardware ontwerp is het bijvoorbeeld niet vanzelfsprekend om het LEDje-link-boven-achter samen met het LEDje-links-voor-onder aan te zetten terwijl alle andere LEDjes uit staan (ik leg dat verder niet uit, lijkt me een leuk zomeravond puzzeltje).
De oplossing (of work-around) heet “tijd-multiplexen”, dwz dat je om-en-om het ene LED-vlak en daarna het andere LED-vlak aan zet. En als je dat heel snel afwisselt lijkt het net alsof de LEDjes van de drie vlakken toch tegelijkertijd aan staan terwijl ze in werkelijkheid 66% van de tijd uit staan. NB: per LEDje is de effectieve lichtopbrengst dus ook teruggezakt tot slechts 33%!
Net als bij een TV moet de herhaalfrequentie minimaal zo’n 50[Hz] zijn voor een flickervrij beeld. Sneller mag natuurlijk ook maar dan zal de effectieve lichtopbrengst nog wat verder terugzakken omdat alle LEDjes tijdens het omschakelen ook heel even uit staan.
De flowchart hiernaast geeft weer hoe dat er in software uit ziet. In de hoofdlus (links) wordt telkens een LED patroon uit een tabel gelezen. Vervolgens wordt een aparte functie aangeroepen om de LEDs conform het huidige patroon aan en uit te zetten. Dat weergeven gebeurt per vlak apart, maar de herhaalfrequentie is zo hoog dat je niet merkt dat de vlakken om-en-om aan staan. Nadat het huidige patroon voldoende lang getoond is, wordt teruggegaan naar de hoofdlus waar een nieuw patroon uit de tabel opgehaald wordt, etc. En zodra alle patronen uit de tabel aan de beurt geweest zijn wordt weer gewoon vooraan begonnen.
Een LED-patroon is een reeks ‘1’-en en ‘0’-en die samen aangeven welke LEDs er tegelijkertijd aan moeten staan. In ons geval gebruiken we een “unsigned long” waarvan elk bitje 1 LED vertegenwoordigd. De 9 meest rechtse (LSB) bits vertegenwoordigen de LEDjes van vlak 1, de volgende 9 horen bij vlak 2 en de daarop volgende 9 bij vlak 3. Van de 32 beschikbare bitjes worden er om praktische redenen dus maar 27 gebruikt.
In de software (zie code hieronder) wordt per vlak beoordeeld (bitje=1?) welk LEDje moet branden en wordt de betreffende kolom (=’anode’) ‘hoog’ gemaakt. Als alle bitjes uit het vlak zijn beoordeeld wordt vlak 1 aangezet door de bijbehorende I/O pen (=’kathode’) ook ‘hoog’ te maken. Nadat de LEDjes een korte tijd (ca 10[msec]) aan zijn geweest worden ze weer uitgezet door alle kolommen en vlakken laag te maken. Daarna wordt hetzelfde gedaan voor vlak2 en vlak 3.
Tenslotte: klik hier om het volledige hard- en software-design te downloaden.
Wanneer je meer wilt…
Als zelfs een Arduino qua bouwvolume te groot is kun je een Teensy overwegen. In veel opzichten vergelijkbaar met de Arduino UNO maar veel compacter en ook iets goedkoper.
Wanneer het timemultiplexen ongewenst is omdat het de lichtopbrengst van je LED kubus te nadelig beïnvloed of wanneer je een grotere LED kubus wilt dan kun je niet meer volstaan met een Arduino Uno. Als eerste kun je een upgrade overwegen naar de Arduino MEGA. Deze heeft 54 digitale I/O pennen waarop de 27 LEDs rechtstreeks aangesloten kunnen worden. Ook de Teensy++ is het overwegen waard. De Teensy++ is qua functionaliteit vergelijkbaar met de Arduino MEGA maar is net als de gewone Teensy veel compacter.
Maar als je ook daarmee niet vooruit kunt, bijvoorbeeld omdat je een 4x4x4 of een RGB kubus wilt maken, dan ontkom je er niet aan om ook extra elektronica toe te voegen. Er zijn verschillende varianten denkbaar. In deze blog zal ik ze alleen kort beschrijven, wellicht kom ik er in een latere blog nog eens uitvoeriger op terug.
Dit is een low-cost serial-to-parallel shift-out register dat middels een seriële (SPI) interface communiceert met de Arduino. Door 2 I/O pennen van de Arduino op te offeren krijg je 8 output pennen terug. En het leuke is dat je deze shift registers kunt cascaderen. Dus zonder verlies van extra I/O pennen op de Arduino krijg je er per chipje dus telkens 8 output pennen bij.
Deze Texas Instruments chip beschikt over 16 PWM kanalen elk 120[mA] kunnen leveren bij Vcc-5[V]. Ideaal voor het aansturen van LEDs. De chip wordt aangestuurd middels een seriele interface en het leuke is dat er ook al een Arduino software library voor beschikbaar is. Dat scheelt dus een boel programmeren. Ook hardwarematig kun je jezelf werk besparen door gebruik te maken van de Sparkfun PWM shield of de TLC5940-breakout. Een kind kan de was doen.