Inhoudsopgave:

RGB LED-matrix: 5 stappen
RGB LED-matrix: 5 stappen

Video: RGB LED-matrix: 5 stappen

Video: RGB LED-matrix: 5 stappen
Video: Начало работы с QLC+ Управление цветомузыкой с компьютера. Как управлять светом. 2024, Juli-
Anonim
Image
Image
Hardware-ontwerp
Hardware-ontwerp

Zoek Instructable en je kunt veel LED-matrixprojecten vinden. Geen van hen was helemaal wat ik wilde, namelijk de interactie van hardware- en softwareontwerp onderzoeken om iets te produceren, en het eindproduct te produceren in een nette PCB met een stuurprogramma waarmee ik naar het "LED-scherm" kon tekenen met behulp van hoogwaardige constructies (bijv. een lijn tekenen in plaats van specifieke pixels in te stellen). Dit onderdeel was belangrijk voor mij, omdat veel van de LED-matrixstuurprogramma's kale botten zijn en niet veel bieden op het gebied van het programmatisch creëren van een afbeelding of animatie. Dit betekent niet dat je geen afbeeldingen en animaties kunt maken met de andere stuurprogramma's, alleen dat je meer repetitief werk van project tot project zou moeten doen.

Dus ging ik aan de slag om mijn visie te verwezenlijken. De eerste stap was het ontwerpen van de hardware. Dit was waarschijnlijk de meest uitdagende voor mij, aangezien mijn achtergrond meer software is. Nogmaals, er waren veel voorgebakken ontwerpen en ik heb ze zeker als inspiratie gebruikt, maar ik wilde leren door te doen, dus maakte ik een prototype van een 4x4-matrix op een breadboard. Ik heb veel geleerd door dat proces, omdat mijn eerste paar iteraties niet werkten. Maar ik deed het hardware-ontwerp dat werkte, waardoor ik een stuurprogramma kon ontwikkelen.

Ik koos de Arduino als mijn driverplatform omdat het overal verkrijgbaar is en veel referenties online heeft. Hoewel mijn loopbaanervaring me in staat stelde om een werkende versie van een driver te krijgen die soepeler was dan mijn hardware-inspanningen, waren er nog steeds genoeg iteraties terwijl ik de driverprestaties voor de ATMega-microcontroller optimaliseerde en een programmeer-API ontwikkelde die ik leuk vond.

Deze Instructuctable documenteert het ontwerp en enkele belangrijke lessen uit mijn project. Meer informatie over dit project is te vinden op mijn website hier, inclusief volledige kits die u kunt kopen om uw eigen RGB LED-matrix te bouwen.

Stap 1: Hardware-ontwerp

Het primaire doel van mijn hardware-ontwerp was om een reeks RGB-LED's te maken die ik kon programmeren, maar ik wilde ook niet veel geld uitgeven. De aanpak die ik koos, was om 74HC595-schuifregisters te gebruiken om de LED's te besturen. Om het aantal benodigde schuifregisters te minimaliseren, heb ik de RGB-LED's gerangschikt in een matrixlay-out waarbij de gemeenschappelijke anodes in rijen aan elkaar waren gebonden en de rode, groene en blauwe kathodedraden in kolommen aan elkaar waren gebonden. Voor de 4x4-matrix zag het schakelschema eruit als het bijgevoegde schakelschema.

Een ding dat je meteen opvalt, is dat, gezien het matrixcircuit, er enkele LED-verlichtingsconfiguraties zijn die niet kunnen worden gedaan met alle gewenste LED's tegelijkertijd aan. De matrix kan bijvoorbeeld niet tegelijkertijd twee LED's verlichten die diagonaal van elkaar zijn, omdat het voeden van zowel de rijen als de kolommen ervoor zorgt dat de twee tegenoverliggende LED's op de loodrechte diagonaal van de gewenste LED's gaan branden. Om dit te omzeilen, zullen we multiplexen gebruiken om door elke rij te scannen. Er zijn tal van bronnen op het web die de techniek van multiplexing behandelen, ik ga niet proberen ze hier te repliceren.

