Forum: Mikrocontroller und Digitale Elektronik Soft PWM für LED Controller (RGB mit Multifunktion)


von Phillip V. (phillip_v)


Lesenswert?

Hallo,

zuerst einmal: Ich bin blutiger Neuling, habe nur wenig C-Erfahrung aber 
kann andere Programmiersprachen (Pascal, Delphi, Java).
Die grundlegenen Prinzipien sind bekannt, die AVR-GCC Doku sowie die 
diversen Foreneinträge und Tutorials zu Soft-PWM und LED-Steuerung 
wurden gelesen und nachvollzogen.

Ich habe eine diffuse Frage, für das Design meines µC-Codes.

Ich will mit einem Mega8 über die IO-Pins PB0 bis PB2 jeweils die 
MOSFETs ansteuern, welche die Betriebsspannung der parallelgeschalteten 
LEDs durchschalten. Alle LEDs haben eine gemeinsame Anode, die Kathoden 
sind jeweils kanalweise zusammen (parralel) geschaltet.

Ich möchte einen Controller Code erstellen, der sowohl
- die Leuchtstärke der LEDs getrennt nach Kanal dimmen kann
- die Farbzusammenstellung über drei Kanäle (RGB) ermöglicht
- auf Taster (6 Stück) reagiert und je Taster ein spezielles 
Farb-Szenario abspielt (bspw. einfach weiß, rot oder grün sowie ein 
definierter Farbverlauf).

Ich arbeite mit dem AVR Studio und dem Mega8.

Könnt ihr mir bitte folgende Fragen beantworten:

1. Kann ich mein Szenario überhaupt unter Nutzung einer gemeinsamen ISR 
abbilden? Ich stelle mir vor, dass ich der ISR jeweils das gewünschte 
Farbprogramm/Pattern übergebe, und die Routine dann daraus in einer 
verschachtelten Logik die PWM erzeugt und am PORTB ausgibt.

2. Muss ich je Farbkanal einen eigenen PWM Channel einsetzen? Das gibt 
dann wohl Probleme, da der Mega8 zwar 3 Channels hat, die Timer aber 
unterschiedliche Leistungsbereiche haben (8-/16-bit, ...).

3. Da mir jede Vorerfahrung fehlt. Ist das mit dem Mega8 überhaupt 
leistbar (Rechenpower). Ich will kein Blinken sehen, weil der Prozessor 
zu viel zu rechnen hat.

Ich würde mich über nachsichtige und konstruktive Kommentare und 
Hilfestellungen freuen.

VG Phillip

von ahlol (Gast)


Lesenswert?

soft-pwm wäre ohne timer, "normales" pwm ist aber mit timern.

welches hättest du denn gerne? ;-)

Rechenleistung sollte übrigens genug da sein.

Zu den Mosfets: beachte dass normale mosfets mind. 10V zum ganz 
durchschalten brauchen, der µC aber nur 5V maximal ausgibt. Du solltest 
deshalb typen verwenden die auch mit den 5V TTL Spannung zurechtkommen

von Phillip V. (phillip_v)


Lesenswert?

ahlol schrieb:
> soft-pwm wäre ohne timer, "normales" pwm ist aber mit timern.
>
> welches hättest du denn gerne? ;-)
Zur schönen hardware-/Timer-PWM fehlen mir drei gleiche Timer, stimmt's? 
Dann also wohl soft-pwm.

> Rechenleistung sollte übrigens genug da sein.
Gut zu wissen. Will trotzdem mind. halb-effizient coden.

> Zu den Mosfets: beachte dass normale mosfets mind. 10V zum ganz
> durchschalten brauchen, der µC aber nur 5V maximal ausgibt. Du solltest
> deshalb typen verwenden die auch mit den 5V TTL Spannung zurechtkommen
Meine MOSFETs : Leistungs-MOSFET N-Ch TO-220AB 55V 110A (reichelt: IRF 
3205)

LG Phillip

von Floh (Gast)


Lesenswert?

Phillip V. schrieb:
> Gut zu wissen. Will trotzdem mind. halb-effizient coden.

Das ist erst mal egal, erst muss es laufen.
Hast du schon ein genaueres Konzept, wie du das PRogramm aufbaust?

> Meine MOSFETs : Leistungs-MOSFET N-Ch TO-220AB 55V 110A (reichelt: IRF
> 3205)
Absoluter Overkill :-) Wieviele LEDs willst du den betreiben?
Übrigends, ich hoffe du hast in jedem LED-Zweig einen Vorwiderstand?
:-)

von Phillip V. (phillip_v)


Lesenswert?

Floh schrieb:
> Das ist erst mal egal, erst muss es laufen.
> Hast du schon ein genaueres Konzept, wie du das PRogramm aufbaust?

