AVR RGB-LED PWM MUX

Gast #1031062
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
Angehängte Dateien:
Gast #1031611
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?
#1031699
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
#1031740
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!!!
Gast #1033285
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
#1033366
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!
Gast #1033404
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!
#1033436
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
Gast #1033452
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren