Forum: Mikrocontroller und Digitale Elektronik 3x LED-PWM-Faden


von jna380 (Gast)


Lesenswert?

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

von hawk (Gast)


Lesenswert?

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

von Maik S. (yellowbird)


Lesenswert?

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

von jna380 (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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"

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?


von hawk (Gast)


Lesenswert?

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

von jna380 (Gast)


Lesenswert?

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! ;)

von hawk (Gast)


Lesenswert?

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

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von c-hater (Gast)


Lesenswert?

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

von Axel S. (a-za-z0-9)


Lesenswert?

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

von San L. (zwillingsfreunde)


Lesenswert?

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 ;)

von jna380 (Gast)


Lesenswert?

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

von Axel S. (a-za-z0-9)


Lesenswert?

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

von San L. (zwillingsfreunde)


Lesenswert?

Vielleicht als weitere Anregung:

Externer Baustein für PWM verwenden.

PCA9685 Beispielsweise.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

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.

von G T M. (gt_m)


Lesenswert?

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
von jna380 (Gast)


Lesenswert?

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

von jna380 (Gast)


Lesenswert?

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...

von hawk (Gast)


Angehängte Dateien:

Lesenswert?

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

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von jna380 (Gast)


Lesenswert?

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?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

jna380 schrieb:
> if(TCNT1 >= next)
>  next = values[i];


  Ooops.
  next ist 8-bit.
  values sind 16-bit.
  Timer1 ist 16-bit.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von jna380 (Gast)


Lesenswert?

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...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von jna380 (Gast)


Lesenswert?

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?

von Hawk (Gast)


Lesenswert?

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

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Angehängte Dateien:

Lesenswert?

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...

von MaWin (Gast)


Lesenswert?

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.

von MaWin (Gast)


Lesenswert?

ups, falscher thread, wo sind denn die 7 x 7 RGB geblieben...

von N. Rokpop (Gast)


Lesenswert?

Warum denn Bit-Angle-Modulation und nicht Sigma-Delta? Ist vom Aufwand 
her nicht schlimmer, flimmert dafür aber weniger...

von Michael K. (tschoeatsch)


Angehängte Dateien:

Lesenswert?

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

von N. Rokpop (Gast)


Lesenswert?

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.

von Michael K. (tschoeatsch)


Lesenswert?

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
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von Gaestchen (Gast)


Lesenswert?

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.

von jna380 (Gast)


Lesenswert?

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?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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...

von jna380 (Gast)


Lesenswert?

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 ;)

von Peter D. (peda)


Lesenswert?

jna380 schrieb:
> da ich irgendwo im Verlauf einen kurzen Helligkeitseinbruch
> habe.

Das Updaten der PWM-Daten muß in mit der letzten Bitzeit erfolgen.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von jna380 (Gast)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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...

von jna380 (Gast)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

jna380 schrieb:
> Was genau ist M88? Konnte da beim googlen kaum was finden.

 MEGA88 = MEGA8 Nachfolger.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Gaestchen (Gast)


Lesenswert?

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?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von jna380 (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.