Hallo! :) Ich bin relativ neu bei der Programmierung von µCs, habe mich jetzt aber einigermaßen in C eingearbeitet. Jetzt stehe ich vor folgendem Problem: Ich möchte gerne mit 3 LEDs (Grün,Blau,Rot) einen Sockel zum Beleuchten eines Gegenstandes bauen. Diese 3 LEDs sollen jeweils paarweise ineinander überfaden, sprich: Grün nimmt ab, Blau nimmt zu. Wenn Blau dann abnimmt, nimmt Rot zu,usw. Anhand dieses Artikels: http://www.mikrocontroller.net/articles/LED-Fading sowie den anderen PWM-Artikeln im Forum habe ich jetzt ungefähr verstanden, wie PWM für eine einzelne LED funktioniert. An Mikrocontrollern habe ich hier einen Atmega8A sowie einen Atmega8515. Bei beiden steht auf dem Deckblatt "Three PWM-Channels". Wenn ich dann weiterlese, finde ich aber maximal 2 Timer, die anscheinend PWM unterstützen. Außerdem gibt es ja nur OC1A und OC1B... Weiterhin steht noch dieser Satz unter Timer1 beim Atmega8A: "When using OCR1A as TOP value in a PWM mode, the OCR1A Register can not be used for generating a PWM output." Nun meine Fragen: 1. Ist mein Ansatz für diesen Einsatzzweck HW-PWM statt SW-PWM zu nutzen richtig, oder erreiche ich ähnliche Ergebnisse (->Flüssiges Faden aller LEDs) auch durch SW? 2. Ist das mit einem der von mir beschriebenen µCs überhaupt grundsätzlich möglich, oder brauche ich dazu einen anderen Controller? 3. Was bedeutet sonst das "3 PWM-Channels" auf der Titelseite? 4. Hab ich richtig verstanden, dass ich OCR1A brauche, falls mein Grenzwert variabel ist (was bei fading ja der Fall ist), sonst reicht ICR1? Vielen Dank schonmal im Voraus für eure Bemühungen ;) Viele Grüße, Jens
moin 1. nimm den hw pwm. 2. ohne jetzt genau ins Datenblatt geschaut zu haben sollte es mit beiden gehen. 3. die Sache mit den timer bezieht sich auf die PWM-Grundfrequenz 4. dein Grenzwert variiert nicht nur der PWM-wert. schau ins Datenblatt :P als kleiner Tip pass auf das die Ausgängen den Strom überhaupt liefern können den du brachst Gruß Andreas
Hallo, es sind 3 HW PWM Kanäle vorhanden. Timer 1 + OC1A und OC1B (8Bit Timer) Timer 2 + OC2 (16Bit Timer, als 10 Bit PWM konfigurierbar) hth Maik
Hi Andreas, danke für die schnelle Antwort! Okay, bedeutet das, dass ich nur einen Timer für alle 3 PWMs benötige? Teile des Datenblatts hab ich schon mehrmals gewälzt, aber für mich als Neuling ist das unglaublich schwierig, da die richtigen Infos rauszulesen. Es scheitert ja schon dran, dass ich das 3. PWM gar nicht finde (bzw. dessen Ausgang...) Zu 4., warum variiert mein Grenzwert nicht? Dimmen wird ja, so wie ich das verstanden habe, erreicht indem jedes mal bis zu einem größeren Wert gefahren wird. Also zb. 1. Durchlauf bis 1, dann bis 3, dann bis 8 usw....Ändert sich da nicht meine Grenze? Danke für den Tipp mit den Strömen, habe ich schon überprüft. Meine LEDs sollen maximal 20mA kriegen, die Ausgänge liefern bis zu 40mA. Danke nochmal. Viele Grüße, Jens
jna380 schrieb: > Bei beiden steht auf dem Deckblatt "Three PWM-Channels". Der 3. ist aber nur 8 Bit, das könnte schon sichtbare Übergänge bedeuten. 10..12 Bit wären besser. Aber man kann in SW leicht 8 PWM-Ausgänge realisieren, die gleich schnell, wie die Fast-PWM sind: Beitrag "AVR: Fast-PWM (BAM) 12 Bit für 8 Kanäle"
huhu Jens wie Maik schon schreibt brachst du beide Timer ,weil eben PB1 = OC1A (Timer1/Counter1 Output Compare Match A Output) PB2 = OC1B (Timer1/Counter1 Output Compare Match B Output) PB3 = OC2 (Timer2/Counter2 Output Compare Match Output) wie Maike auch schon schreibt ist aber die Auflösung der Timer unterschiedlich Timer1 zählt bis 1024 aber Timer 2 nur bis 256. zu 2 grensen sind ie max werte also 1024 und 256 z.B. die 1,3,8 ist er wert vom PWM vereinfacht wie lange die Spannung anliegt zB. 1/256,3/268,8/268 der Grundfrequenz Gruß Andreas
Vielen Dank für eure Antworten, hat mir sehr geholfen. Habs jetzt verstanden, PWM läuft auch mit 3 LEDs an allen verfügbaren Channels. Leider war der Einwand richtig, dass 8-bit da nicht wirklich ausreichend sind. 10-bit sieht da schon wesentlich schöner aus. Was kann ich jetzt tun? Habe mal bei reichelt die Atmega bis 4€ durchgeschaut, die scheinen aber alle nur einen einzigen 16-bit Timer zu besitzen. Hat jemand einen Tipp für einen passenden µC für 3*10-bit PWM? Danke! ;)
huhu ehe ich einen neuen µC kaufen würde, würde ich mal versuchen mir ein PWM Signal über den Timer Interrupt zu basteln.Die µC macht ja eh nicht mehr als nur die PWM Sache oder? nach dem Motto: main{ if (PWMzaeler<=PWMdimmwert) pb1= ein; else PB1= aus; } Overflow Interrupt{ if (PWMzaeler<=1024) PWMzaeler++; else PPWMzaeler=0; } Gruß Andreas
jna380 schrieb: > Leider war der Einwand richtig, dass 8-bit da nicht wirklich ausreichend > sind. 10-bit sieht da schon wesentlich schöner aus. Auch 10-bit reichen nicht aus, bei den ersten 16 Helligkeitsstufen muss man mit mindestens 2 Stellen hinterm Komma rechnen. Ich hoffe, du verwechselst nicht PWM-Frequenz und PWM-Auflösung. Für deine LEDs reicht eine PWM-Frequenz von 200Hz (5mS) vollkommen, aber die PWM-Auflösung sollte so groß wie möglich sein. Mit Timer1 hat die MEGA8 16-bit Auflösung, also genug für normales dimmen. Problem ist aber, dass es nur einen 16-bit Timer gibt. Du könntest auch Timer1 als 16-bit Counter in CTC Mode für alle 3 LEDs nacheinander benutzen: OCR auf gewünschte PWM-Frequenz einstellen. Timer1 starten, ISR abwarten. In der ISR LEDs (falls nötig) einschalten, neue Endwerte laden. Danach TCNT Zustand in einer Schleife in main() ständig abfragen, falls >= LED_Endwert, LEDs eine nach der anderen, je nach Endwert ausschalten. Die paar uS Ungenauigkeit fallen kaum ins Gewicht... Am besten ist aber Software-PWM mit BAM. Lese doch mal Beitrag "AVR: Fast-PWM (BAM) 12 Bit für 8 Kanäle" von peda, das ist mehr als genug für deine 3 LEDs.
:
Bearbeitet durch User
jna380 schrieb: > Hat jemand einen Tipp für einen passenden µC für 3*10-bit PWM? Zwei 16Bit-Timer (und damit 4 16Bit-PWM-Kanäle) haben z.B.: Mega1284P Tiny441 Tiny841
jna380 schrieb: > Ich möchte gerne mit 3 LEDs (Grün,Blau,Rot) einen Sockel zum Beleuchten > eines Gegenstandes bauen. Diese 3 LEDs sollen jeweils paarweise > ineinander überfaden, sprich: Grün nimmt ab, Blau nimmt zu. Wenn Blau > dann abnimmt, nimmt Rot zu,usw. Such nach "Moodlight". Meins z.B. verwendet einen ATmega8. XL
jna380 schrieb: > Danke für den Tipp mit den Strömen, habe ich schon überprüft. Meine LEDs > sollen maximal 20mA kriegen, die Ausgänge liefern bis zu 40mA. Für deine Anwendung jetzt vielleicht weniger wichtig, aber als Tipp für die Zukunft: Bedenke bitte, dass nicht nur der Strom über einem Ausgang beschränkt ist, sondern auch der Strom über einem ganzen Port sowie der Strom für den ganzen uC. Sprich, wenn du 8 Ausgänge pro Port hast die 40mA liefern können, wärst du ja theoretisch bei 40mA * 8 = 320 mA. Heisst jetzt aber auch, dass dein Port gesamt 320 mA liefern können muss. Das müsste man dann auch noch überprüfen. Wie gesagt für deine jetzige Anwendung vielleicht weniger wichtig, aber irgendwann für die Zukunft.. ;) zu meinen Anfangszeiten mit uC's haben mir wegen dieser fehlenden Information ein paar Controller lebewohl gesagt :P Desweiteren: Wenn deine LED mit 20mA angegeben wird, bedeutet das nicht dass du diese mit 20mA bestromen musst. Die heutigen LEDs leuchten meist auch schon bei 5-10mA stark genug. Also vielleicht zu Beginn ruhig mal einen etwas grösseren Vorwiderstand wählen und schauen, ob es so schon reicht. Gewechselt wäre er ja ansonsten schnell ;)
Danke für die zahlreichen Tipps/Anregungen und Hinweise ;) Das trotzdem mit dem Atmega8 zu realisieren finde ich gut, hätte es irgendwie nicht eingesehen für so eine Aufgabe einen Controller jenseits 5€ zu benutzen. Ich denke mich mal noch ein bisschen durch eure Vorschläge, und schaue dass ich das irgendwie softwareseitig realisiert bekomme. Bei dem verlinkten Beispiel "Fast-PWM (BAM)" verstehe ich leider noch erstaunlich wenig...muss ich mich nochmal reindenken. Ansonsten klingt das Vorgehen eigentlich gut, bin mit den verschiedenen PWM-Modi noch nicht so ganz warm geworden, und lese jetzt zum 5. Mal das Datenblatt :D Momentan bin ich nur mit (1<<WGM10) gefahren, also "PWM, Phase-Correct 8-bit". Witzigerweise sehe ich überhaupt keinen Unterschied zu "Fast-PWM 8-bit", das sieht vielleicht nochmal minimal weniger weich aus. Bei "TOP" steht im Datenblatt 0x00FF. Das macht Sinn. Also zählt er bis OCR1A, hat solange OC1A auf 1, und schaltet das dann auf 0 und zählt weiter bis 0x00FF. Richtig? Was macht er denn dann beim CTC-Mode, wenn da OCR1A "TOP" ist? Dann zählt er bis zu diesem Wert, hat solange 1 und fängt dann wieder von unten an? Hab den Sinn noch nicht ganz erfasst... Danke, habt mir schon ziemlich geholfen :) Viele Grüße, Jens
jna380 schrieb: > Das trotzdem mit dem Atmega8 zu realisieren finde ich gut, hätte es > irgendwie nicht eingesehen für so eine Aufgabe einen Controller jenseits > 5€ zu benutzen. Das ehrt dich. Allerdings solltest du gleich wissen, daß ein ATmega8 dafür einfach zu wenig PWM-Kanäle hat. Die 256 linearen(!) Stufen einer 8-Bit PWM sind zu wenig. Man braucht wenigstens 10 Bit (besser 12) bei linearer Abstufung. Mit Soft-PWM kann man das aber hinbekommen. Es erfordert nur halt ein wenig mehr Hirnschmalz als einfach nur 3 PWM-Register der Hardware zu beschreiben. XL
Ich hatte doch weiter oben was verlinkt ;) Atmega88, der hat so schon 2x16 bit PWM und die dritte 16bit PWM wurden mit 2 Timern erzuegt. Gucks dir mal an.
Der dritte PWM hat nur leider Timingprobleme im Bereich ab 60000 (da gibt es ein paar Werte, wo er komplett aus geht) und kleine Werte (0...256) bekommt er auch nicht richtig hin (zu grob abgestuft und "zu hell").
:
Bearbeitet durch User
So, jetzt habe ich das mit den Timern und Interrupts soweit mal verstanden glaube ich. Danke für die anderen Vorschläge, aber zuerst versuche ich das jetzt mal mit Soft-PWM und gegebenen Mitteln zu realisieren ;) Momentan bin ich dabei, den Vorschlag von @Marc Vesely umzusetzen, wobei das noch nicht so ganz hinhaut. Eigentlich müsste das doch folgendermaßen funktionieren, oder hab ich da was falsch verstanden?: 1. Mittels CTC-Mode zählt mein Timer bis zu Wert x. Bei einem Prescaler von 1 erhalte ich also jeden x.Prozessortakt einen Interrupt. Die Frequenz dieser Interrupts ist also meine PWM-Frequenz. Richtig? Bei 8 MHz clk_CPU ergeben sich ja Periodendauern zu 12,5 µs, also brauche ich für 200HZ "Interrupttakt" jeden 400. Schritt. Folglich ist mein OCR1A=400, oder? 2. Da mein Timer aber ja nur Werte zwischen 0 und x annehmen kann, ist automatisch meine PWM-Auflösung auch auf diesen x-Stufen, oder? Ich kann in der main() ja nur Werte zwischen 0 und x im TCNT1 überprüfen, da dieses ja nie größer x wird. Eigentlich wollte man die Auflösung doch von der Frequenz trennen? Wie kriege ich es hin, zb die Auflösung von 10-bit zu haben, ohne die Interrups und damit die PWM-Frequenz zu beeinflussen? Mache ich komplett einen Denkfehler?! Hier mal, was ich bis jetzt zusammengeschrieben habe, LED ist aber gleichbleibend gedimmt, wird wohl irgendwie dran liegen dass sich alles zu schnell ändert...
1 | #include <stdint.h> |
2 | #include <string.h> |
3 | #include <avr/io.h> |
4 | #include <avr/interrupt.h> |
5 | #include <util/delay.h> |
6 | |
7 | uint16_t values[32] = |
8 | {
|
9 | 0, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 10, 11, 13, 16, 19, 23, |
10 | 27, 32, 38, 45, 54, 64, 76, 91, 108, 128, 152, 181, 215, 255 |
11 | };
|
12 | uint8_t next = 0; |
13 | uint8_t i = 0; |
14 | |
15 | int main(void) |
16 | {
|
17 | DDRB = 0xFF; |
18 | PORTB = 0x00; |
19 | OCR1A = 255; |
20 | TCCR1B |= (1<<WGM12) | (1<<CS10); |
21 | TIMSK |= (1<<OCIE1A); |
22 | sei(); |
23 | while(1) |
24 | {
|
25 | if(TCNT1 >= next) |
26 | {
|
27 | PORTB &= ~(1<<PB0); |
28 | }
|
29 | }
|
30 | return 0; |
31 | }
|
32 | |
33 | ISR(TIMER1_COMPA_vect) { |
34 | PORTB |= (1<<PB0); |
35 | if(i<31){ |
36 | next = values[i]; |
37 | i++; |
38 | }
|
39 | else {i=0;} |
40 | }
|
Sorry wenn da irgendwelche groben Fehler drin sind, mache das wie gesagt noch nicht so lange ;) Danke nochmal, wird langsam alles etwas klarer...:) Viele Grüße, Jens
Okay, die Rechnung oben war natürlich quatsch, es ist natürlich nicht jeder 400. Takt sondern jeder 40000. der einen Interrupt auslöst um auf 200 Hz PWM zu kommen...Periodendauer bei 8MHz ist natürlich 0,125 µs...
huhu war mal so frei das Programm auf einen atmega328p zu schieben und es ans ossy zu hängen. #define F_CPU 16000000UL //fehlt ganz oben TIMSK1 |= (1<<OCIE1A); //so ist die Zeile korrekt Kommentare ftw :D wie du siehst lauft den pwm rasend schnell alle werte durch, glaube nicht das man das sieht ob du einfach Ein schaltest oder langsam hoch fährst :) Gruß Andreas
jna380 schrieb: > Okay, die Rechnung oben war natürlich quatsch, es ist natürlich nicht > jeder 400. Takt sondern jeder 40000. der einen Interrupt auslöst um auf > 200 Hz PWM zu kommen...Periodendauer bei 8MHz ist natürlich 0,125 µs... Und damit hast du ja mehr als 15-bit PWM-Auflösung bei einer PWM-Frequenz von 200Hz... Nur aufpassen bei kleineren Werten, dass du nicht die ISR blockierst. Am besten deine Werte aus der Tabelle * 16 (oder sogar 32), und noch feinere, bzw. genauere Abstufung.
:
Bearbeitet durch User
Ja, das leuchtet ein...und wie variiere ich dann die Dauer des Fadevorgangs? Die Frequenz bleibt gleich...die Bitbreite bzw Abstufung ist direkt abhängig von der Frequenz, muss ich dann immer meine Wertetabelle ändern um die Steig- und Fallgeschwindigkeit zu beeinflussen?
jna380 schrieb: > if(TCNT1 >= next) > next = values[i]; Ooops. next ist 8-bit. values sind 16-bit. Timer1 ist 16-bit.
jna380 schrieb: > Die Frequenz bleibt gleich...die Bitbreite bzw Abstufung ist direkt > abhängig von der Frequenz, muss ich dann immer meine Wertetabelle ändern > um die Steig- und Fallgeschwindigkeit zu beeinflussen? Wie bei Radio Eriwan Im Prinzip ja, aber... Sagen wir mal, du hast deiner ISR eine Mindestzeit von 32 Cycles gegeben. Damit fängst du also an, das ist die erste Stufe, die sichtbar sein soll. Bei einem Endwert von 40000 kommst du auf etwa 59 Stufen. Deinem compiler sagst du das die erste Stufe 32 ist, jede weitere Stufe 1,13 mal grösser sein soll als die vorhergehende und lässt ihn die Arbeit machen. Das wars. Und glaube mir, unteres Drittel ist wichtig, da must du genau sein. Lieber im oberen Drittel etwas gröber abstufen.
Ja hab ich grade schon bemerkt und behoben, davor hat die LED nur geglimmt :D Trotzdem hab ich selbst bei einer großen Tabelle wie values3 oder der von dir vorgeschlagenen values11 ein sehr unruhiges faden, viel zu schnell und außerdem sieht man flackern...langsam bin ich mit meinen Ideen am Ende...
1 | uint16_t values3[256] = |
2 | {
|
3 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, |
4 | 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, |
5 | 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15, |
6 | 15, 16, 17, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, |
7 | 31, 32, 33, 35, 36, 38, 40, 41, 43, 45, 47, 49, 52, 54, 56, 59, |
8 | 61, 64, 67, 70, 73, 76, 79, 83, 87, 91, 95, 99, 103, 108, 112, |
9 | 117, 123, 128, 134, 140, 146, 152, 159, 166, 173, 181, 189, 197, |
10 | 206, 215, 225, 235, 245, 256, 267, 279, 292, 304, 318, 332, 347, |
11 | 362, 378, 395, 412, 431, 450, 470, 490, 512, 535, 558, 583, 609, |
12 | 636, 664, 693, 724, 756, 790, 825, 861, 899, 939, 981, 1024, 1069, |
13 | 1117, 1166, 1218, 1272, 1328, 1387, 1448, 1512, 1579, 1649, 1722, |
14 | 1798, 1878, 1961, 2048, 2139, 2233, 2332, 2435, 2543, 2656, 2773, |
15 | 2896, 3025, 3158, 3298, 3444, 3597, 3756, 3922, 4096, 4277, 4467, |
16 | 4664, 4871, 5087, 5312, 5547, 5793, 6049, 6317, 6596, 6889, 7194, |
17 | 7512, 7845, 8192, 8555, 8933, 9329, 9742, 10173, 10624, 11094, |
18 | 11585, 12098, 12634, 13193, 13777, 14387, 15024, 15689, 16384, |
19 | 17109, 17867, 18658, 19484, 20346, 21247, 22188, 23170, 24196, |
20 | 25267, 26386, 27554, 28774, 30048, 31378, 32768, 34218, 35733, |
21 | 37315, 38967, 40693, 42494, 44376, 46340, 48392, 50534, 52772, |
22 | 55108, 57548, 60096, 62757, 65535 |
23 | };
|
24 | uint16_t values11[32] = |
25 | {
|
26 | 0, 256, 512, 512, 512, 768, 768, 1024, 1280, 1536, 1792, 2048, 2560, 2816, 3328, 4096, 4864, 5888, |
27 | 6912, 8092, 9728, 11520, 13824, 16384, 19456, 23296, 27648, 32768, 38912, 46336, 55040, 65280 |
28 | };
|
Hast du noch Ideen, wie ich das verlangsamen kann ohne ganze Tabellen zu ändern, bzw warum es immernoch unrund läuft? Danke...
jna380 schrieb: > Trotzdem hab ich selbst bei einer großen Tabelle wie values3 oder der > von dir vorgeschlagenen values11 ein sehr unruhiges faden, viel zu > schnell und außerdem sieht man flackern...langsam bin ich mit meinen > Ideen am Ende... Auweiea. Du sollst nicht die Tabelle durchfahren, sondern nur die entsprechenden Werte daraus entnehmen. Also: > next = values[i]; i ist die Helligkeitsstufe, Tabelle values hast du mit 59 dimensioniert, da stehen die Werte für OCR1. i änderst du aber in main() oder nimmst Timer0 dafür, d.h. i kann unverändert bleiben für 5 oder 500 CTC-Aufrufe des Timer1 oder sich bei jedem Aufruf ändern, was aber zu schnell ist. Wenns immer noch unklar ist, versuche ich später mit einem Beispiel.
jna380 schrieb: > Hast du noch Ideen, wie ich das verlangsamen kann ohne ganze Tabellen zu > ändern, bzw warum es immernoch unrund läuft? Das hat mir Excel ausgerechnet: 32, 36, 41, 46, 52, 59, 66, 75, 85, 96, 108, 123, 139, 157, 177, 200, 226, 255, 289, 326, 369, 416, 471, 532, 601, 679, 767, 867, 980, 1107, 1251, 1414, 1598, 1806, 2040, 2306, 2605, 2944, 3327, 3760, 4249, 4801, 5425, 6130, 6927, 7828, 8846, 9996, 11295, 12764, 14423, 16298, 18417, 20811, 23517, 26574, 30029, 33932, 38344 Versuchs mal damit.
:
Bearbeitet durch User
Erstmal vielen Dank, dass du dir so viel Zeit nimmst mir das zu erklären. Mir ist durchaus bewusst, dass ich mich wohl erst noch ein bisschen in das ganze Thema reinfinden muss... Ich glaube ich hab jetzt verstanden was du mit dem i-Erhöhen meintest:
1 | int main(void) |
2 | {
|
3 | DDRB = 0xFF; |
4 | PORTB = 0x00; |
5 | |
6 | //Timer1 init
|
7 | OCR1A = 40000; |
8 | TCCR1B |= (1<<WGM12) | (1<<CS10); // Timer1 CTC-Mode, zählt bis OCR1A, kein Prescaler |
9 | TIMSK |= (1<<OCIE1A) | (1<<TOIE0); // Compare Interrupt OCR1A enabled |
10 | |
11 | //Timer0 init
|
12 | TCCR0 |= (1<<CS02) | (1<<CS00); //Prescaler 1024 |
13 | |
14 | sei(); |
15 | while(1) |
16 | {
|
17 | if(TCNT1 >= next) |
18 | {
|
19 | PORTB &= ~(1<<PB0); |
20 | }
|
21 | }
|
22 | return 0; |
23 | }
|
24 | |
25 | ISR(TIMER1_COMPA_vect) { |
26 | PORTB |= (1<<PB0); |
27 | next = values4[i]; |
28 | }
|
29 | |
30 | ISR(TIMER0_OVF_vect) { |
31 | if (i<58) |
32 | i++; |
33 | else {i=0;} |
34 | }
|
Sowas, oder? Timer0 mit maximalem Prescaler also möglichst langsam. Das hab ich jetzt mit deiner Tabelle umgesetzt, (values4, s.o.), die LED scheint aber zwischendrin auszugehen oder sowas, oder die Frequenz ist zu niedrig. Es sieht einfach wahnsinnig ruckelig aus und wird auch im Verlauf selbst blitzartig heller und dunkler...Warum?
huhu einfach noch eine if Schleife über die Variable i lagen so das sie mehrere Interrupts unverändert bleibt. damit könntest du dann die Geschwindigkeit einstellen :D Gruß Andreas
jna380 schrieb: > zu niedrig. Es sieht einfach wahnsinnig ruckelig aus und wird auch im > Verlauf selbst blitzartig heller und dunkler...Warum? Muss jetzt gehen, versuch mal in der Zwischenzeit das Ganze in Atmel Studio laufen zu lassen, kannst auch logfile machen mit PortB.
Probiere es mal mit angehängter Datei, sollte eigentlich gehen. Habe da ein paar Sachen geändert, CTC-ISR rausgeschmissen, hoffe das es funktioniert. mfg Marc P.S. Auch wenn es funktionieren sollte, ist es trotzdem ziemlich nutzlos, rauf- und runterdimmen auf diese Art ist vielleicht zum üben gut, hat aber keinen praktischen Wert. Deswegen rate ich dir wieder, den Beitrag "AVR: Fast-PWM (BAM) 12 Bit für 8 Kanäle" von peda zu lesen. Laut Autor beträgt die Last nur etwa 9%. Mit BAM kann der uC auch andere Sachen machen - ich habe hier eine 10 Kanal RGB-BAM rumstehen, da werden die Sequenzen locker von der SD-Karte gelesen - mit 8MHz M328, allerdings in Assembler und mit mehr als 60% Last. Aber auch das ist ziemlich nutzlos, den mit WS28xx geht das alles viel einfacher...
Oje oje oje, wie hat sich denn der Thread entwickelt. Man braucht überhaupt keine Timer, die machen die Sache nur langsamer, man lässt nur eine Timer mitlaufen den man pollt um in langen Wartezeiten auch Dinge machen zu können, die unterschiedlich lange dauern. Man hat eine Programm-Hauptschleife, die zur Bedienung der 3 x 7 LEDs pro Reihe mit 256 Helligkeitsstufen nur folgendes machen muss PORTA=red0; PORTB=blue0; PORTC=green0; PORTD=1; delay(1); PORTA=red1; PORTB=blue1; PORTC=green1; PORTD=2; delay(2); PORTA=red2; PORTB=blue2; PORTC=green2; PORTD=4; delay(4); PORTA=red3; PORTB=blue3; PORTC=green3; PORTD=8; delay(8); PORTA=red4; PORTB=blue4; PORTC=green4; PORTD=16; delay(16); PORTA=red5; PORTB=blue5; PORTC=green5; PORTD=32; delay(32); PORTA=red6; PORTB=blue6; PORTC=green6; PORTD=64; delay(64); PORTA=red7; PORTB=blue7; PORTC=green7; PORTD=128; delay(128); für bit angle modulation der 3 Farben. Dabei steht red0 für die Sammlung der 7 bit 0 der Farbe red der 7 LEDs, red1 für die Sammlung der 7 bit 1 der Farbe rot, usw. (oder mit anderer, letzlich beliebiger, bits auf ports Verteilung) Diese Aufbereitung der Daten macht man VORHER, wenn man Zeit hat, also innerhalb des delay(128) Timeslots. Dort kann man die bits so umordnen, dass sie dann mit obenstehender Routine schnell gesendet werden können. Auf einem ATMega16 mit 16MHz reicht das für 500ns pro Farbbit, bei 10 bit Helligkeitsauflösung also 512usec, bei 7 Reihen also 280 Hz Bildwiederholfrequenz, natürlich in Assembler (mit LD reg,X+). Es gingen auch 12 bit Farbauflösung mit 70Hz Bildwiederholrate oder 8 bit mit 128 x 7 LEDs.
Warum denn Bit-Angle-Modulation und nicht Sigma-Delta? Ist vom Aufwand her nicht schlimmer, flimmert dafür aber weniger...
Marc Vesely schrieb: > Aber auch das ist ziemlich nutzlos, den mit WS28xx geht das alles > viel einfacher... Hi, ich glaub' der Mann hat recht. Im Bascom-forum wurde eine tolle WS2812 lib entwickelt, und schon mit der ersten Version dieser lib lässt sich dein Beleuchtungsprojekt mit einem Attiny13 ! realisieren. Die Ws2812 hat zwar 'nur' 8bit pro Farbe, aber ich versteh' das ganze Gedöns mit 10bit und mehr nicht. Wenn du dein Teil mit einer Überblendungszeit von ca. 5 sec anstrahlst, hast du dabei 512 Farben durch zu laufen, macht pro sec 100 Farben. Wie viel Bilder/sec kann das menschliche Auge als Einzelbilder wahrnehmen? 10? 12?. Hier mal mein Versuch: https://www.youtube.com/watch?v=aHS61jRsjqQ Grüße von tschoeatsch
Michael Kirch. schrieb: > Die > Ws2812 hat zwar 'nur' 8bit pro Farbe, aber ich versteh' das ganze Gedöns > mit 10bit und mehr nicht. Bascom Profis halt... Mach doch mal ein Fade von 0 bis 255. Fällt Dir bei den dunkeln Farben etwas auf? Da fehlen ein paar Stufen... Das liegt daran, dass das Auge die Helligkeit nicht linear wahrnimmt. Für die dunklen Bereiche benötigt man eine höhere Auflösung.
N. Rokpop schrieb: > Fällt Dir bei den dunkeln Farben > etwas auf? Da fehlen ein paar Stufen... Hi, ich dachte, hier wird ein Objekt beleuchtet und nicht verdunkelt. So wie ich das verstanden hab', wird die Beleuchtung des Objektes nie auf schwarz gedimmt, sondern es leuchtet eine Farbe mindestens mit 50%. Klar kann man alles bis auf's letzte Tüpfelchen ausreizen. Das Ding läuft hier vor sich hin und mir fällt keine Lücke auf. Grüße von tschoeatsch
:
Bearbeitet durch User
N. Rokpop schrieb: > Mach doch mal ein Fade von 0 bis 255. Fällt Dir bei den dunkeln Farben > etwas auf? Da fehlen ein paar Stufen... > > Das liegt daran, dass das Auge die Helligkeit nicht linear wahrnimmt. > Für die dunklen Bereiche benötigt man eine höhere Auflösung. Ja, und da kann man quasi interpolieren. Mit PWM-Frequenz von 1KHz hast du 1mS Zeit, die Farbe oder Intensität zu wechseln. Kürzer als 20mS hat kaum Sinn, also hast du 20*1mS Zeit. Damit ist man auf 0,05 genau. Als Beispiel: (17*3 + 3*4) / 20 ergeben 3,15. Wo sollen da paar Stufen fehlen ? P.S. PWM bzw. BAM macht es genauso und du merkst es trotzdem nicht. Ausser logarithmischer Wahrnehmung gibt es so etwas wie Trägheit des Auges...
:
Bearbeitet durch User
jna380 schrieb: > Das trotzdem mit dem Atmega8 zu realisieren finde ich gut, hätte es > irgendwie nicht eingesehen für so eine Aufgabe einen Controller jenseits > 5€ zu benutzen. Ein Atmega1284 kostete 5Euro, ein Atmega8A kostet 1,50. Dazu 2,40 Versand, z.B. im guloshop. Aus China wird es dann nochmal günstiger. Wenn man in Apotheken kauft wird es natürlch teuer.
Vielen Dank nochmal für die vielen Vorschläge. @Marc, das mit der CPU-Auslastung macht schon Sinn, ich versuche mich mal an BAM so wie MaWin das beschrieben hat. Wie kann ich innerhalb des 128ms-Delay-Slots neu initialisieren und trotzdem sichergehen, dass genau 128ms vergehen? Dazu müsste ich ja die genaue Dauer meiner Initialisierung kennen, und die Restzeit mit _delay_ms "auffüllen",oder? Abgesehen davon nehme ich einfach wie gehabt eine Wertetabelle, und picke mir aus dem aktuellen Wert die bits raus, die dann für eine gewisse delay-dauer gesetzt werden, oder? Also bei 8-bit z.B. Wert 200, Binär: 11001000. Also sind red0-2 0, red3 ist 1, red4,5 wieder 0, red6,7 1, korrekt? Und dann lade ich mir im nächsten 128ms-delay zB. den Wert 204 rein?
jna380 schrieb: > Also bei 8-bit z.B. Wert 200, Binär: 11001000. Also sind red0-2 0, red3 > ist 1, red4,5 wieder 0, red6,7 1, korrekt? Korrekt. jna380 schrieb: > Und dann lade ich mir im nächsten 128ms-delay zB. den Wert 204 rein? Wie kommst du überhaupt auf 128mS ? jna380 schrieb: > Wie kann ich innerhalb des 128ms-Delay-Slots neu initialisieren und > trotzdem sichergehen, dass genau 128ms vergehen? Dazu müsste ich ja die > genaue Dauer meiner Initialisierung kennen, und die Restzeit mit > _delay_ms "auffüllen",oder? Also, ich kann dir nur sagen, wie ich es mache: main() setzt die entsprechenden RGB-Werte, eine funktion rechnet diese RGB-Werte in bit-Zustände um, schreibt diese in einen Array. ISR nimmt die bit-Zustände und setzt die Ports dementsprechend. Für die ersten 4 bits wird die ISR überhaupt nicht verlassen (bei mir). Wichtig ist, dass die ISR genau ist - ob du LEDs nach 128mS oder 127mS die Farbe oder Helligkeit wechseln lässt, ist ziemlich unwichtig und keiner wird es merken. Ich lasse meine BAM mit etwa 1KHz laufen (1012Hz, um genau zu sein), da habe ich auch gleichzeitig einen Timer für mSec. Natürlich kann man es auch genauer machen - Timer0 in CTC, Clock / 64, TOP auf 124, ganz schnell eine Variable in der ISR erhöhen und raus aus der ISR...
So, habe PWM jetzt mittels BAM implementiert, funktioniert super. Bin momentan jetzt dran, das ganze mittels MIBAM (mirrored BAM) zu verbessern, da ich irgendwo im Verlauf einen kurzen Helligkeitseinbruch habe. Jetzt soll das ganze Ding batteriebetrieben in ein kleines Gehäuse kommen. 2 Knöpfe soll es mindestens besitzen, einen zum Aus-/ und Einschalten, einen um den Farbverlauf in der aktuellen Position zu stoppen. Falls möglich soll es noch einen Modus-Umschalter geben, bei dem z.B. verschiedene Geschwindigkeiten ausgewählt werden können. Das mache ich alles via Interrupts, oder? Ist für das An-/ und Ausschalten der "power-down"-Modus geeignet? Gibt es abgesehen von int0 und int1 noch weitere Ports, die im laufenden Betrieb einen Interrupt z.B. für den Moduswechsel auslösen können? Viele Grüße ;)
jna380 schrieb: > da ich irgendwo im Verlauf einen kurzen Helligkeitseinbruch > habe. Das Updaten der PWM-Daten muß in mit der letzten Bitzeit erfolgen.
jna380 schrieb: > Bin momentan jetzt dran, das ganze mittels MIBAM (mirrored BAM) zu > verbessern, da ich irgendwo im Verlauf einen kurzen Helligkeitseinbruch > habe. Wie schnell ist deine BAM ? Mit 500Hz und schneller merkt man das überhaupt nicht, es sei denn, du wechselst ständig zwischen 128 und 127. Dann scheint es als ob die LED mit etwa 170 angesteuert wird. Aber wie oft wird das passieren und wie lange wird das dauern ? Es ist mehr eine theoretische als eine praktische Frage. Der Aufwand lohnt sich bestimmt nicht. EDIT: peda's BAM läuft mit 2 KHz, da hast du es bestimmt nicht gemerkt.
:
Bearbeitet durch User
Die Berechnung der neuen Werte erfolgt ständig mittels while(1) und delay in der main(). In Gewissen Zeitabständen je nach Gewichtung der bits startet dann eine ISR, die die Ausgänge entsprechend des aktuellen bits setzt. Die Berechnung erfolt also ständig, wird nur immer durch die ISR unterbrochen...das sollte ja dann kein Problem sein, oder? Zur Frequenz...ehrlich gesagt bin ich mir nicht ganz sicher. Der Timer läuft mit Prescaler 1/8, also 1 MHz. Mein gesamter Durchlauf für alle bits benötigt 20461 Timer-ticks (10-bit, Faktor 20), damit ergibt sich dann eine Wiederholungsrate von "nur" knapp 49 Hz. Oder mach ich einen Denkfehler? Sieht trotzdem sehr flüssig aus.
jna380 schrieb: > Gibt es abgesehen von int0 und int1 noch weitere Ports, die im laufenden > Betrieb einen Interrupt z.B. für den Moduswechsel auslösen können? Nein. Nimm M88, dann hast du an jedem Pin ein Interrupt. Muss aber nochmals meinen Senf zu MIBAM zugeben: |_______|-------|-------|_______| | 0 1111111| 1 0000000| | 127 | 128 | | 250uS 250uS | 250uS 250uS Anstatt 250uS Off - 250uS On - 250uS Off - 250 uS On, hat man 250uS Off - 500uS On - 250uS Off. Wegen Trägheit des Auges wird das aber als ein Wert von... ? Genau, es wird als ein Wert von 128 empfunden. Schlimmstenfalls wird es für 750uS als ein Wert von 170 empfunden. Da das menschliche Auge pro Sekunde maximal 30 Lichtreize voneinander unterscheiden kann (und zwar nur als nervöses Flackern), ist das mit MIBAM nur für PWM-Frequenzen unter 100Hz interessant... Selbstverständlich kann man auch kürzere Impulse sehen - Impulse mit einer Länge von etwa 75mS werden sogar als doppelt so hell empfunden. Danach muss aber eine Pause folgen, ansonsten geht der Effekt verloren...
Ahh, okay, gut zu wissen! Du kennst dich ja aus... Was genau ist M88? Konnte da beim googlen kaum was finden. Hab jetzt aber schon öfter gelesen, dass Taster an Interrupt-Ports wohl überhaupt nicht gut sind wegen dem Prellen. Wie mache ich das denn dann, wenn ich einen Tastendruck abfragen will, ohne diesen ständig im Programm zu überwachen? Momentan war mein erster Ansatz eine "state"-Variable, die durch Interrupts gesetzt wurde, und in der main() dann mittels switch etwas unterschiedliches ausgeführt wurde...funktioniert aber nicht wie es soll.
jna380 schrieb: > Was genau ist M88? Konnte da beim googlen kaum was finden. MEGA88 = MEGA8 Nachfolger.
jna380 schrieb: > Hab jetzt aber schon öfter gelesen, dass Taster an Interrupt-Ports wohl > überhaupt nicht gut sind wegen dem Prellen. Wie mache ich das denn dann, > wenn ich einen Tastendruck abfragen will, ohne diesen ständig im > Programm zu überwachen? Also, ganz ohne überwachen wirds wohl kaum gehen... Ich habe das früher so gemacht (wow, lange nicht mehr gemacht), dass ich in der ISR ( PCIx heist es bei M88), einen Flag gesetzt habe und Zähler für Prellen auf 50 gesetzt habe (mein Systemzähler läuft immer mit 1mS). Beim Eintritt in die ISR wird zuerst geprüft, ob der Zählerstand > 0mS ist (Zähler fürs Prellen läuft rückwarts bis Null). Wenn ja, wird einfach zum ISR-Ende gesprungen. Wenn nein, handelt es sich wahrscheinlich um einen neuen Tastendruck. Nachdem dein Tastendruck abgearbeitet ist, Flag wieder zurücksetzen. jna380 schrieb: > Momentan war mein erster Ansatz eine "state"-Variable, die durch > Interrupts gesetzt wurde, und in der main() dann mittels switch etwas > unterschiedliches ausgeführt wurde...funktioniert aber nicht wie es > soll. Probiere es mal wie oben. jna380 schrieb: > Ahh, okay, gut zu wissen! Du kennst dich ja aus... Habs auch erst kürzlich im Forum gelesen, musste es aber gleich ausprobieren. Da war von 50mS die Rede, bei mir waren es so um 75mS, ist aber natürlich subjektive Empfindung.
Marc Vesely schrieb: >> Und dann lade ich mir im nächsten 128ms-delay zB. den Wert 204 rein? > > Wie kommst du überhaupt auf 128mS ? Er schrieb von Millisekunden, wie kommst Du jetzt auf Millisiemens? Das würde ja jetzt 8 Ohm entsprechen. Marc Vesely schrieb: > | 250uS 250uS | 250uS 250uS > Anstatt 250uS Off - 250uS On - 250uS Off - 250 uS On, hat man > 250uS Off - 500uS On - 250uS Off. Wegen Trägheit des Auges wird > das aber als ein Wert von... ? Was hat die Trägheit des Auges hier im Zusammenhang mit dem Leitwert zu tun. Und wo bekommst Du den Leitwert her?
Gaestchen schrieb: > Er schrieb von Millisekunden, wie kommst Du jetzt auf Millisiemens? Das Gaestchen mit seinem Gehirnchen. Wieder einmal zu feige, um deinen richtigen Namen zu schreiben ? Was bringt dich zu der idiotischen Annahme, dass deine IP-Adresse als Gast nicht rübergekommen ist ?
:
Bearbeitet durch User
Versteh ich auch nicht, warum es immer Leute gibt die derart spitzfindig sein müssen. @Marc, Ich habe sehr gut verstanden was du mir sagen wolltest, und bin ziemlich dankbar dafür dass sich jemand die Mühe macht und mir weiterhilft. Muss man wohl einfach ignorieren... Danke für den Hinweis mit dem Zähler, ich teste das ;)
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.