3 Phasen PWM (Verschoben)

Hallo,

Ich bin zurzeit an einem RGB-Würfel für ein Berufsschulprojekt am werkeln.
Da ich erst einen 3D-Drucker bauen wollte ist die meiste Zeit leider schon weg.
Habe mich dann entschieden in der restlichen Zeit noch einen RGB-Würfel zu bauen.

Ich habe mit meinem Ausbilder die Platinen designet und alles bestellt. In der Zwischenzeit habe ich mich schon mal an das Programm gemacht.

Zuerst habe ich die PWM selbst geschrieben mit einer Zählerabfrage & digitalWrite Befehlen.
Da das Programm langsam länger und länger wird ist mir aufgefallen das die 3 PWM Signale immer langsamer werden.
Warum das so ist, ist mir bewusst aber ich bekomme mit den analogWrite funktionen einfach keine Phasenverschiebung hin sodas die PWM über die Timer läuft und nicht im Programm selber.

Ich habe jetzt schon viele Stunden im Internet gesucht aber leider nichts gefunden & auf der arbeit kennt sich leider keiner so richtig mit Arduinos aus.(Ich selber habe leider auch zu wenig Ahnung dafür)

Fest steht ich brauche eine 3 Phasen PWM mit Phasenverschiebung sodas keine der drei Phasen zum gleichen Zeitpunkt an ist. Am besten wäre =

Periode(100%)=Phase1(30%)+Totzeit(~3%)+Phase2(30%)+Totzeit(~3%)+Phase3(30%)+Totzeit(~3%)

Laufen wird das ganze auf einem Mega 2560.

MfG
Alex T.

Eigentlich eine schöne Idee...

Nur leider ist mir kein AVR bekannt, welcher einen Timer hat, welcher solch eine 3 Phasen PWM mit Totzeiten, in Hardware, kann.

Vielleicht solltest du dich mal in der STM32 Familie umsehen.
Deren Timer sind erheblich leistungsfähiger.

Hallo,

wie meinst du das mit der Phasenverschiebung? Alle nacheinander wie dargestellt?
Pulszeit, kurze Totzeit, dann nächste Pulszeit usw. ... ?
Wenn ja dann hätte ich eine Idee.
Timer 1 im CTC Modus und in der ISR die Schaltlogik, also die Abfolge programmieren.
Der Compare-Wert wird für den nächsten Schaltpunkt (ISR) wird dann immer nur aufaddiert.
Wenn obige Annahme bzw. Darstellung stimmt.

Wieso brauchst Du ein solches 3fasiges Signal?
Grüße Uwe

Mit dem PCA9685 sollte das machbar sein.
ungetestet

Was ich in #2 sehe, erinnert mich an die Servo-Bibliothek:

#define MIN 40
#define MAX 2000

void setup() {
  sv1.attach(9, MIN, MAX);
  sv2.attach(10, MIN, MAX);
  sv3.attach(11, MIN, MAX);
}

In Servo.h

#define REFRESH_INTERVAL     6000

Ob das zum gewünschten Ergebnis führt, kann ich aber nicht versprechen, da mir der Sinn noch nicht einleuchtet.

Hallo,

jetzt wäre es an der Zeit das altou sein Vorhaben nochmal genauer erklärt. Am besten mit Skizze wie es wirklich sein soll. Sonst haben wir alle eine andere Vermutung was gemeint ist.

combie:
Eigentlich eine schöne Idee...

Nur leider ist mir kein AVR bekannt, welcher einen Timer hat, welcher solch eine 3 Phasen PWM mit Totzeiten, in Hardware, kann.

Vielleicht solltest du dich mal in der STM32 Familie umsehen.
Deren Timer sind erheblich leistungsfähiger.

combie:
Mit dem PCA9685 sollte das machbar sein.
ungetestet

Danke, das Problem ist die Platine ist schon bestellt und ich wüsste nicht wie ich den noch mit verwenden könnte.

Doc_Arduino:
Hallo,

wie meinst du das mit der Phasenverschiebung? Alle nacheinander wie dargestellt?
Wenn ja dann hätte ich eine Idee.
Timer 1 im CTC Modus und in der ISR die Schaltlogik, also die Abfolge programmieren.
Der Compare-Wert wird für den nächsten Schaltpunkt (ISR) wird dann immer nur aufaddiert.
Wenn die Annahme stimmt.

