Forum: Mikrocontroller und Digitale Elektronik AVR RGB-LED PWM MUX


von Roberto (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
habe vor mein Zimmer mit RGB-LEDs zu beleuchten, habe dem entsprechend 
auch schon so ziemlich alle Beiträge gelesen die es hier gibt...

Das was ich anders habe als bei den anderen Projekten ist, das ich pro 
LED (rgb) ein Poti habe der an jeweils an einem AD-Wandler hängt.
Danach soll der Wert (1:1) als PWM wieder ausgegeben werden, aber nur 
auf einem PWM-Port. Ein MUX schaltet zwischen den 3 LEDs.

Habe das soweit auch alles geschafft. Mein Problem ist, dass wenn ich 
einen Poti hochdrehe, ab einer gewissen Stelle eine andere LED mit 
aufleuchtet, obwohl ich den Poti dazu garnicht verändert habe....

Habe dann erstmal die Potis und den AD-Wandler weggelassen um zu 
überprüfen ob es vielleicht am MUX liegt und alle LEDs mit einem festen 
wert über den MUX angesteuert, aber der hat seine arbeite richtig getan!
Daher denke ich das es irgendwie an den AD-Wandlern liegt?!

Benutze übrigens einen ATMega16 dafür mit 12Mhz

Hoffe ich konnte mein Problem soweit gut erklären....

Grüße
Roberto

von Gast (Gast)


Lesenswert?

Äh, "PWM multiplexen", wie soll das gehen?
Wenn Du ein PWM signal per Multiplexer an die LEDs
weitergibst wirst Du nie 100% Helligkeit erreichen.
Oder verstehe ich Dich falsch?
Schick mal Deinen Schaltplan.

von so vieleicht besser (Gast)


Lesenswert?

PORTA = pwm[pwm_count];
  cli();
  OCR1BL = werte[pwm_count][0];
  OCR1BH = werte[pwm_count][1];
  pwm_count++;
  if(pwm_count > 2) pwm_count=0;
  sei();

von Roberto (Gast)


Lesenswert?

Naja, also das mit der Helligkeit ist sicher richtig, aber macht sich 
nicht soo bemerkbar
Also wie gesagt, am Multiplexer liegt das nicht....
Leider geht trotzdem noch die eine LED mit an, wenn ich den Poti einer 
anderen LED hochdrehe....
Weiß jemand woran es liegt und was ich dagegen tun kann?

von Falk B. (falk)


Lesenswert?

@  Roberto (Gast)

>Weiß jemand woran es liegt und was ich dagegen tun kann?

Dein Programm ist sehr merkwürdig.

cli() und sei() in einer ISR ist ziemlich sinnlos bis gefährlich.
Dein Umschaltung der AD-MUX ist falsch. Das muss eher heissen.

BYTE ad[3] = {0, 1, 2};      //AD-Wandler

Denn nur so misst du nacheinander den ADC-Kanal 0, 1, und 2.
Das mmit einem Array zu machen ist aber wie man sieht eher sinnlos.
Das merkwürdige trennen von   ad_count++; und der Überlaifprüfung ist 
keine gute Idee, spätestens wenn deine Programme grösser werden schiesst 
du dir damit ins Knie.
Seinen eigenen Datentyp Byte zu erfinden ist Unsinn, schau dir mal 
stdint.h an, dort ist alles schön und standardisiert verfügbar.

Probiers mal so
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
//Globale Variablen
5
uint8_t pwm_count, ad_count, werte[3][2];
6
uint8_t pwm[3] = {0, (1<<PA3), (1<<PA4)};  //Ports f?r LED-MUX
7
8
//PWM-Interrupt
9
ISR(TIMER1_COMPB_vect) {
10
11
  PORTA = pwm[pwm_count];
12
  OCR1BL = werte[pwm_count][0];
13
  OCR1BH = werte[pwm_count][1];
14
  pwm_count++;
15
  if(pwm_count > 2) pwm_count=0;
16
}
17
18
19
//AD-Interrupt
20
ISR(ADC_vect)
21
{
22
  werte[ad_count-1][0] = ADCL;
23
  werte[ad_count-1][1] = ADCH;
24
  ADMUX = ad_count;
25
  ADCSRA |= (1<<ADSC);
26
  ad_count++;
27
  if(ad_count > 2) ad_count = 0;
28
}
29
30
int main()
31
{
32
33
  //Richtungskonfiguration der Ports
34
  DDRA = (1<<PA3) | (1<<PA4);  //Port A 3/4 als Ausgang f?r MUX definieren
35
  DDRD = (1<<PA4);        //PWM Port OC1B
36
37
38
  ad_count = 1;
39
  pwm_count = 1;
40
  
41
  //PWM OC1B gew?hlt mit 10 Bit, Vorteiler 1 f?r PWM OC1B
42
  TCCR1A = (1<<WGM11) | (1<<WGM10) | (1<<COM1B1) | (1<<COM1B0);
43
  TCCR1B = (1<<CS10) | (1<<WGM12);
44
  
45
  TIMSK = (1<<OCIE1B);      //Interrupt einschalten
46
  
47
  
48
  //Vorteiler bei 12 MHz auf 187.5 kHz stellen, Interrupt ausl?sen wenn fertig, Wandler einschalten
49
  ADCSRA = (1<<ADIE) | (1<<ADPS2) | (1<<ADEN);
50
  
51
  
52
  sei();              //Interrupts allg. aktivieren
53
  
54
  
55
  ADMUX = ad[0];          //AD-Wandler 0 w?hlen, ADLAR=0
56
57
  ADCSRA |= (1<<ADSC);      //AD-Wandlung starten
58
59
  OCR1BH = 0x00;
60
  OCR1BL = 0x00;
61
  
62
  PORTA = pwm[0];
63
64
  //Unendlich-Schleife
65
  
66
  while(1)
67
  {}
68
  
69
  return 0;
70
}

MFG
Falk

von Robert L. (robertino)


Lesenswert?

@Falk: Vielen Dank, aber leider hat sich an dem Problem damit nicht 
verabschiedet :(
Aber der Quellcode ist schonmal etwas kleiner geworden...

Hab eben mal das Oszilloskop an die Stuerports vom MUX getan, und nun 
weiß ich denk ich woran es liegt, aber nicht wie ich es beheben kann.
Und zwar habe ich die PWM invertiert laufen, "Top" heißt das meine ich, 
also so das wenn ich ne 0 drauf gebe der 5V ausgibt und bei 255 (8 Bit) 
dann 0V (RGB-LED hat gemeinsame Anode)
Also wenn ich nun an das Poti hochdrehe, wird dadurch ja das Signal des 
PWMs immer kleiner, und irgendwann dann mal so klein, das der MUX es 
nicht mehr schafft mitzu schalten....
Das war meine Überlegung, kann das sein?
Wenn das richitg ist, was könnte ich dagegen tun?

Grüße und vielen dank (schonmal) an alle!!!

von Gast (Gast)


Lesenswert?

Eben, ein PWM Signal zu Multiplexen ist quatsch...
Welchen Vorteil versprichst Du Dir davon?
Bitte poste doch mal Deinen Schaltplan.

von Robert L. (robertino)


Lesenswert?

Wieso sollte das quatsch sein?
Wenn man nur einen PWM-Port zur verfügung hat ist das doch ne top sache!
Das läuft zZt ja nur auf dem Mega16, soll aber später auf dem Tiny2313 
(vormals AT90S2313) laufen, und der hat nur einen PWM.

von Robert L. (robertino)


Angehängte Dateien:

Lesenswert?

Der Lageplan

von Jens W. (dermoench)


Lesenswert?

eine alternative wäre Soft-PWM:
http://www.mikrocontroller.net/articles/Soft-PWM

von Falk B. (falk)


Lesenswert?

@ Gast (Gast)

>Eben, ein PWM Signal zu Multiplexen ist quatsch...

Nöö, das passt schon. Sowas macht man auch, wenn man eine LED-Matrix 
dimmen will. Been there, done that.

MFg
Falk

von Falk B. (falk)


Lesenswert?

@ Roberto Leonardi (robertino)

>Dateianhang: Plan.JPG (18,2 KB, 2 Downloads)

Mal abgesehen vom Hinweis auf Bildformate, sind solche 
hingeschmierten Schaltpläne nicht sehr viel wert. Hast du das dritte 
MUX-Eingangspin fest auf 0V gelegt? Und auch alle anderen Eingänge auf 
festes Potential?

MFG
Falk

von Robert L. (robertino)


Lesenswert?

Weiß das das nicht viel Sinn macht, hatte eigentlich auch nicht vor 
dieses hier hochzuladen, da es einfach ein zu simpler Schaltplan ist...
Ja, alle anderen Pins liegen auf festem Potential.

von Gast (Gast)


Lesenswert?

Ok, Muxen macht Sinn, wenn man zu Anzeigezwecken eine
RGB LED ansteuern will.

Aber für den genannten Zweck der Zimmerbeleuchtung gehe ich
davon aus, dass man die volle Leistung der LEDs ausnutzen will / muss.

Und ab hier macht das Multiplexen meiner Meinung nach
keinen Sinn mehr, da man ja nie eine 100% An-Phase je LED
realisieren kann.

Jede einzelne RGB LED ist also max. 1/3tel der Zeit an.
Um dies zu kompensieren müsstest Du in den An-Phasen den Strom 
entsprechend erhöhen. Ob dies einer Power LED (alles andere macht
für eine Zimmerbeleuchtung imo keinen Sinn) so zuträglich ist?

Da Dein Kontroller ja vermutlich nicht mehr viel mehr macht als das
RGB PWM Signal zu erzeugen, überlege Dir ob Du nicht eine Soft PWM 
realisierst.

Grüße

von Robert L. (robertino)


Lesenswert?

Hm ja, das habe...das hört sich gut an, allerdings habe ich noch nicht 
ganz verstanden wie das funktioniert...werd ich mich wohl mal reinlesen
Wieso ist denn eine LED beim Multiplexen max nur 1/3tel an? Der MUX 
wartet ja bis das Signal komplett rüber ist und schaltet dann erst um. 
Und das bei 12MHz, da drüfte es doch keine Verluste geben, oder doch?

Vielen Dank für euren gazen Beiträge!

von Falk B. (falk)


Lesenswert?

@  Roberto Leonardi (robertino)

>Wieso ist denn eine LED beim Multiplexen max nur 1/3tel an?

Das ist das Prinzip von Multiplexen, siehe auch LED-Matrix.

>Und das bei 12MHz, da drüfte es doch keine Verluste geben, oder doch?

;-)
Denk mal in RUHE drüber nach und nicht solche Schnellschüsse aus der 
Hüfte.

MfG
Falk

von Sven H. (Gast)


Lesenswert?

Dein Problem liegt im Prinzip der A/D Wandlung:
Du schaltest den Kanal des A/D Mux um und liest direkt danach den Wert 
des Kanals ein!
Das funktioniert nicht, da im A/D Wandler sich die Sample & Hold 
Schaltung erstmal umladen muss,
bis du den A/D Vorgang starten darfst.

Beispiel:
Poti 1: 5V
Poti 2: 0V

Zuerst hat sich der Kondensator auf 5V geladen. Anschliessend soll er 
sich in einem
Taktzyklus sofort auf 0 Volt entladen? Das kann nicht funktionieren. 
Deshalb wird ein
Wert bei ca. 1V o.ä. eingelesen.
Schau dir mal das Datenblatt zum Prozessor an. Dort sind die Timings 
beschrieben!

von Robert L. (robertino)


Lesenswert?

@ Falk
Ah ok....jetzt hab ichs auch ;)


