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
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.
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").
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_tvalues[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_tnext=0;
13
uint8_ti=0;
14
15
intmain(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
return0;
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.
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:> 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...
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.
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
intmain(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
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.
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
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...
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:> 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.
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:> 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 ?
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 ;)