Danke, ja genau so soll es sein. Kannst du mir deine Lösung vielleicht etwas anfängerfreundlicher erklären ? Bin noch nicht so bewandert im programmieren. Hab auch schon bisschen im Datenblatt gelesen aber verstehen tu ich da leider nicht viel.

uwefed:
Wieso brauchst Du ein solches 3fasiges Signal?
Grüße Uwe

Undzwar haben wir uns das so gedacht das dauerhaft mit den 3 verschobenen Phasen (eine Phase für jede Frage) über ein Transistor die RGBs auf Masse gezogen werden. Dazu mit 4 Multiplexern 4:16 (da es ein 4x4x4 Würfel wird) immer die 5V mit den Phasen, je nach dem welche Farbe an gehen soll, geschalten werden.

Ah, Du willst die LED Multiplexen.
Da kannst Du kein PWM-Signal verwenden da die Ansteuerung der LED in einer Ebene mit der Ansteuerung der Ebenen synchronisiert sein muß.

Multiplexer für die Ansteuerung von Verbrauchern zu verwenden ist wenig ziehlführend da die Multiplexer immer nur 1 Ausgang mit dem gemeinsamen Kontakt verbinden und so immer nur 1 LED angesteuert werden kann. DU hast also einen 4x4x4 Würfel mit RGB LED mit gemeinsamer Anode. Die Kathoden der 3 Farben sind jeweis zusammengeschaltet (3 x 64 Kathoden) und die 64 Anoden der LED auf je einen Ausgang der 4 1:16 Multiplexer verbunden.
Das Funktioniert nie richtig (flimmerfrei und hell) da immer nur 4 der 192 LED (hier als Einzelfarbe genommen) angesteuert werden können und somit ein LED max 1/48-stel Sekunde leuchtet. Oder anders gesagt nur 2% der Zeit ist jedes LED eingeschaltet.

Damit ein 4x4x4 RGB Würfel halbwegs hell und flimmerfrei funktioniert braucht es eine andere Ansteuerung der LEDs.

Grüße Uwe

uwefed:
Ah, Du willst die LED Multiplexen.
Da kannst Du kein PWM-Signal verwenden da die Ansteuerung der LED in einer Ebene mit der Ansteuerung der Ebenen synchronisiert sein muß.

Multiplexer für die Ansteuerung von Verbrauchern zu verwenden ist wenig ziehlführend da die Multiplexer immer nur 1 Ausgang mit dem gemeinsamen Kontakt verbinden und so immer nur 1 LED angesteuert werden kann. DU hast also einen 4x4x4 Würfel mit RGB LED mit gemeinsamer Anode. Die Kathoden der 3 Farben sind jeweis zusammengeschaltet (3 x 64 Kathoden) und die 64 Anoden der LED auf je einen Ausgang der 4 1:16 Multiplexer verbunden.
Das Funktioniert nie richtig (flimmerfrei und hell) da immer nur 4 der 192 LED (hier als Einzelfarbe genommen) angesteuert werden können und somit ein LED max 1/48-stel Sekunde leuchtet. Oder anders gesagt nur 2% der Zeit ist jedes LED eingeschaltet.

Damit ein 4x4x4 RGB Würfel halbwegs hell und flimmerfrei funktioniert braucht es eine andere Ansteuerung der LEDs.

Grüße Uwe

Ich würde gern Bilder vom Schaltplan rein stellen aber ich weiß leider nicht wie.

Hallo,

.png oder .jpg einfach anhängen.
Einmal Preview drücken, danach kannste die Dateien als Attachments anhängen.

Hallo,

auch wenn es vielleicht nicht mehr benötigt wird wegen dem Problem mit dem Multiplexing, möchte ich dennoch zeigen wie man das mit einem Timer erschlagen kann. Es ist beliebig erweiterbar. Im Grunde basiert es auf einem Servo Sketch. Der benötigt aber keine künstliche Totzeit zwischen den Pulsen. Die maximale Zeit für irgendwelche Pulsformung oder Totzeit ergibt sich aus dem maximalen Timercount von 65535 und dem aktuellen Prescaler 8. Ein Timercount entspricht 1 / 16MHz * 8 = 0,5µs. Das wäre gleichzeitig die Auflösung. Daraus ergibt sich 0,5µs * 65535 = 32,767ms was maximal einstellbar wäre mit Prescaler 8.