Omdat ik gewone anode-LED's gebruik, betekent dit dat de rijen positief vermogen leveren en dat de kolommen naar de grond zinken. Het goede nieuws is dat de 74HC595-schuifregisters zowel stroom kunnen opwekken als afnemen, maar het slechte nieuws is dat ze een limiet hebben op hoeveel stroom ze kunnen opwekken of laten zinken. Afzonderlijke pinnen van de 74HC595 hebben een maximale stroomafname van 70 mA, maar het is het beste om minder dan 20 mA te behouden. De afzonderlijke kleuren in onze RGB-leds hebben elk ongeveer 20 mA stroomafname. Dit betekent dat de 74HC595 niet direct een hele rij LED's kan voeden als ik ze allemaal wil inschakelen.

Dus in plaats van de rij rechtstreeks van stroom te voorzien, zal de 74HC595 in plaats daarvan een transistor aansturen voor elke rij, en de transistor zal de stroom die de rij van stroom voorziet in- of uitschakelen. Omdat het ontwerp gebruik maakt van gemeenschappelijke anode-LED's, zal de schakeltransistor PNP zijn. Als we een gewone kathode-LED zouden gebruiken, zou de schakeltransistor NPN zijn. Merk op dat bij het gebruik van een PNP-transistor om een rij aan te sturen, de instelling van het schuifregister om deze in te schakelen nu laag wordt omdat een PNP-transistor een negatieve spanning nodig heeft tussen de emitter en de basis om te worden ingeschakeld, waardoor positieve stroom in de rij.

Een ander ding om te overwegen is de gewenste bitlay-out van de schuifregisters. Dat wil zeggen, onder de schuifregisters, welke bits bepalen welke rijen of kolommen in de matrix. Het ontwerp waarmee ik heb verzonden, is waar het eerste bit, of "meest significante bit", dat naar de in serie geschakelde schuifregisters wordt gestuurd, de kolom met het rode element van de LED's bestuurt, het tweede bit het groene element van de eerste kolom bestuurt, het derde bit de eerste kolom bestuurt blauw element, de vierde bit bestuurt het rode element van de tweede kolom, … dit patroon wordt herhaald over de kolommen van links naar rechts. Vervolgens bestuurt het volgende verzonden bit de laatste of onderste rij, de volgende de voorlaatste rij, … dit wordt herhaald totdat het laatste verzonden bit, of "minst significante bit", de eerste of bovenste rij in de matrix bestuurt.

Ten slotte moest ik bepalen welke weerstanden ik zou gebruiken voor elk van de LED's in de RGB-LED. Hoewel je de standaardformule zou kunnen gebruiken die voorwaartse spanning en gewenste stroom combineert om de vereiste weerstand te berekenen, ontdekte ik dat het instellen van de stroom van elke LED op 20 milliampère resulteerde in een gebroken witte kleur wanneer alle rode, groene en blauwe LED's aan waren. Dus begon ik het te bekijken. Te veel rood in het wit betekende het verhogen van de weerstand ohm van de rode LED om de stroom te verminderen. Ik herhaalde het verwisselen van weerstanden van verschillende ohm totdat ik een combinatie vond die een witte kleur produceerde die volgens mij goed was. De uiteindelijke combinatie was 180 voor de rode LED, 220 Ω voor de groene LED en 100 voor de blauwe LED.

Stap 2: Hardwareconstructie - Breadboard

Hardwareconstructie - Breadboard
Hardwareconstructie - Breadboard
Hardwareconstructie - Breadboard
Hardwareconstructie - Breadboard

De eerste fase van de ijzerwarenbouwer was de breadboarding. Hier heb ik een 4x4 matrix gemaakt met de RGB LED's. Deze matrix zou 16 bits nodig hebben om te besturen, 12 voor de RGB-kolommen en 4 voor elke rij. Twee 74HC595 schuifregisters kunnen het allemaal aan. Ik heb eerst een circuit onderzocht en ontworpen waarvan ik dacht dat het zou werken, en bouwde het vervolgens op het breadboard.

Waarschijnlijk was de grootste uitdaging van het bouwen van het breadboard het beheer van alle draden. Ik pakte een voorgevormde draadset voor breadboards, maar toen was het een beetje onpraktisch. Een truc die ik nuttig vond, was om een "poort" te maken om verbinding te maken met het Arduino-bord. Dat wil zeggen, in plaats van de pinnen op de Arduino rechtstreeks aan te sluiten op de verschillende IC-pinnen op het breadboard, wijs een paar rijen op het breadboard aan als verbindingspunt voor de Arduino en verbind vervolgens de relevante ID-pinnen met die rijen. Voor dit project heb je slechts vijf verbindingen met de Arduino nodig: +5V, aarde, data, klok en vergrendeling.

Nadat de breadboard-build was voltooid, moest ik het testen. Echter, zonder een soort driver om de juiste signalen naar de schuifregisters te sturen, kon ik niet testen of de hardware layout werkte.

Stap 3: Ontwerp van stuurprogrammasoftware

Image
Image

Gezien mijn eigen loopbaanervaring met softwareontwikkeling, was dit het deel van het project waar ik waarschijnlijk het meest duidelijk over was. Ik heb veel van de andere op Arduino gebaseerde LED-matrixstuurprogramma's onderzocht. Hoewel er zeker goede stuurprogramma's beschikbaar zijn, had geen enkele het ontwerp dat ik wilde. Mijn ontwerpdoelen van de bestuurder waren:

  • Bied een API op hoog niveau om programmatisch afbeeldingen en animaties te kunnen maken. De meeste stuurprogramma's die ik zag, waren meer gefocust op hardgecodeerde afbeeldingen. Omdat ik van beroep een C++-programmeur ben, wilde ik ook een goed objectgeoriënteerd ontwerp gebruiken om de activiteiten van het tekenen naar de LED-matrix te implementeren en te beheren.
  • Gebruik een aanpak met dubbele buffer om de afbeelding op het scherm te beheren. Eén buffer is waar programmatisch in wordt getrokken, terwijl de andere de toestand van de matrixpixels op een bepaald moment vertegenwoordigt. Het voordeel van deze benadering is dat u niet verplicht bent om de volgende frame-update voor het scherm volledig te renderen tussen updatecycli van de multiplexing.
  • Gebruik PWM om meer dan de zeven primitieve kleuren die een RGB kan weergeven mogelijk te maken door eenvoudige combinaties van de rode, groene en blauwe elementen.
  • Schrijf het stuurprogramma zo dat het "gewoon zou werken" met RGB LED-matrices van verschillende grootte die mijn algemene matrixontwerpbenadering volgden. Merk op dat hoewel mijn hardware-ontwerp 74HC595-schuifregisters gebruikt, ik zou verwachten dat mijn stuurprogramma zou werken met elk aan/uit-mechanisme in de stijl van een schuifregister dat is opgesteld met een vergelijkbare bitlay-out als mijn hardware-ontwerp. Ik zou bijvoorbeeld verwachten dat mijn stuurprogramma zou werken met een hardwareontwerp dat DM13A-chips gebruikte om de kolommen te besturen en een 74HC595-chip om de rijen te besturen.

Als je direct naar de drivercode wilt kijken, kun je deze hier op GitHub vinden.

De eerste iteratie van mijn stuurprogramma was een beetje een leercurve over de mogelijkheden van het Arduino-platform. De meest voor de hand liggende beperking is het RAM, dat 2K bytes is voor de Arduino Uno en Nano. Het gebruik van C++-objecten in een dergelijk scenario wordt vaak afgeraden vanwege de geheugenoverhead van objecten. Ik had echter het gevoel dat als het goed werd gedaan, het voordeel van objecten in C ++ groter was dan hun kosten (in RAM).