@ Sven
Ich habe mir irgendwie schon immer gedacht das es an den AD-Wandlern 
liegt...könnte ich das Problem denn dann so lösen, das ich da einfach 
ein delay reinbastel im Interrupt vom AD-Wandler?

von Falk B. (falk)


Lesenswert?

@ Roberto Leonardi (robertino)

>liegt...könnte ich das Problem denn dann so lösen, das ich da einfach
>ein delay reinbastel im Interrupt vom AD-Wandler?

Patsch
Delays haben im Interrupt nichts zu suchen!

Einfach den ADC richtig ansteuern und es läuft. Den Interrupt brauchst 
du dazu nicht. Lies den ADC ohne interrupt in der Hauptschleife aus, 
dort ist dann ausnahmsweise auch ein Delay zulässig.

MFG
Falk

von Falk B. (falk)


Lesenswert?

@  Sven H. (Gast)

>Du schaltest den Kanal des A/D Mux um und liest direkt danach den Wert
>des Kanals ein!

Nöö, er list das Ergebnis der letzten Umwandlung ein. Was wahrscheinlich 
fehlt ist ein Kondensator von 2..100nF an dem AD-Eingangspin.

MfG
Falk

von Gast (Gast)


Lesenswert?

Bei eine Soft PWM erzeugst Du softwaregesteuert die
jeweiligen Signale an drei Pins, je ein Pin pro
LED. Da das Auge recht träge ist reicht imo eine
PWM Cycle Frequenz von z.B. 100hz, vermutlich auch weniger,
dann kann es aber vorkommen, dass das Auge bei Bewegung
ein Flackern wahrnimmt.
Dass heißt, dass Du immer dann einen Timer Interrupt
auslösen musst, wenn sich einer der PWM Ausgangszustände
ändern soll. Im Interrupt änderst Du dann den Zustand des Pins.
Außerdem berechnest Du die Zeit bis zum nächsten Wechsel und
setzt den Timer entsprechend.

                           1    1
            2    5       9 0    2
t(ms)  0    5    0       0 0    5 usw
        ___                ___
R _____|    |______________|    |______________ 25%

        ________           ________
G _____|         |_________|         |_________ 50%

        ________________   ________________
B _____|                 |_|                 |_ 90%


Das Abtasten der AD Eingänge kannst Du sogar noch deutlich
langsammer machen z.B. nur alle 200ms und die Werte in globale
Variablen speichern. Damit hast Du insgesamt recht entspannte
Verhältnisse und bekommst 100% LED Power je LED und hast
keine Probleme mit der AD Wandlung der Potispannungen.

Grüße

von Gast (Gast)


Lesenswert?

Und das ganze spart dann auch noch den Multiplexer...

von Robert L. (robertino)


Lesenswert?

@ Gast
Das hört sich gut an...dann werd ich das wohl mal testen!
Meld mich bei Problemen wieder ;)
Vielen Dank

@Falk
Hab einen Kondensator und eine Spule am Aref Pin, wie es im Datenblatt 
es Mega16 drin steht....
Soll ich pro Poti einen 100nF C dran tun, oder wie?

von Falk B. (falk)


Lesenswert?

@ Roberto Leonardi (robertino)

>Soll ich pro Poti einen 100nF C dran tun, oder wie?

Ja.

von Robert L. (robertino)


Lesenswert?

Hm...
wegen dem TP-Verhalten?
Meine da liegt ja eigentlich nur Gleichspannung an....

von Sven H. (Gast)


Lesenswert?

@Falk:

  ADMUX = ad_count;
  ADCSRA |= (1<<ADSC);


Das beißt sich direkt untereinander!

von Sven H. (Gast)


Lesenswert?

(Da gehe ich jede Wetter drauf ein, dass das Problem darin liegt)

von Robert L. (robertino)


Lesenswert?

Was soll ich denn sonst dazwischen machen? Leerzeilen?

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.