Nee, hab in C echt wenig Erfahrung. Mein Konzeptproblem liegt im Dilemma 
zwischen Schleifenbody, welcher die LEDs ansteuert und der 
"Erreichbarkeit" des Umschaltens durch die Taster.

>> Meine MOSFETs : Leistungs-MOSFET N-Ch TO-220AB 55V 110A (reichelt: IRF
>> 3205)
> Absoluter Overkill :-) Wieviele LEDs willst du den betreiben?
> Übrigends, ich hoffe du hast in jedem LED-Zweig einen Vorwiderstand?

Die LEDs haben 12V Betriebsspannung mit integriertem Vorwiderstand. Es 
sind je Kanal ca. 30 LEDs. Etwa 2A Strom in Gänze.

von Floh (Gast)


Lesenswert?

Phillip V. schrieb:
> Nee, hab in C echt wenig Erfahrung. Mein Konzeptproblem liegt im Dilemma
> zwischen Schleifenbody, welcher die LEDs ansteuert und der
> "Erreichbarkeit" des Umschaltens durch die Taster.

Jo, das ist nicht so toll.
Mein Tip wäre ein Timer-Interrupt, in dem die ganze PWM-Geschichte 
abgehandelt wird, dann ist dein Hauptprogramm davon frei.

Würde das so angehen:
Timer-Interrupt auf ca. 30 Hz * 256 ist ungefähr 8 kHz einstellen.

Im Interrupt siehts dann so aus:

Interrupt:
  8bit Zähler erhöhen
  Wenn Zähler > Stellwert rot
    rot an
  ansonsten
    rot aus
  Wenn Zähler > Stellwert grün
    grün an
  ansonsten
    grün aus
  Wenn Zähler > Stellwert blau
    blau an
  ansonsten
    blau aus
Interrupt ende

Im Hauptprogramm kannste dann über die Stellwerte die Farben verändern.
:-)

von Phillip V. (phillip_v)


Lesenswert?

Floh schrieb:
> Im Hauptprogramm kannste dann über die Stellwerte die Farben verändern.

Super soweit! Nur wie steuer ich dann im Hauptprogramm den Verlauf 
zwischen zwei farben "sanft" ein? Mit _delay_ms() ?

von Falk B. (falk)


Lesenswert?

Siehe Soft-PWM und LED-Fading.

MFG
Falk

von Philipp B. (philipp_burch)


Angehängte Dateien:

Lesenswert?

Hallo Phillip,

das Beschriebene Vorgehen ist sowas wie die Brute-Force-Möglichkeit. Das 
funktioniert zweifellos und wird in Hardware auch so gemacht, hat bei 
Software-PWM jedoch eine erhebliche CPU-Last zur Folge. In Soft-PWM 
steht beschrieben, wie man das wesentlich effizienter implementieren 
kann. Leider ist die dortige Version nur für acht Bit ausgelegt, was zum 
schönen Faden unter Umständen nicht reicht. Ausserdem hat sie noch ein 
paar andere "Unschönheiten", beispielsweise bei der Synchronisation 
mittels busy-wait...
Eine etwas aufgemotzte Variante findest du im Anhang. Das scheint alles 
zu funktionieren, dennoch möchte ich das Teil noch etwas ausgiebiger 
testen, bevor ich es als Alternative in den Artikel schreibe. Daher: 
Feedback/Kritik erwünscht!

Gruss,
Philipp

von Phillip V. (phillip_v)


Lesenswert?

Philipp Burch schrieb:
> Hallo Phillip,
>
> das Beschriebene Vorgehen ist sowas wie die Brute-Force-Möglichkeit. Das
> funktioniert zweifellos und wird in Hardware auch so gemacht, hat bei
> Software-PWM jedoch eine erhebliche CPU-Last zur Folge. In Soft-PWM
> steht beschrieben, wie man das wesentlich effizienter implementieren
> kann. Leider ist die dortige Version nur für acht Bit ausgelegt, was zum
> schönen Faden unter Umständen nicht reicht. Ausserdem hat sie noch ein
> paar andere "Unschönheiten", beispielsweise bei der Synchronisation
> mittels busy-wait...
> Eine etwas aufgemotzte Variante findest du im Anhang. Das scheint alles
> zu funktionieren, dennoch möchte ich das Teil noch etwas ausgiebiger
> testen, bevor ich es als Alternative in den Artikel schreibe. Daher:
> Feedback/Kritik erwünscht!
>
> Gruss,
> Philipp

Hi,

wie Dimme ich mit nur einer ISR die drei Kanaele separat?
LG Phillip

von Philipp B. (philipp_burch)


Lesenswert?

Phillip V. schrieb:
> Hi,
>
> wie Dimme ich mit nur einer ISR die drei Kanaele separat?
> LG Phillip