De tweede grote uitdaging was uitzoeken hoe we de pulsbreedtemodulatie via de schuifregisters konden implementeren, zodat ik meer dan de zeven primitieve kleuren van de RGB-LED kon genereren. Na vele jaren op Linux-platforms te hebben geprogrammeerd, was ik gewend constructies zoals threads te gebruiken om processen te beheren die een consistente timing vereisen. De timing van het bijwerken van het schuifregister blijkt behoorlijk kritisch te zijn bij het maken van een driver voor een LED-matrix die multiplexing gebruikt. De reden hiervoor is dat, hoewel het multiplexen zo snel gebeurt dat uw ogen de individuele LED's niet kunnen zien aan en uit knipperen, uw akoestiek verschillen kan oppikken in de totale totale tijd dat een van de LED's aan is. Als de ene rij LED's constant langer brandt dan de andere, zal deze er tijdens het multiplexen helderder uitzien. Dit kan leiden tot ongelijkmatige helderheid in de matrix of periodieke strobing van de matrix als geheel (dit gebeurt wanneer de ene updatecyclus langer duurt dan de andere).

Omdat ik een consistent timingmechanisme nodig had om ervoor te zorgen dat de schuifregisterupdates toestemming waren, maar de Arduino formeel geen thread ondersteunt, moest ik mijn eigen threading-achtig mechanisme maken. Mijn eerste iteratie hiervan was om simpelweg een lustimer te maken die afhing van de Arduino-lus()-functie en een actie zou starten wanneer een bepaalde hoeveelheid tijd is verstreken sinds de laatste keer dat de actie werd geactiveerd. Dit is een vorm van "coöperatief multitasken". Klinkt goed, maar in de praktijk bleek dit inconsistent toen de vuursnelheid werd gemeten in microseconden. De reden hiervoor is dat als ik twee van deze looptimers aan had, een van hun acties vaak lang genoeg duurde om de tweede actie later dan gewenst te activeren.

Ik ontdekte dat de oplossing voor dit probleem is om het ingebouwde klokonderbrekingsmechanisme van de Arduino te gebruiken. Met dit mechanisme kunt u een klein stukje code uitvoeren met zeer consistente tussenpozen. Dus ontwierp ik de drivercode rond het ontwerpelement van het gebruik van een klokonderbreking om de code te activeren voor het verzenden van de matrixschuifregisters bij de volgende update in de multiplexcyclus. Om dit te doen en updates van het schermbeeld mogelijk te maken om een actieve dump naar de schuifregisters niet te verstoren (iets dat we een "race-conditie" zouden noemen), gebruikte ik een benadering van het hebben van dubbele buffers voor de schuifregisterbits, één om te schrijven en een om te lezen. Wanneer de gebruiker de matrixafbeelding bijwerkt, vinden deze bewerkingen plaats in de schrijfbuffer. Wanneer deze bewerkingen zijn voltooid, worden interrupts tijdelijk onderbroken (dit betekent dat de klokinterrupt niet kan worden geactiveerd) en de schrijfbuffer wordt verwisseld met de vorige leesbuffer en het is niet de nieuwe leesbuffer, waarna de interpretaties opnieuw worden ingeschakeld. Dan, wanneer de klokonderbreking afgaat, wat aangeeft dat het tijd is om de volgende bitconfiguratie naar de schuifregisters te sturen, wordt die informatie uit de huidige leesbuffer gelezen. Op deze manier wordt er nooit geschreven naar een buffer waaruit momenteel wordt gelezen tijdens een klokinterrupt, wat de informatie die naar de schuifregisters wordt verzonden, zou kunnen beschadigen.