Zur besseren Erkennung am Oszi habe ich die Totzeit auf halbe Pulszeit gesetzt.

/*
  Doc_Arduino - german Arduino Forum
  IDE 1.8.5
  Arduino Mega2560

  11.04.2018
    
  Pinouts  >>> http://www.pighixxx.com/test/pinoutspg/boards/
  Uno      >>> http://www.pighixxx.com/test/portfolio-items/uno/?portfolioID=314
  Mega2560 >>> http://www.pighixxx.com/test/portfolio-items/mega/?portfolioID=314 
*/

struct t_phasen  
{
  const byte pin;
  unsigned int pulszeit;
  unsigned int totzeit;
};  

t_phasen phase[] = {    
  {23, 4000, 2000},   // Pin, Pulszeit, Totzeit
  {24, 4000, 2000},
  {25, 4000, 2000}
};

const byte ANZ_PHASEN = sizeof(phase) / sizeof(t_phasen);

volatile bool flag_updated = false;

void setup()  { 
 
  for (byte i=0; i < ANZ_PHASEN; i++) {
    pinMode(phase[i].pin, OUTPUT);
  }
   
  set_Timer1();               
}


void loop() {
  
  if (flag_updated == true) {
    calc_Phasen();
    flag_updated = false;
  }
    
} // loop Ende


// ****** Funktionen ******* //

ISR(TIMER1_COMPB_vect)    // wird aller x Timercounts aufgerufen
{  
   static byte zustand = 0;
   static unsigned int waitTime = 0;  // 2 counts = 1µs
    
   switch(zustand) {    
      // Count  1999 =  1ms
      // Count  3999 =  2ms
      // Count 39999 = 20ms
      case 0: digitalWrite(phase[0].pin, HIGH); waitTime = phase[0].pulszeit; break;
      case 1: digitalWrite(phase[0].pin, LOW);  waitTime = phase[0].totzeit;  break;
      case 2: digitalWrite(phase[1].pin, HIGH); waitTime = phase[1].pulszeit; break;
      case 3: digitalWrite(phase[1].pin, LOW);  waitTime = phase[1].totzeit;  break;
      case 4: digitalWrite(phase[2].pin, HIGH); waitTime = phase[2].pulszeit; break;
      case 5: digitalWrite(phase[2].pin, LOW);  waitTime = phase[2].totzeit;
                                                flag_updated = true;          break;                                      
   }
   
   OCR1B += waitTime;     // Zeit vom nächsten Compare berrechnen
   zustand++;
   if (zustand > 5)  zustand = 0;                  
}


void calc_Phasen ()      
{          
   // *** zum Bsp. alle Pulszeiten ändern/aktualisieren ***
   /*
   phase[0].pulszeit =
   phase[0].totzeit  =
   phase[1].pulszeit =
   phase[1].totzeit  = 
   phase[2].pulszeit =
   phase[2].totzeit  =   
   */   
}


void set_Timer1 ()     // Normal Mode, Pulserzeugung
{
  cli();                  // Interrupts ausschalten
  TCCR1A = 0;             // Reset 
  TCCR1B = 0;             // 
  TIMSK1 = 0;             // 
  TCNT1  = 0;             // 
  OCR1B  = 0;             // 
  TIMSK1 = (1<<OCIE1B);   // enable Compare Match B ISR
  TCCR1B = (1 << CS11);   // Prescaler 8
  sei();                  // Interrupts einschalten
}

Doc_Arduino:
auch wenn es vielleicht nicht mehr benötigt wird ...

... gefällt es mir dennoch :slight_smile:

Hallo,

freut mich. Das Grundgerüst vom Servocode ist universell anwendbar wie ich in letzter Zeit feststelle. In dem Fall hier habe ich die defines und bitset durch digitalWrite ersetzt. Dann macht das struct auch mehr Sinn wenn der Pin mit drin ist. Timer fetzen. :slight_smile:

Vielleicht könnten wir ja noch altou beim Multiplexing helfen, wobei ich mich damit noch nie ernsthaft beschäftigt habe.