Na indem du mittels set_pwm(...) verschiedene Werte für die drei Kanäle 
übergibst. Um die ISR brauchst du dich gar nicht zu kümmern, die wird 
automatisch konfiguriert. Du darfst einfach nicht vergessen, nach dem 
ändern der Kanalwerte (set_pwm()) noch pwm_update() aufzurufen, sonst 
werden die neuen Werte nicht übernommen.

von Phillip V. (phillip_v)


Lesenswert?

Philipp Burch schrieb:
> Na indem du mittels set_pwm(...) verschiedene Werte für die drei Kanäle
> übergibst. Um die ISR brauchst du dich gar nicht zu kümmern, die wird
> automatisch konfiguriert. Du darfst einfach nicht vergessen, nach dem
> ändern der Kanalwerte (set_pwm()) noch pwm_update() aufzurufen, sonst
> werden die neuen Werte nicht übernommen.

Also so in der Richtung, ja?
1
#define F_CPU 8000000L
2
#define PWM_STEPS 255
3
4
#include<avr/io.h>
5
#include<util\delay.h>
6
#include<inttypes.h>
7
#include<avr/pgmspace.h>
8
9
/* Variablendeklaration */
10
uint16_t colorvalue[256] PROGMEM = {0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,
11
                  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,
12
                  3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,5,5,5,
13
                  5,5,5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7,7,7,8,8,8,
14
                  8,8,8,9,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,
15
                  12,13,13,13,13,14,14,14,15,15,15,16,16,16,17,17,
16
                  17,18,18,19,19,19,20,20,21,21,22,22,23,23,24,24,
17
                  25,25,26,26,27,28,28,29,29,30,31,31,32,33,34,34,
18
                  35,36,37,37,38,39,40,41,42,43,44,45,46,47,48,49,
19
                  50,51,52,53,54,55,57,58,59,60,62,63,65,66,67,69,
20
                  70,72,74,75,77,79,80,82,84,86,88,89,91,93,96,98,
21
                  100,102,104,107,109,111,114,116,119,121,124,127,
22
                  130,133,135,138,141,145,148,151,154,158,161,165,
23
                  168,172,176,180,184,188,192,196,201,205,210,214,
24
                  219,224,229,234,239,244,249,255,255};
25
26
27
28
/* Prozeduren und Hilfsroutinen */
29
30
void initialize() {
31
  DDRB = 0x07; //DDR PORTB auf Ausgang
32
  // TIMER0 initialisieren
33
  // TIMER1 initialisieren
34
}
35
36
void mydelay(const unsigned int delay){
37
  uint8_t i = 1;
38
  if (delay >1) {
39
    for (; i < delay;i++) _delay_ms(1); }
40
   else
41
    _delay_ms(1);
42
}
43
44
45
void setRGB(uint16_t r, uint16_t g, uint16_t b) {
46
  volatile uint8_t pwmcnt;
47
  int port_value;
48
  for(pwmcnt=0;pwmcnt<PWM_STEPS;pwmcnt++) { 
49
    port_value = 0;
50
    if (r>=pwmcnt) port_value = (port_value+1); 
51
  if (g>=pwmcnt) port_value = (port_value+2); 
52
  if (b>=pwmcnt) port_value = (port_value+4); 
53
  PORTB = port_value; 
54
  }
55
}
56
57
/* Interrupt Serive Routinen */
58
59
60
61
62
63
64
/* Hauptprogramm */
65
66
int main() {
67
  initialize();
68
  setRGB(colorvalue[255],colorvalue[128],colorvalue[64]);
69
70
  return 0;
71
72
}

von Philipp B. (philipp_burch)


Lesenswert?

Phillip V. schrieb:
> Philipp Burch schrieb:
>> Na indem du mittels set_pwm(...) verschiedene Werte für die drei Kanäle
>> übergibst. Um die ISR brauchst du dich gar nicht zu kümmern, die wird
>> automatisch konfiguriert. Du darfst einfach nicht vergessen, nach dem
>> ändern der Kanalwerte (set_pwm()) noch pwm_update() aufzurufen, sonst
>> werden die neuen Werte nicht übernommen.
>
> Also so in der Richtung, ja?

Ähm... Nein?

Ich sehe nicht wirklich, was du mit deinem Code bezweckst. Dein setRGB() 
würde, wenn man es denn regelmässig aufrufen würde, zwar etwas Ähnliches 
wie ein PWM-Signal ausgeben, allerdings hängt der uC dann dauerhaft dort 
drin und tut überhaupt nichts anderes mehr. Zusätzlich hängt die 
Frequenz von den Kanalwerten und von den Einstellungen und Launen des 
Compilers ab.
Die Links und mein Code oben wurden nicht aus Jux und Tollerei gepostet, 
wenn du dir das Zeug wenigstens mal ansehen würdest, würde vielleicht 
eher ein Schuh draus.

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.