Het ontwerpen van de rest van de driver was een relatief eenvoudig geval van objectgeoriënteerd ontwerpen. Ik heb bijvoorbeeld een object gemaakt om de bitafbeelding van het schuifregister te beheren voor een bepaalde schermstatus. Door de code met betrekking tot het bitbeeldbeheer in te kapselen, was het creëren van de bovengenoemde benadering met dubbele buffers zelf een eenvoudige oefening. Maar ik heb dit Instructable niet geschreven om de deugden van objectgeoriënteerd ontwerp te prijzen. Andere ontwerpelementen zijn het concept van een Glyph en een RGB-afbeelding. Een Glyph is een basisbeeldconstructie die geen aangeboren kleurinformatie heeft. Je kunt het zien als een zwart-wit afbeelding. Wanneer de Glyph naar het LED-scherm wordt getekend, wordt kleurinformatie gegeven om aan te geven hoe de "witte" pixels gekleurd moeten worden. Een RGB-afbeelding is een afbeelding waarbij elke pixel zijn eigen kleurinformatie heeft.

Ik moedig je aan om de Arduino-schetsvoorbeelden te bekijken en de documentatie van de driverheader te bekijken om vertrouwd te raken met het gebruik van de driver om afbeeldingen en animaties te maken op een RGB LED-matrix.

Stap 4: LED-ghosting

LED Ghosting
LED Ghosting
LED Ghosting
LED Ghosting

In een LED-matrix is "ghosting" het fenomeen van een LED in de matrix die oplicht wanneer dit niet gewenst is, meestal een zeer verlaagd niveau. Mijn oorspronkelijke hardware-ontwerp was gevoelig voor ghosting, met name in de laatste rij. De oorzaak hiervan is te wijten aan twee dingen: transistors schakelen niet onmiddellijk uit en parasitaire capaciteit in de RGB-leds.

Terwijl we door de rijen scannen, wordt de vorige rij in de scancyclus nog steeds gedeeltelijk van stroom voorzien wanneer de volgende rij wordt ingeschakeld, vanwege het feit dat transistors niet onmiddellijk worden uitgeschakeld. Als een bepaalde kolom die uit was in de vorige rij opnieuw wordt ingeschakeld wanneer de nieuwe rij wordt gevoed, zal de LED van die kolom in de vorige rij even oplichten terwijl de schakeltransistor van die vorige rij nog bezig is met draaien uit. Wat ervoor zorgt dat de transistor een merkbare hoeveelheid tijd nodig heeft om uit te schakelen, is verzadiging in de basis van de transistor. Dit zorgt ervoor dat het collector-emitterpad van de transistor blijft geleiden wanneer de stroom van de basis wordt verwijderd, tenminste totdat de verzadiging verdwijnt. Aangezien onze multiplexing-updatecyclus ervoor zorgt dat rijen opzettelijk aan staan gedurende een tijdsperiode gemeten in microseconden, kan de hoeveelheid tijd dat de verzadigde transistor van de vorige rij geleidend blijft een merkbare fractie daarvan zijn. Als gevolg hiervan kan uw oog die zeer korte tijd waarnemen dat de LED van de vorige rij is ingeschakeld.

Om het verzadigingsprobleem van de transistor op te lossen, kan een Schottky-diode aan de transistor tussen de basis en de collector worden toegevoegd om een beetje tegenstroom naar de basis te veroorzaken wanneer de transistor aan staat, waardoor wordt voorkomen dat de transistor verzadigd raakt. Dit zorgt er op zijn beurt voor dat de transistor sneller uitschakelt wanneer de stroom van de basis wordt verwijderd. Zie dit artikel voor een uitgebreide uitleg van dit effect. Zoals je kunt zien op de afbeelding in dit gedeelte, is de ghosting zonder de diode behoorlijk merkbaar, maar door de diode voor elke rij aan het circuit toe te voegen, wordt de ghosting aanzienlijk verwijderd.

