Hallo! Etwas AVR-Hardcore-Assembler gefällig? Vor ein paar Tagen habe ich meine LED-Stripes bekommen, bestückt mit den WS2812-LEDs. Ich habe mich daraufhin am Wochenende mal aufgerafft eine AVR-Routine zur Ansteuerung zu schreiben, die möglichst exakt die Vorgaben des Datenblatts einhält und dennoch flexibel ist. Die Vorgaben des Datenblatts von Worldsemi habe ich wie folgt umgesetzt: * Jede Bitübertragung dauert exakt 1.25 Mikrosekunden. Das entspricht 20 Taktzyklen bei 16 MHz Takt. * Ein "1"-Bit teilt sich auf in 625 us "1"-Pegel (10 Zyklen) und 625 us "0"-Pegel (10 Zyklen) * Ein "0"-Bit teilt sich auf in 375 us "1"-Pegel (6 Zyklen) und 875 us "0"-Pegel (14 Zyklen) Die Vorteile meiner Routine: * Sehr kurz (nur 29 Zeilen für beliebig viele LEDs) * Reines Bit-Banging, ohne Hardwareunterstützung (wie SPI, UART, etc.) * Jeder beliebige I/O-Pin verwendbar Die Bitzeit von 1.25 Mikrosekunden ist schon sehr anspruchsvoll für einen 16 MHz AVR. Dies ist so ohne Tricks nicht lösbar ... Mein angehängtes Beispielprogramm ist für einen Atmel 90CAN128 geschrieben, weil der gerade greifbar war. Andere AVRs gehen natürlich auch. Voraussetzung sind: 16 MHz Takt und gleiche Ausführungszeiten der Befehle. "Reduced Core TinyAVR" gehen nicht, da muss nachgearbeitet werden, da z.B. CBI und SBI dort schneller ausgeführt werden. Bei anderen AVRs muss man natürlich die Initialisierung anpassen (MCU-Kern, Stack, RAM, PORT und Timer-Interrupt). Ich habe als "Test-Streifen" 30 LEDs angeschlossen. Ausgebender Port ist Bit 0 von Port E. Alle die beim Lesen des Quelltextes aufschreien "Ahhh, Interrupt-Routinen müssen so kurz wie möglich sein!!!": Legt euch wieder hin! Mein Programm läuft KOMPLETT im Interrupt! Es gibt einen Initialisierungsteil, der die MCU, den Stack und die Ports initialisiert. Dann wird ein Speicherbereich eingerichtet, der zu jeder Zeit ein Abbild der anzusteuernden LEDs vorhält und zwar für jede LED drei Bytes: 1. Byte: LED 1: Helligkeit Grün 2. Byte: LED 1: Helligkeit Rot 3. Byte: LED 1: Helligkeit Blau 4. Byte: LED 2: Helligkeit Grün 5. Byte: LED 2: Helligkeit Rot 6. Byte: LED 2: Helligkeit Blau 7. Byte: LED 3: Helligkeit Grün usw. Es folgt die Initialisierung des Timers 1, damit der Timer-Interrupt alle 125 Millisekunden aufgerufen wird (8 Hz). Die Aufruffrequenz lässt sich natürlich anpassen ... Dann noch den Interrupt freigeben und danach als Hauptprogramm ein "JMP" auf sich selbst immer und immer wieder ausführen. Sollte der Timer-Interrupt nicht funktionieren, wäre hier das Ende ... Alle 125 ms wird aber die Interrupt-Routine aufgerufen. Diese macht folgendes: Teil 1) Den Bitstrom für die WS2812-LEDs erzeugen (Hinweis: NOP verzögert 1 Takt, RJMP PC+1 verzögert 2 Takte ...) Teil 2) Das LED-Speicherabbild für die nächste Übertragung vorbereiten. (Im Beispiel ist ein einfaches Lauflicht programmiert, welches einfach das LED-Speicherabbild verschiebt und eine neue Farbe ans Ende dranhängt ...) Teil 3) für eigene Erweiterungen ;-) Bei diesem Programmierstil muss man natürlich Sorge tragen, dass die Ausführungszeit der Interrupt-Routine nicht länger ist als die Aufruffrequenz. Viel Spaß damit ... Kommentare oder Fragen? Immer her damit ... Gruß, Thomas Tahsin-Bey
Was sind das für Stripes und woher hast du die? Verstehe ich recht, jede LED hat einen eigenen Controller den du mit deiner Software ansprichst?
Habe ich auch im Einsatz, coole Teile: http://shop.led-studien.de/index.php/cat/c30_Flexband-digital.html Gruß Jürgen
In diesem Thread gibt es auch eine Menge Infos: Beitrag "[Mitbestellung] SMD5050 RGB-LED mit integriertem 8-bit PWM Controller" Und ja, jede LED hat ihren eigenen Controller ... Gruß, Thomas
In diesem Beitrag gibt es Links auf die LED-Stripes: Beitrag "Re: [Mitbestellung] SMD5050 RGB-LED mit integriertem 8-bit PWM Controller" Ich habe hier ein paar Meter mit jeweils 60 LEDs pro Meter. Zum testen für das Programm habe ich mir einfach einen halben Meter abgeschnitten und mit drei Adern an den Controller gehängt (Vcc, Data, Gnd). Die LEDs sind einzeln ansteuerbar, wobei jeder Farbkanal (Rot, Grün und Blau) 256 unterschiedliche Helligkeitswerte annehmen kann. Gruß, Thomas
Hallo Thomas ! Tolles Programm ! und jetzt die Frage ;-) Assembler ist mir zu hoch gegriffen zur Zeit. Ich bin dabei C zu lernen. Kannst du ein Beispiel erzeugen wie ich das in C aufrufen/verwenden kann ? MfG Bart
bart verberne schrieb: > Assembler ist mir zu hoch gegriffen zur Zeit. Ich bin dabei C zu lernen. > Kannst du ein Beispiel erzeugen wie ich das in C aufrufen/verwenden kann > ? Und C liegt mir so gar nicht. :-( Aber vielleicht helfen dir die folgenden Tipps (oder ein anderer Leser kann hier weiterhelfen (wie übergebe ich in C einen Pointer?): A) Du kannst im Prinzip die Senderoutine (Txd_WS2811) ohne Probleme übernehmen. (Der gesamte "Teil 1") B) Die C Routine muss einen Pointer auf einen genügend großes eindimensionales Byte-Array bereitstellen, in dem die Helligkeitswerte drin sind. Meine Routine erwartet diesen Pointer im Y-Register. C) Anzahl der LEDs kannst du im Quelltext direkt reinschreiben (multipliziert mit 3). Siehe die ersten beiden Zeilen im "Teil 1". D) Interrupts während der Ausführung meiner Routine verbieten, da sonst die Zeiten nicht mehr exakt eingehalten werden. E) Benutzte Register sichern. Ich kann dir nicht sagen, welche Register du in deinem C-Programm während der Ausführung einer Assemblerroutine einfach so ändern darfst. Deswegen würde ich am Anfang alle benutzen Register auf dem Stack sichern und am Ende wieder zurückholen (auch das Statusregister!). Eventuell rettet C selbst alle Register, bevor die Ausführung an das Assemblerprogramm übergeben wird? F) Das Ende meiner Routine wäre dann bei "Update_Table". Hier sollte dann das Rückstellen der Register und der Rücksprung zum C-Programm stehen. G) Das Byte-Array kann dann im C-Programm beliebig geändert werden und bei Bedarf wird dann meine Routine aufgerufen. Eventuell sogar per Interrupt... Ich hoffe, dies hilft erstmal wenigstens etwas weiter! Gruß, Thomas
Hallo Alle. Gaebe es von eurer Seite aus Bedarf fuer eine WS2812 Ansteuerung, die lediglich den internen 8MHz benoetigen wuerde? Ich haette eine Roh-Implementierung und wuerde gern wissen ob sich aufraeumen lohnt, ob es jemand anderes gebrauchen koennte? Klarer Vorteil duerfte wohl sein, das man preiswerte "ATmegas" ohne grossartig externe Komponenten verwenden koennte... MfG
ich hab' jetzt grad meinen strip mit WS2812er rgb-leds bekommen: http://www.ledlightinghut.com/144-led-m-ws2812-digital-intelligent-rgb-led-strip-light.html lieferung war in ordnung, freitag abend bestellt, donnerstag angekommen. die WS2812 sind 5050er SMD-RGB-LEDS mit eingebautem WS2811-controller. es gibt nur eine leitung vom arduino zum strip. keine clock-leitung, deswegen ist das timing sehr wichtig, aber das erledigt diese bibliothek: http://code.google.com/p/fastspi/ den strip anschließen, im beispielsketch die anzahl der leds angeben und bei der auswahl des chipsets FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801); auswählen und ausbessern auf: FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2811); sketch hochladen und das testprogramm läuft. wär nur alles so einfach...
Bei do_nothing müsste man noch ein Sleep reinmachen können um noch etwas Strom zu sparen. Gruss Abraham
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.