Hallo, seit einigen Stunden mache und tue ich aber das Timing will einfach nicht passen. Ich möchte RGB LEDs mit integriertem WS2812 Controller ansteuern. Dieser verlangt als Timing für eine 1 ein High von 0,7us sowie ein Low von 0,6us. Für eine 0 beläuft sich das Timing auf 0,35us High sowie 0,8us Low. Wenn ich nun den Mega mit 8 Mhz betreibe beträgt die Zeit pro Takt 1/8000000, sowmit also 125ns. Laut Datenblatt beträgt die Zeit für eine 1 oder 0 je 1,25µs / 1250ns sowie eine Toleranz von 150ns, somit eine Gesamtzeit von min. 1,1µs/1100ns und max. 1,4µs/1400ns. Daher dachte ich mir nun folgendes: Für eine 1: Pin auf High 6 takte warten (750ns) Pin auf Low 5 takte warten (625ns) Gesamt: 1,375µs/1375ns Für eine 0: Pin auf High 3 takte warten (375ns) Pin auf Low 7 takte warten (875ns) Gesamt: 1,25µs/1250ns Gilt nur das High/Low auch schon als 1 Takt also muss ich diesen mit "einberechnen"? Anbei noch das Datenblatt Danke euch schonmal.
Tada: Beitrag "Re: Touch bauen, suche günstigere alternativen" :-D Hängs an SPI und überleg Dir , welchen SPI_Takt du brauchst um mit den entsprechenden BitMustern das Timing zu bekommen ;) Ansatzpunkt wäre 001 für ne 0 und 011 für ne 1. musst hat nur die helligkeitswerte in solch ein Muster umwandeln. Evtl kommst auch mit ner 5 stelligen Bitfolge pro Bit besser hin. Aber wie ich schon schrieb, das Timing trau ich die schon zu um die 800kbs zu schaffen, nur wird dein Problem das du nicht schnell genug die Daten nach einander rausschiebst und die Pause als reset(datenübername) interpretiert wird ;) Was auch ginge wäre PWM ohne OCR_Buffer . Musst nur 2 verschiedene Werte zur richtigen zeit ins OCR laden, also einen für ne 1 und einen anderen für die 0. Hier hättest allerdings gleich 2 timingprobleme, OCR zur richtigen zeit und keine Lücke größer als die resetzeit. Aber wie wir dich alle kennen, findest DU schon einen eigenen weg, der genau und nur für deinen aktuellen fall funktionieren wird... MfG Bugs
Vielleicht passt mein Beitrag ja für Dein Problem: Beitrag "WS2812 Ansteuerung in AVR-Assembler (ohne SPI o.ä., beliebige Pins verwendbar)" Schönen Abend... Gruß, Thomas
Nunja, da ich weder was von Bascom nund noch weniger von ASM verstehe, und damit ich den code hinterher auch selber gut verstehe würde, würde ich das ganze schon gerne selber machen. Deswegen fragte ich halt nach dem Timing. Ich habe gestern mal einen externen 12Mhz Quarz angeschlossen und gefused. Damit sollte ich eigentlich einen takt von um die 80ns erzeugen können. Kurzes test programm. int main void() { DDRB |= (1<<PD3); while(1) { PORTD |= (1<<PD3); PORTD &= ~(1<<PD3); } } Oszi dran und messen. Beim High bekomme ich einen takt von 186ns, bei LOW einen takt von 224ns. Ich bin gerade ein wenig am verzweifeln. Weiss jemand rat?
Tobias N. schrieb: > Gilt nur das High/Low auch schon als 1 Takt also muss ich diesen mit > "einberechnen"? Das kommt drauf an, ob dein abstrakter µC für die Ausführung des Befehls Zeit braucht. Jeder normale µC muß den Befehl lesen und ausführen. Sonst gäbe es keine Programmlaufzeiten - davon träumen viele.
Also das problem ist mit einem mega8, mega32 und mega128 das gleiche. Low ist länger als high und bei 12mhz sollte ein takt doch 83ns betragen. Also ich verstehe nicht warum die takte unterschiedlich sind und warum sie nichtmals annähernd an die 80ns kommen.
Tobias N. schrieb: > Also ich verstehe nicht warum die takte unterschiedlich sind > und warum sie nichtmals annähernd an die 80ns kommen. Der Compiler wird's nicht in SBI/CBI umsetzen kônnen, môglicherweise Optimierung aus, Portadresse außerhalb des Bereichs, dann ist's Port lesen, or/and und zurückschreiben. Das geht nicht in einem Takt. Das JMP am Ende braucht zusätzlich, darum dauert Low länger als High.
Das Tastverhältnis bei den Bits iist nicht so kritisch, aber der Takt /1.25us / Bit) muß konstant sein. Die Angaben in den Datenblättern sind da z.T. einfach falsch. Mit freundlichen Grüßen, James
Probier einmal soetwas:
1 | while(1) |
2 | {
|
3 | PORTD |= (1<<LED); |
4 | PORTD &= ~(1<<LED); |
5 | PORTD |= (1<<LED); |
6 | PORTD &= ~(1<<LED); |
7 | PORTD |= (1<<LED); |
8 | PORTD &= ~(1<<LED); |
9 | PORTD |= (1<<LED); |
10 | PORTD &= ~(1<<LED); |
11 | PORTD |= (1<<LED); |
12 | PORTD &= ~(1<<LED); |
13 | PORTD |= (1<<LED); |
14 | PORTD &= ~(1<<LED); |
15 | }
|
Ich hatte das selbe wie du auch schon mal auf einem PIC. Die Ausführung der While Schlaufe benötigt halt auch ein bisschen Zeit. Dadurch bleibt der Pin länger auf Low als auf High. Dieser Code hier ist zwar extrem unschön jedoch sollten dann ein paar high/low Takte gleich lange Zeiten haben.
Tobias N. schrieb: > so habe mal ein paar dateien angehangen. Also ich verstehe da echt > nichts mehr. Das Du nichts verstehst, ist für jeden auch nur halbwegs vernunftbegabten Menschen offensichtlich! Eine etliche Anzahl von Forumsmitgliedern und Gästen rät Dir, zunächst erstmal mit den LEDs zu experimentieren. "bla bla bla, alles kein Problem für mich!" Gleiches gilt für Deine Theorieren zu der "Touch"-Erkennung. Nun ja, wenigsten hast Du jetzt einen hübschen großen hölzernen Setzkasten, in welchen Du Deinen Elektroschrott stilvoll zur Schau stellen kannst...
Tobias N. schrieb: > jau, jetzt sind sie exakt 186ns High, 186ns Low Das sollte auch in C noch schneller, also in einem Takt anstatt in zwei Takten gehen: unsigned char off = PORTD & ~(1<<LED); unsigned char on = off | (1<<LED); PORTD = on; PORTD = off; PORTD = on; PORTD = off; PORTD = on; PORTD = off; PORTD = on; PORTD = off; Nur: Du möchtest ja nicht die gesamte Bitfolge fest programmieren. Du musst also irgendwann neue Daten ranschaffen. Dazu hast du aber gar keine Zeit. Wie willst du das lösen? LG, Sebastian
Für extrem timingkritisches "Bitbanging" ist C nicht die richtige Sprache. Selbst wenn es irgendwie funktionieren sollte, besteht immer das Risiko dass durch Änderungen an anderen Stellen im Programm (Registernutznug) oder andere Optimierungssetting das Timing des erzeugten Codes wieder verändert wird. Fertige Lösungen gibt es hier: Meine Library Beitrag "Lightweight WS2811/WS2812 Library" Neopixel Library für Arduino https://github.com/adafruit/Adafruit_NeoPixel Oder mal nach FastSPI-Lib suchen.
so das Timing passt jetzt inkl. reset. Getestet von 8Mhz intern über 8Mhz Quarz über 10Mhz Quarz sowie 12Mhz Quarz. Mit allen lässt es sich steuern, leider noch nicht "dynamisch". Das Problem vor dem ich stehe ich dei "umwandlung" von Ganzzahlen ins Binär vormat. Also halt x = 0; y = [code]; y = 00000000; oder x = 255; y = [code]; y = 11111111; Leide finde ich zwar über google gazen listen welche Zahl was in Binär ist aber ich finde keine C funktion die mir den Zahlen direkt ins Binär ändert. Derzeit gibt es zwei funktionen. writezero() und wirteone(). Nun will ich das ganze in writergb() erweitern, also
1 | writergb(255,255,255); |
Die funktion hierzu sollte in etwa so aussehen.
1 | unsigned char writezero(int g, int r, int b) |
2 | {
|
3 | |
4 | // Hier die einzelnen werte in Binär ändern. Und dann in einzelne Zeichen zerlegen. Danach halt if 1 = writeone, if 0 = writezero
|
5 | |
6 | }
|
ich will euch ja nichts vorenthalten :) Der Code ist nicht schön. Sicherlich gibt es hier welche die es "besser" können was "bei mir" ja nicht schwer sein sollte (wie alle sagen). Jetzt muss ich nur noch rumtesten und probieren wie das mit dem Farbenmischen ist, also "automatisch" also was ich wie erhöhe um die passenden farben zu kriegen usw. Per hand die werte eingeben ist ja nicht das problem. Kommen auch schöne farben raus nur würde ich gerne das jeweilige "mischverhältnis" wissen.
1 | #define LED PD3 // Licht port
|
2 | |
3 | unsigned char init5050(void) |
4 | {
|
5 | _delay_us(5); |
6 | return 0; |
7 | }
|
8 | |
9 | unsigned char reset5050(void) |
10 | {
|
11 | _delay_us(55); |
12 | return 0; |
13 | }
|
14 | |
15 | unsigned char writezero(void) |
16 | {
|
17 | PORTD |= (1<<LED); |
18 | PORTD |= (1<<LED); |
19 | PORTD &= ~(1<<LED); |
20 | PORTD &= ~(1<<LED); |
21 | PORTD &= ~(1<<LED); |
22 | PORTD &= ~(1<<LED); |
23 | PORTD &= ~(1<<LED); |
24 | PORTD &= ~(1<<LED); |
25 | return 0; |
26 | }
|
27 | |
28 | unsigned char writeone(void) |
29 | {
|
30 | PORTD |= (1<<LED); |
31 | PORTD |= (1<<LED); |
32 | PORTD |= (1<<LED); |
33 | PORTD |= (1<<LED); |
34 | PORTD |= (1<<LED); |
35 | PORTD &= ~(1<<LED); |
36 | PORTD &= ~(1<<LED); |
37 | PORTD &= ~(1<<LED); |
38 | return 0; |
39 | }
|
40 | |
41 | unsigned char writegrb(int g, int r, int b) |
42 | {
|
43 | // Grün
|
44 | if (g & 1<<1) { writeone(); } else { writezero(); } |
45 | if (g & 1<<2) { writeone(); } else { writezero(); } |
46 | if (g & 1<<3) { writeone(); } else { writezero(); } |
47 | if (g & 1<<4) { writeone(); } else { writezero(); } |
48 | if (g & 1<<5) { writeone(); } else { writezero(); } |
49 | if (g & 1<<6) { writeone(); } else { writezero(); } |
50 | if (g & 1<<7) { writeone(); } else { writezero(); } |
51 | if (g & 1<<8) { writeone(); } else { writezero(); } |
52 | |
53 | // Rot
|
54 | if (r & 1<<1) { writeone(); } else { writezero(); } |
55 | if (r & 1<<2) { writeone(); } else { writezero(); } |
56 | if (r & 1<<3) { writeone(); } else { writezero(); } |
57 | if (r & 1<<4) { writeone(); } else { writezero(); } |
58 | if (r & 1<<5) { writeone(); } else { writezero(); } |
59 | if (r & 1<<6) { writeone(); } else { writezero(); } |
60 | if (r & 1<<7) { writeone(); } else { writezero(); } |
61 | if (r & 1<<8) { writeone(); } else { writezero(); } |
62 | |
63 | // Blau
|
64 | if (b & 1<<1) { writeone(); } else { writezero(); } |
65 | if (b & 1<<2) { writeone(); } else { writezero(); } |
66 | if (b & 1<<3) { writeone(); } else { writezero(); } |
67 | if (b & 1<<4) { writeone(); } else { writezero(); } |
68 | if (b & 1<<5) { writeone(); } else { writezero(); } |
69 | if (b & 1<<6) { writeone(); } else { writezero(); } |
70 | if (b & 1<<7) { writeone(); } else { writezero(); } |
71 | if (b & 1<<8) { writeone(); } else { writezero(); } |
72 | |
73 | return 0; |
74 | }
|
So, damit nicht wieder erzählt wird "das wird eh nichts" und bla bla bla hier mal ein Video von einem "Testfeld" und ein paar Fotos dazu. Sobald ich die weiteren Platinen fertig geätzt und "angehangen" habe folgt dann auch ein Video mit mehreren LEDs. Als Codebasis fungiert mein Code von oben. Also läuft bisher super. Hier mal das Video: http://www.vidup.de/v/j1QZB/
Vielleicht passt es ja hier rein, war gestern gerade auf hackaday.Driving the WS2811 at 800 kHz with an 8 MHz AVR http://rurandom.org/justintime/index.php?title=Driving_the_WS2811_at_800_kHz_with_an_8_MHz_AVR
immerhin ;) siehste.. kannst ja mal die main() mit anhängen, damit mal sehen kann, wo die Farben durchgezählt werden.
hier noch die Ätzvorlage. Es passen immer 15 Platinen auf eine 10 x 16 cm Platine.
Tobias N. schrieb: > hier noch die Ätzvorlage. Es passen immer 15 Platinen auf eine 10 x 16 > cm Platine. Da hast Du aber arg dünne Leiterbahnen. Mach die dicker, Platz ist ja mehr als genug vorhanden!
naja, was heisst arg dünn? 0,5mm für die Daten und die Versorgung für die LED. 1,2mm für die 5V die ja von oben nach unten weitergegeben werden. Weil ich werde immer 10 Stück in Reihe schalten (die Versorgung) und die Daten dann wiederrum verbinden. Daher 1A pro mm. Also habe ich 1,2mm gewählt. Es wird ja "nur" die erste Platine in der Reihe "voll" belastet, bzw. die Leiterbahn, die weiteren "durchfahren" ja dann immer weniger Spannung. Nur mit der LED "anbindung" bin ich noch am überlegen. Also wie ich die Daten durchgebe. Ich habe ja 10 mal 15 Felder Soll ich die Verbindung nun von: 1 - 10 => 11 - 20 => 21 - 30 usw oder 1 - 10 => 20 - 11 => 21 - 30 => 40 - 21 usw oder 1 - 15 => 16 - 30 => 31 - 45 usw oder 1 - 15 => 30 - 16 => 31 - 45 => 60 - 46 usw ? Was wäre da also am sinnvollsten?
Guest schrieb: > Da hast Du aber arg dünne Leiterbahnen. Mach die dicker, Platz ist ja > mehr als genug vorhanden! Das lohnt leider nicht... der macht sein Ding... obs gut oder schlecht ist, ist erstmal egal... gibt schon Leute ;)
>Weil ich werde immer 10 Stück in Reihe schalten (die Versorgung)
Schreibfehler? Die kann man nicht in Reihe schalten...
Viel Erfolg!
KaA
Soll ich die Verbindung nun von: 1 - 10 => 11 - 20 => 21 - 30 usw oder 1 - 10 => 20 - 11 => 21 - 30 => 40 - 21 usw oder 1 - 15 => 16 - 30 => 31 - 45 usw oder 1 - 15 => 30 - 16 => 31 - 45 => 60 - 46 usw ? Was wäre da also am sinnvollsten? Ist egal, macht man doch nachher über das Mapping im Framebuffer.
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.