RGB-LED's zijn gevoelig voor een ander fenomeen dat parasitaire capaciteit wordt genoemd. De hoofdoorzaak hiervan is het feit dat elk van de drie kleuren-LED's in de RGB LED-eenheid elk verschillende voorwaartse spanningen hebben. Dit verschil in voorwaartse spanningen kan het effect van elektrische capaciteit tussen elk van de individuele LED-kleuren veroorzaken. Aangezien er een elektrische lading wordt opgebouwd in de LED-eenheid wanneer deze wordt ingeschakeld, moet de parasitaire capaciteit worden ontladen wanneer de stroom wordt verwijderd. Als die LED-kolom anders aan is om een andere rij van stroom te voorzien, zal de parasitaire lading door die LED-kolom ontladen en deze kort laten gloeien. Dit effect wordt mooi uitgelegd in dit artikel. De oplossing is om een ontladingspad voor deze parasitaire lading toe te voegen, anders dan via de LED zelf, en de LED vervolgens de tijd te geven om te ontladen voordat de kolom weer wordt gevoed. In mijn hardware-ontwerp wordt dit bereikt door een weerstand toe te voegen aan de voedingslijn van elke rij die de kracht met de aarde verbindt. Dit zorgt ervoor dat er meer stroom wordt getrokken als de rij wordt gevoed, maar biedt wel een ontladingspad voor de parasitaire capaciteit wanneer de rij niet wordt gevoed.

Het is echter vermeldenswaard dat ik in de praktijk het effect van parasitaire capaciteit nauwelijks merkbaar vind (als je ernaar zoekt, kun je het vinden), en dus beschouw ik het toevoegen van deze extra weerstand als optioneel. Het effect van de vertragingstijd voor verzadigde transistors is veel sterker en merkbaarder. Desalniettemin, als u de drie foto's in dit gedeelte inspecteert, kunt u zien dat de weerstanden alle ghosting die nog steeds optreedt na die van de langzame uitschakeltijden van de transistor volledig verwijderen.

Stap 5: Eindproductie en volgende stappen

Image
Image

De laatste fase van dit project was voor mij om een printplaat (PCB) te maken. Ik heb het open source programma Fritzing gebruikt om mijn PCB te ontwerpen. Hoewel er veel repetitieve taken moesten worden uitgevoerd om 100 LED's op een 10x10-bord te plaatsen, vond ik deze fase van het project eigenlijk vreemd bevredigend. Uitzoeken hoe elk elektrisch pad zou worden aangelegd, was als een puzzel, en het oplossen van die puzzel zorgde voor een gevoel van voldoening. Aangezien ik niet ben ingesteld om de printplaten te vervaardigen, heb ik een van de vele online bronnen gebruikt die kleine oplagen van aangepaste PCB's maken. Het aan elkaar solderen van de onderdelen was vrij eenvoudig, omdat mijn ontwerp alle doorgaande gaten gebruikte.

Op het moment dat ik dit Instructable schrijf, heb ik de volgende plannen voor mijn mijn RGB LED Matrix-projecten:

  1. Ga door met het verbeteren van het stuurprogramma op de API-laag om meer functionaliteit op hoog niveau voor de programmeur mogelijk te maken, met name scrollen met tekst.
  2. Maak grotere matrixontwerpen, zoals 16x16 of zelfs 16x32.
  3. Ontdek het gebruik van MOSFET's in plaats van BJT's voor het schakelen tussen rijen en stroom
  4. Verken het gebruik van DM13As-stuurprogramma's met constante stroom in plaats van 74HC595's voor het schakelen van kolommen
  5. Maak stuurprogramma's voor andere microbesturingsplatforms, zoals de Teensy, ODROID C2 of Raspberry Pi.

Merk op dat zowel het hardware-ontwerp als het stuurprogramma zijn vrijgegeven onder de GPL v3 open source-licentie op deze GitHub-repository. Bovendien, hoewel de PCB-fabrikanten "kleine oplagen" van mijn PCB-ontwerp maken, krijg ik nog steeds veel meer dan ik persoonlijk nodig heb. Dus ik verkoop volledige kits voor mijn verschillende RGB LED-matrixontwerpen (PCB en alle onderdelen inbegrepen) van mijn website hier.

Aanbevolen: