Forum: Compiler & IDEs alternative für for-schleife zeitmangel


von Kaan A. (deranfaenger)


Lesenswert?

Hey Leute,
ich erinnere mich mal gehört zu haben, dass man bei µC Programmierung 
keine for-Schleifen verwendet, da diese zu langsam sind (oder so).

Folgendes Problem..
Ich habe ein Programm, das mir 6 verschiedene PWM-Signale erzeugt.
sprich manche Funktionen werden 6 mal aufgerufen.
Dies geschieht bei manchen Aufgaben mit switch-Anweisungen und bei 
anderen in for-Schleifen. Je nach dem, was gefragt ist.

Beispielcode (aufs wesentliche komprimiert der richtige Code hat 220 
Zeilen):
1
// increase PWM-Time
2
void stepPWM(){
3
  for (unsigned char i=0; i<numberOfMags; i++){
4
    mag[i].currentTime += 1;
5
  }
6
}
7
8
//Timer Interrupt
9
ISR(TIMER0_COMPA_vect){
10
  TCNT0 = 0x00;
11
  stepPWM();
12
}
13
14
int main(void){
15
..........  // Initialisierungen usw.
16
  while(1){
17
    
18
    // Kontrolle, ob Einstellungen für PWM geändert werden müssen
19
    if (PORTB & 0x3F){
20
      process(); // hier wird geschaut, welche PWM geändert werden müssen, um welche Werte diese geändert werden müssen(2x ADC für (Frequenz oder Phase wird an einem Eingang gemultiplext) und Tastverhältnis) dann werden die Einstellungen aktualisiert
21
//hier wird eine Funktion mit for-Schleife aufgerufen und zusätzlich in einer for-Schleife eine weitere Funktion aufgerufen
22
    };  
23
        // Kontrolle, ob die Phasen aller PWM zurückgesetzt werden sollen    
24
    if (PORTB & 1<<PORTB7) {        
25
      for (unsigned char i=0; i<numberOfMags; i++){
26
        synchronizePhase(&mag[i]); // hier werden die Variablen für die Phasenverschiebungen auf 0 gesetzt (in einer for Schleife)
27
      }
28
    }; 
29
    for (unsigned char i=0; i<numberOfMags; i++){
30
      checkPWM(&mag[i], i); // hier wird für die i te PWM überprüft, ob Phasenverschiebung, Tastverhältnis, Frequenz(Periodenende) erreicht ist, um dann den Output festzulegen.
31
    }
32
  }
33
  return 0;
34
}
Mein Problem ist, einfach dass der Ablauf der Mainschleife viel zu lange 
dauert. Meine erste Optimierung wäre den Code effizienter zu gestalten, 
indem ich die for-Schleifen umgehe, wenn das denn möglich ist.

Ich hoffe mein Problem ist verständlich erklärt.

von Peter II (Gast)


Lesenswert?

die Schleifen werden wohl nicht das Problem sein. (Wie gross ist 
numberOfMags überhaupt?)

sondern die Funktionen (synchronizePhase,checkPWM).

von Karl H. (kbuchegg)


Lesenswert?

Kaan Ayhan schrieb:
> Hey Leute,
> ich erinnere mich mal gehört zu haben, dass man bei µC Programmierung
> keine for-Schleifen verwendet, da diese zu langsam sind (oder so).

Die meisten Aussagen die mit 'Ich habe mal gehört' beginnen, sind 
kompletter Unsinn.

von Falk B. (falk)


Lesenswert?

@ Karl Heinz (kbuchegg) (Moderator)

>Die meisten Aussagen die mit 'Ich habe mal gehört' beginnen, sind
>kompletter Unsinn.

Das hab ich auch mal gehört! ;-)

von Daniel V. (danvet)


Lesenswert?

Peter II schrieb:
> die Schleifen werden wohl nicht das Problem sein. (Wie gross ist
> numberOfMags überhaupt?)
>
> sondern die Funktionen (synchronizePhase,checkPWM).

Jepp
@TO: Bitte IMMER den kompletten Code posten. So ist das ein 
"Rate-Rate-Was-ist-das".

von Udo S. (urschmitt)


Lesenswert?

Das Problem ist in checkPWM.


...




oder in sonst einem Teil, den du nicht gepostet hast.

Kaan Ayhan schrieb:
> ich erinnere mich mal gehört zu haben, dass man bei µC Programmierung
> keine for-Schleifen verwendet, da diese zu langsam sind (oder so).

"Oder so" sollte man nie vertrauen solange man keinen plausiblen Grund 
hat warum das so sein sollte.
Die for Schleife selbst ist zu 99,999% NICHT dein Problem.


Schon mal bei Eintritt und verlassen von Funktionen einen Port 
gesetzt/gelöscht und mit dem Oszi geschaut wie lange die Funktionen 
brauchen?

von CCodeSchauer (Gast)


Lesenswert?

Die Funktionen auf die es ankommt hats du ja zum Glück im Listing
unterschlagen. Die müssen wir ja nicht anschauen .....

Wo "viel" Zeit draufgeht ist der Funktionaufruf (Register retten
und Parameter kopieren) selbst und die Rückkehr aus der Funktion.

von Karl H. (kbuchegg)


Lesenswert?

> Beispielcode (aufs wesentliche komprimiert der richtige Code hat 220 Zeilen):

Zeig den Code und beschreibe, inwiefern er zu langsam ist.

Alles andere ist Kaffeesatzleserei.
Das Wahrscheinlichste ist, dass dein Zeitproblem in der Progammstruktur 
enthalten ist. D.h. man kann nicht eine bestimmte Stelle dafür 
verantwortlich machen, sondern muss das Programm entsprechend 
strukturieren bzw. umstrukturieren.
Zb sieht es seltsam aus, wenn du von 6 PWMs redest, in der einzigen ISR 
aber gar kein PWM Code enthalten ist (ich geh mal davon aus, dass du 
Software-PWM machen willst, weil du nicht genügend Hardware Einheiten 
für 6 PWM hast).

: Bearbeitet durch User
von sdg (Gast)


Lesenswert?

ich hab mal gehört µCs besitzen Timer in Hardware die sich als PWM 
gebrauchen lassen, aber vielleicht ist das ja nur ein Gerücht :)

von Kaan A. (deranfaenger)


Angehängte Dateien:

Lesenswert?

Ja, an meiner Programmierung wird es natürlich eher liegen, da ich noch 
nicht besonders viel Erfahrung darin habe. Ich habe den Mikrocontroller 
noch garnicht. Das ganze läuft im Moment nur im Debugger des AtmelStudio 
6.2 bei mir.

Ich habe das Programm mal gepackt und hochgeladen. Ich hoffe, ihr könnt 
etwas damit anfangen. Wichtig ist mir halt insbesondere, dass die 
Funktion checkPWM() zwischen jedem Timerinterrupt aufgerufen werden 
kann. das packe ich aber nicht. Der Timerinterrupt wird, wenn ich mich 
nicht irre, 3 mal pro Mainschleifendurchlauf aufgerufen.
Im Moment wird der Timerinterrupt mit 500Hz geschmissen und der 
Systemtakt liegt bei 1Mhz.
Wenn das Board fertig ist, wird ein externes Quarz angeschlossen, um 
16MHz Systemtakt zu erhalten und der TimerInterrupt soll mit 200kHz 
aufgerufen werden...  sodass eine PWM-Frequenz von 2kHz bei einem 
Tastverhältnis von 1% Genauigkeit möglich ist.

Ich habe mir überlegt, die checkPWM()-Funktion im Interrupt auszuführen, 
aber das ist ja auch nicht gerade gut. Vor allem weil die Funktion zu 
viele Takte braucht >.<
...

Ich bin für jede Hilfe dankbar.

von Karl H. (kbuchegg)


Angehängte Dateien:

Lesenswert?

Stell doch die beiden Files direkt hier ein. Die paar KB sind jetzt 
nichts, was irgend jemanden vom Hocker hauen würde.

von Peter II (Gast)


Lesenswert?

Auf den ersten blick wird wohl hier die engstelle sein
1
float scaledTime;
2
3
scaledTime = magnetron->currentTime * magnetron->freqScaler; // scale currentTime from Timer frequency to desired PWM frequency


warum muss es denn float sein?

Tut es da kein int?

von Udo S. (urschmitt)


Lesenswert?

Kaan Ayhan schrieb:
> um
> 16MHz Systemtakt zu erhalten und der TimerInterrupt soll mit 200kHz

Das ist natürlich mal ne Ansage, viel Takte sind das nicht.
Gerade mal 80 minus der Zeit, die die Interrupt Funktion selbst braucht.

Kaan Ayhan schrieb:
> Funktion checkPWM()zwischen jedem Timerinterrupt aufgerufen werden
> kann. das packe ich aber nicht. Der Timerinterrupt wird, wenn ich mich
> nicht irre, 3 mal pro Mainschleifendurchlauf aufgerufen.

Kann oder muss die Funktion aufgerufen werden.
Wenn sie nach jedem Timerinterrupt aufgerufen werden MUSS dann ist es 
vieleicht sinnvoll sie am Ende der Timerinterruptfunktion direkt 
aufzurufen.

Denn der Zusammenhang zwischen Timerinterruptfunktion und Hauptschleife 
ist per se erst mal asynchron.

: Bearbeitet durch User
von Mark B. (markbrandis)


Lesenswert?

Kaan Ayhan schrieb:
> Hey Leute,
> ich erinnere mich mal gehört zu haben, dass man bei µC Programmierung
> keine for-Schleifen verwendet, da diese zu langsam sind (oder so).

Nein, das ist Unsinn. Wenn man über eine bestimmte Anzahl von Elementen 
iterieren soll, so kann man dies hervorragend mit einer for-Schleife 
tun. Oder auch mit einer while-Schleife.

von Amateur (Gast)


Lesenswert?

Wenn Du etwas X-Mal machen willst, so kommst Du um die grundlegende 
Frage: "Wie oft habe ich es schon getrieben", nicht herum.
Dies wiederum bedeutet, dass Du auch jemanden hast den Du fragen kannst 
- meist eine Variable - und etwas, das diese, bei jedem Mal, 
inkrementiert - alternativ dekrementiert.

Eine minimale Verkürzung würde eine Endlosschleife bringen. Aber nur, 
wenn die Anzahl unwichtig ist.

Moderne Compiler "wissen" auch, ob der jeweilige Prozessor 
Sondermöglichkeiten besitzt, die es ermöglichen Sonderbefehle zu 
verwenden.

Also solche, die die Dekrementierung oder Inkrementierung mit 
verkürzenden Sprunganweisungen verbinden. Oder explizite Vergleiche nach 
dem Zählen sparen.

von MaWin (Gast)


Lesenswert?

Kaan Ayhan schrieb:
> ich erinnere mich mal gehört zu haben, dass man bei µC Programmierung
> keine for-Schleifen verwendet, da diese zu langsam sind (oder so).

Also dein

> void stepPWM(){
>   for (unsigned char i=0; i<numberOfMags; i++){
>     mag[i].currentTime += 1;
>   }
> }

wäre als
1
 void stepPWM(){
2
    mag[0].currentTime += 1;
3
    mag[1].currentTime += 1;
4
    mag[2].currentTime += 1;
5
    mag[3].currentTime += 1;
6
    mag[4].currentTime += 1;
7
    mag[5].currentTime += 1;
8
 }
ungefähr doppelt so schnell (vorausgesetzt, mag ist global).

Aber mit doppelt so schnell bekommt man kein VIEL zu langsamen Programm 
schnell genug. Meistens sind die Algorithmen schlecht gewählt. Irgendwas 
lernen die Leute in ihren Informatikstudium schon.

von Karl H. (kbuchegg)


Lesenswert?

Udo Schmitt schrieb:

> Kann oder muss die Funktion aufgerufen werden.
> Wenn sie nach jedem Timerinterrupt aufgerufen werden MUSS dann ist es
> vieleicht sinnvoll sie am Ende der Timerinterruptfunktion direkt
> aufzurufen.

Ja.
Aber bitte jetzt nicht die vorhandene Funktion.

Im Timer Interrupt soll nur die PWM erzeugt werden. Nichts anderes. Für 
6 Ausgänge sollte das auch mit der beschränkten Taktzahl noch machbar 
sein.

Laufen die einzelnen PWM eigentlich alle mit derselben Frequenz?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> Im Timer Interrupt soll nur die PWM erzeugt werden. Nichts anderes. Für
> 6 Ausgänge sollte das auch mit der beschränkten Taktzahl noch machbar
> sein.
>
> Laufen die einzelnen PWM eigentlich alle mit derselben Frequenz?

1
struct pwm_t
2
{
3
  uint8_t cnt;
4
  uint8_t setCnt;
5
  uint8_t setMask;
6
  uint8_t clrMask;
7
}
8
9
volatile struct pwm_t Pwm[6] =
10
{
11
  { 0, ( 1 << PORTD0 ), ~( 1 << PORTD0 ) },
12
  { 0, ( 1 << PORTD1 ), ~( 1 << PORTD1 ) },
13
  { 0, ( 1 << PORTD2 ), ~( 1 << PORTD2 ) },
14
  { 0, ( 1 << PORTD3 ), ~( 1 << PORTD3 ) },
15
  { 0, ( 1 << PORTD5 ), ~( 1 << PORTD5 ) },
16
  { 0, ( 1 << PORTD6 ), ~( 1 << PORTD6 ) },
17
};
18
19
ISR( ... )
20
{
21
  static uint8_t pwmCount = 0;
22
  uint8_t i;
23
  uint8_t portShadow;
24
25
  pwmCount++;
26
  if( pwmCount == 100 ) {
27
    pwmCount = 0;
28
    for( i = 0; i < 6; i++ )
29
      Pwm[i].cnt = Pwm[i].setCnt;
30
  }
31
32
  portShadow = PORTD;
33
34
  for( i = 0; i < 6; i++ ) {
35
    if( Pwm[i].cnt < pwmCount )
36
      portShadow |= Pwm[i].setMask;
37
    else
38
      portShadow &= Pwm[i].clrMask;
39
  }
40
41
  PORTD = portShadow;
42
}

damit laufen mal die 6 PWM Stufen und alles andere arbeitet diesen zu.

wenn das unlösbare Zeitprobleme ergibt, dann müsste man an den Masken 
noch feilen, und eventuell die Schleife aufdröseln, damit der Compiler 
die schnellen Bitinstruktionen benutzen kann
1
volatile uint8_t Pwm[6]; // die Werte der einzelnen PWM Stufen
2
uint8_t PwmWork[6];         
3
4
#define CHECK_PWM(i, pin)      \
5
    if( PwmWork[i] < pwmCount )   \
6
      PORTD |= ( 1 << pin );  \
7
    else                      \
8
      PORTD &= ~( 1 << pin );
9
10
ISR( ... )
11
{
12
  static uint8_t pwmCount = 0;
13
  uint8_t i;
14
15
  pwmCount++;
16
  if( pwmCount == 100 ) {
17
    pwmCount = 0;
18
    for( i = 0; i < 6; i++ )
19
      PwmWork[i] = Pwm[i];
20
  }
21
22
  CHECK_PWM( 0, PORTD0 );
23
  CHECK_PWM( 1, PORTD1 );
24
  CHECK_PWM( 2, PORTD2 );
25
  CHECK_PWM( 3, PORTD3 );
26
  CHECK_PWM( 4, PORTD5 );
27
  CHECK_PWM( 5, PORTD6 );
28
}

Das ist der Kern der ganzen Sache. Die einzelnen PWM müssen mit der 
angestrebten Frequenz laufen. Alles andere hat sich dem unterzuordnen.

Es gäbe auch noch eine cleverere Variante der PWM Erzeugung, die um 
einiges weniger CPU-Laufzeit benötigt. Die ist allerdings um einiges 
komplexer.

Und da rundherum konstuierst du jetzt deinen Code, der die Veränderung 
der jeweiligen PWM Werte realisiert.

Disclaimer: Ich hab jetzt die einzelnen ISR nicht kontrolliert, ob sich 
das mit der Taktzahl noch ausgeht. Es sollte aber zumindest nahe drann 
sein. Wenn es sich nicht ausgeht, könntest man mal darüber nachdenken, 
ob man die 200kHz nicht etwas lockert. Mit 100kHz (und damit 2% anstelle 
von 1%) ist man mit 16Mhz auf jeden Fall im grünen Bereich.

: Bearbeitet durch User
von Amateur (Gast)


Lesenswert?

@MaWin

>ungefähr doppelt so schnell (vorausgesetzt, mag ist global).

Stimmt bei kurzen Anweisungen und bei überschaubarer Anzahl an 
Schleifendurchläufen.

Andernfalls werden hauptsächlich die Fingerkuppen strapaziert und der 
Code gerät aus der Form. Vielleicht springt auch der Compiler aus dem 
Fenster, weil ihm dauernd jemand den Speicher klaut.

von (prx) A. K. (prx)


Lesenswert?

MaWin schrieb:
> ungefähr doppelt so schnell (vorausgesetzt, mag ist global).

Nur als Beispiel, auf welche Ideen Compiler schon von sich aus kommen, 
wenn man sie nicht dran hindert:
1
extern char mag[];
2
3
void stepPWM(void){
4
   for (unsigned i=0; i<256; i++){
5
     mag[i] += 1;
6
   }
7
}
wird bei GCC 4.7.2 und -O3 für x86-64 im Kern zu
1
.L5:
2
        movdqa  (%rsi,%rax), %xmm0
3
        addl    $1, %ecx
4
        paddb   %xmm1, %xmm0
5
        movdqa  %xmm0, (%rsi,%rax)
6
        addq    $16, %rax
7
        cmpl    %r8d, %ecx
8
        jb      .L5
und falls jemandem das nichts sagt: Das ist gepackter SSE Code mit 16 
mag[] Elementen pro Iteration. Mit -funroll-loops wird das dann zu 128 
pro Iteration:
1
.L5:
2
        movdqa  (%rdx,%rax), %xmm9
3
        addl    $8, %ecx
4
        movdqa  16(%rdx,%rax), %xmm10
5
        paddb   %xmm0, %xmm9
6
        movdqa  32(%rdx,%rax), %xmm11
7
        paddb   %xmm0, %xmm10
8
        movdqa  48(%rdx,%rax), %xmm12
9
        paddb   %xmm0, %xmm11
10
        movdqa  64(%rdx,%rax), %xmm13
11
        paddb   %xmm0, %xmm12
12
        movdqa  80(%rdx,%rax), %xmm14
13
        paddb   %xmm0, %xmm13
14
        movdqa  96(%rdx,%rax), %xmm15
15
        paddb   %xmm0, %xmm14
16
        movdqa  112(%rdx,%rax), %xmm1
17
        paddb   %xmm0, %xmm15
18
        movdqa  %xmm9, (%rdx,%rax)
19
        paddb   %xmm0, %xmm1
20
        movdqa  %xmm10, 16(%rdx,%rax)
21
        movdqa  %xmm11, 32(%rdx,%rax)
22
        movdqa  %xmm12, 48(%rdx,%rax)
23
        movdqa  %xmm13, 64(%rdx,%rax)
24
        movdqa  %xmm14, 80(%rdx,%rax)
25
        movdqa  %xmm15, 96(%rdx,%rax)
26
        movdqa  %xmm1, 112(%rdx,%rax)
27
        subq    $-128, %rax
28
        cmpl    %r8d, %ecx
29
        jb      .L5

Zwar ist x86-64 kein Mikrocontroller und AVRs haben keine SSE Befehle, 
aber das Prinzip ist gleich: Erst einmal sehen, was der Compiler von 
sich aus zustande bekommt, bevor man versucht, von Hand zu optimieren.

: Bearbeitet durch User
von Kaan A. (deranfaenger)


Lesenswert?

Hey Leute danke erstmal für die vielen Antworten in der kurzen Zeit..
Ich bin ja mit dem lesen fast garnicht nachgekommen xD

Ich hoffe aus meinem angehängten Quelltext könnt ihr heraussehen was ich 
falsch mache bzw grundsätzlich ändern sollte.
Und den Namen der Datei nicht beachten, das war ursprünglich nur zum 
Testen der ADC Funktion. Habe sie nachträglich einfach erweitert.

CCodeSchauer schrieb:
> Wo "viel" Zeit draufgeht ist der Funktionaufruf (Register retten
> und Parameter kopieren) selbst und die Rückkehr aus der Funktion.
Heißt das, ich soll nach Möglichkeit Funktionsaufrufe vermeiden um nicht 
unnötig "Takte zu verlieren"?

sdg schrieb:
> ich hab mal gehört µCs besitzen Timer in Hardware die sich als PWM
> gebrauchen lassen, aber vielleicht ist das ja nur ein Gerücht :)
Karl Heinz schrieb:
> Laufen die einzelnen PWM eigentlich alle mit derselben Frequenz?
Es sollen 6 PWM mit jeweils von einander unabhängig variablen 
Frequenzen, Phasenverschiebungen und Tastverhältnissen erzeugt werden.
Der MikroController besitzt nur 3 Timer. Also kann ich auch nur 3 
unterschiedliche PWM erzeugen. Also muss das softwareseitig gelöst 
werden.
Aber eben weil die Phasen und Frequenzen verschieden sind, kann ich 
deine Variante leider nicht benutzen Karl :/

Udo Schmitt schrieb:
> Das ist natürlich mal ne Ansage, viel Takte sind das nicht.
> Gerade mal 80 minus der Zeit, die die Interrupt Funktion selbst braucht.
Ja, genau das ist ja mein Problem, warum ich das optimieren muss.
> Wenn sie nach jedem Timerinterrupt aufgerufen werden MUSS dann ist es
> vieleicht sinnvoll sie am Ende der Timerinterruptfunktion direkt
> aufzurufen.
Das kann ich ja nicht, da erstens der Funktionsdurchlauf zu lange 
dauert, sodass er nicht zwischen 2 Interruptaufrufe passt und zweitens 
noch etwas Zeit übrig bleiben muss, um die anderen Operationen 
durchzuführen.

MaWin schrieb:
> Aber mit doppelt so schnell bekommt man kein VIEL zu langsamen Programm
> schnell genug. Meistens sind die Algorithmen schlecht gewählt.
Ich weiß, dass es mehr an den Algorithmen liegt, aber jeder Zeitgewinn 
ist Gold wert. Wie Udo ja auch schon festgestellt hat, habe ich nur 80 
Takte - Interruptaufwand zur verfügung.
Bzw. muss hier mein PWMcheck hineinpassen. Wenn der rest etwas länger 
dauert ist das nicht schlimm.
Ich bin am überlegen ob wir vielleicht sogar einen 20MHz Quarz anbauen, 
um etwas mehr Takte zur verfügung zu haben.

Peter II schrieb:
> float scaledTime;
> warum muss es denn float sein?
Das war float, da ich an der Stelle zuvor eine Division hatte. Das hat 
sich jett geändert. Aber danke für den Hinweis hab das jetzt geändert.

von Karl H. (kbuchegg)


Lesenswert?

Kaan Ayhan schrieb:

>> Laufen die einzelnen PWM eigentlich alle mit derselben Frequenz?
> Es sollen 6 PWM mit jeweils von einander unabhängig variablen
> Frequenzen, Phasenverschiebungen und Tastverhältnissen erzeugt werden.
> Der MikroController besitzt nur 3 Timer. Also kann ich auch nur 3
> unterschiedliche PWM erzeugen. Also muss das softwareseitig gelöst
> werden.
> Aber eben weil die Phasen und Frequenzen verschieden sind, kann ich
> deine Variante leider nicht benutzen Karl :/

Kannst du nach wie vor.
Du hast dann eben 6 durchlaufende pwmCount und nicht nur einen, so dass 
jede PWM ihren eigenen Maximalwert haben kann und nicht, wie bei nur 
einem derartigen Counter alle bei 100 den nächsten Zyklus beginnen.
1
ISR( ... )
2
{
3
  static uint8_t pwmCount[6] = 0;
4
  uint8_t i;
5
6
  for( i = 0; i < 6; i++ )
7
    pwmCount[i]++;
8
    if( pwmCount[i] == pwmMax[i] ) {
9
      pwmCount = 0;
10
      PwmWork[i] = Pwm[i];
11
    }
12
  }
13
14
  CHECK_PWM( 0, PORTD0 );
15
  CHECK_PWM( 1, PORTD1 );
16
  CHECK_PWM( 2, PORTD2 );
17
  CHECK_PWM( 3, PORTD3 );
18
  CHECK_PWM( 4, PORTD5 );
19
  CHECK_PWM( 5, PORTD6 );
20
}

und wenn du die Counter auch noch aus der ISR rausnimmst, dann kannst du 
mit ihnen auch noch eine Phasenverschiebung erreichen, in dem du den 
jeweiligen pwmCount manipulierst.

: Bearbeitet durch User
von Kaan A. (deranfaenger)


Lesenswert?

Ja meine Lösung für die Phasenverschiebung war folgende:
Ich setze den pwmCount auf 0 - Phasenverschiebung (gezählt wird ja 
sowieso immer mit +1 da ist es egal wie der Wert wirklich aussieht).
Der Output sieht dann so aus:
1
if(pwmCount[i] >=0 && pwmCount[i]<tastverhaeltnis[i]({
2
    PORTD |= 1<<PORTDi;
3
}else{
4
    PORTD &= ~(1<<PORTDi);

Aber was ist, wenn durch meine Phasenverschiebung mein Tastverhältnis in 
die nächste Periode über geht? Dann kann ich das so ja nicht mehr 
machen.
Dann sieht das bei mir so aus:
1
if((phase + tastverhalten) > frequenz){ // wenn es einen Überlauf gibt
2
    if(pwmCount <= ((phase + tastverhalten) - frequenz)){
3
      PORTD |= 1<<PORTDi;
4
    }else{
5
      (((pwmCount - phase) >= 0)&&((pwmCount - phase) < tastverhalten)) ? PORTD |= 1<<PORTDi : PORTD &= ~(1<<PORTDi);
6
    };
7
}else{ // wenn es keinen Überlauf gibt
8
  (((pwmCount - phase) >= 0)&&((pwmCount - phase) < tastverhalten)) ? PORTD |= 1<<PORTDi :PORTD &= ~(1<<PORTDi);
9
}
Und das würde wiederum zu lange dauern, um im Interrupt ausgeführt zu 
werden. Oder nicht?

von Karl H. (kbuchegg)


Lesenswert?

Kaan Ayhan schrieb:

> Der Output sieht dann so aus:

Du versuchst viel zu viel während des Outputs auf die Pins zu erledigen.
Das ist eine Sackgasse!

Der Teil des Programms, der die Pins dann tatsächlich bedient, darf sich 
nicht mehr um Sonderfälle kümmern müssen. Dieser Programmteil arbeitet 
nur noch seine simple PWM Erzeugung ab. Alle Sonderfälle und sonstigen 
Dinge müssen von diesem Teil des Programmes fern gehalten werden, indem 
man die Intelligenz in die Generierung der Steuerdaten der einzelnen PWM 
Stufen steckt. Während der Auswertung dieser Daten zur Generierung der 
eigentlichen PWM darf da nichts mehr auftreten.

Wenn du dieses Timing hinkriegen willst, dann geht das nicht anders. Die 
6 PWM Stufen sind der zentrale Kern deines Programms.


> Und das würde wiederum zu lange dauern, um im Interrupt ausgeführt zu
> werden. Oder nicht?

Was ist eigentlich die genaue Aufgabenstellung?

>> Aber mit doppelt so schnell bekommt man kein VIEL zu langsamen
>> Programm schnell genug. Meistens sind die Algorithmen schlecht gewählt.
> Ich weiß, dass es mehr an den Algorithmen liegt, aber jeder
> Zeitgewinn ist Gold wert.

reichlich naiv.
Wenn die Aufgabe lautet, von hier aus möglichst schnell zum Mond zu 
kommen, dann ist es völlig wurscht, ob du an deiner Haustür ein schnell 
öffnendes Schloss hast oder nicht. Die 3 Sekunden, die du hier einsparen 
kannst, sind nichts im Vergleich zu den 4 Tagen, die du zum Mond 
brauchst.
Nur Laien glauben immer, man könne mit einem schnelleren Prozessor oder 
winzigen Mikrooptimierungen den Laden noch herumreissen. Das bringt was, 
wenn du knapp drann bist. Dein jetziges Timing ist aber so weit daneben, 
das du mit derartigen Ansätzen maximal die goldene Himbeere gewinnen 
kannst. Um von Deutschland aus in 24 Stunden nach Peking zu kommen, 
kannst du dein Fahrrad pimpen so viel du willst, ohne grundsätzlichen 
Wechsel zu einem FLugzeug wird das nichts.

: Bearbeitet durch User
von Mark B. (markbrandis)


Lesenswert?

Karl Heinz schrieb:

> Was ist eigentlich die genaue Aufgabenstellung?

Kann man diesen Satz bitte in Stein gemeißelt vor dem Eingang zu diesem 
Forum aufhängen? :-)

von Kaan A. (deranfaenger)


Lesenswert?

Ok, ich verstehe was du meinst. Dass ich das noch nciht so gut hinkriege 
liegt einfach an der mangelnden Erfahrung. Aber ich werde versuchen, das 
Programm umzustrukturieren.

Die Aufgabenstellung habe ich ja ziemlich weit oben schon erläutert.
Ich versuche ein Programm zu schreiben, das mir PWM bei einer Frequenz 
von bis zu 2kHz erzeugen kann. D.h. ich muss es schaffen, die PWM im 
200kHz Takt zu überprüfen und den Output dem entsprechend zu setzen. So 
habe ich für die Phasenverschiebung und das Tastverhältnis eine 
Genauigkeit von 1%.
Der µC soll später mit einem externen Quarz auf 16MHz getaktet werden.

von Peter II (Gast)


Lesenswert?

Schau dir mal den Artikel an:

http://www.mikrocontroller.net/articles/Soft-PWM

Diese Art der Umsetzung müsste auch bei dir möglich sein.

von Karl H. (kbuchegg)


Lesenswert?

Mark Brandis schrieb:
> Karl Heinz schrieb:
>
>> Was ist eigentlich die genaue Aufgabenstellung?
>
> Kann man diesen Satz bitte in Stein gemeißelt vor dem Eingang zu diesem
> Forum aufhängen? :-)

Gleich darunter würde ich noch einmeisseln:
Leute, nehmt keine Aufträge an, von denen im Vorfeld schon feststeht, 
dass ihr sie nicht stemmen könnt, weil eure Kenntnisse hinten und vorne 
nicht ausreichen.

von Dennis R. (dennis_r93)


Lesenswert?

Wenn das Signal sich nach wenigen Zyklen wiederholt gibt es auch die 
Möglichkeit die Ausgabesignale im Speicher für einen kompletten Zyklus 
zu berechnen und in der ISR nur den Wert zu Laden, Auszugeben und 
Counter um eins erhöhen

deine ISR würde dann ungefähr so aussehen:
1
Void ISR(){
2
  static unsigned char i;
3
  PORTD = data[i];
4
  i++;
5
}

Außerhalb der ISR musst du dann die werte für das Ram berechnen.
Der Aufwand zum Berechnen fällt dann aber nur dann an, wenn sich etwas 
ändert.

Oder wenn es viele werte sind kann man auch die Datenstruktur um einen 
Zeitstempel erweitern mit dem der aktuelle Zyklus verglichen wird, so 
muss nur ein Bruchteil der Zyklen im Ram gespeichert werden.

von Falk B. (falk)


Lesenswert?

@ Kaan Ayhan (deranfaenger)

>Ich versuche ein Programm zu schreiben, das mir PWM bei einer Frequenz
>von bis zu 2kHz erzeugen kann. D.h. ich muss es schaffen, die PWM im
>200kHz Takt zu überprüfen und den Output dem entsprechend zu setzen. So
>habe ich für die Phasenverschiebung und das Tastverhältnis eine
>Genauigkeit von 1%.
>Der µC soll später mit einem externen Quarz auf 16MHz getaktet werden.

Schon mal 5 Minuten gerechnet und nachgedacht?

Bei 16 MHz macht dein AVR pro us 16 Takte, wenn men es halbwegs 
intelligent macht 16 Einzelbefehle. 200 kHz sind 5us, sprich du hast 80 
CPU Takte pro PWM Takt. Das ist nicht allzu viel! Selbst mit einer guten 
ASM-Interruptroutine muss man sich da schon SEHR anstrengen!

Mach dir das Leben leicht und nimm einen großen AVR, der 6 PWMs in 
Hardware erzeugen kann.

von Falk B. (falk)


Lesenswert?

@Karl Heinz (kbuchegg) (Moderator)

>Leute, nehmt keine Aufträge an, von denen im Vorfeld schon feststeht,
>dass ihr sie nicht stemmen könnt, weil eure Kenntnisse hinten und vorne
>nicht ausreichen.

Sowas hier ?

Beitrag "Überleben auf dem Mars"

;-)

von Karl H. (kbuchegg)


Lesenswert?

Falk Brunner schrieb:
> @Karl Heinz (kbuchegg) (Moderator)
>
>>Leute, nehmt keine Aufträge an, von denen im Vorfeld schon feststeht,
>>dass ihr sie nicht stemmen könnt, weil eure Kenntnisse hinten und vorne
>>nicht ausreichen.
>
> Sowas hier ?
>
> Beitrag "Überleben auf dem Mars"
>
> ;-)

;-)
Das würde ich noch als Grundlagenforschung einstufen. Neuland.
Hier gehts eher um den x-ten, der seinem PKW-Motor 200 zusätzliche PS 
verpassen will, aber keinen Schraubenzieher richtig rum in die Hand 
nehmen kann.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Karl Heinz schrieb:
> Leute, nehmt keine Aufträge an, von denen im Vorfeld schon feststeht,
> dass ihr sie nicht stemmen könnt, weil eure Kenntnisse hinten und vorne
> nicht ausreichen.

Wie war der Spruch doch? Um feststellen zu können, dass die Kenntnisse 
nicht ausreichen, reichen die Kenntnisse nicht aus. Oder so ähnlich.

Addiere darauf dann noch die Hybris der Jugend.

: Bearbeitet durch User
von Kaan A. (deranfaenger)


Lesenswert?

@Falk
Ja, natürlich habe ich das durchgerechnet und bin mir dessen bewusst.
Deshalb brauche ich ja die Hilfe hier im Forum.
Aber die 2kHz PWM-Frequenz sind kein muss. Es ist das Ziel. Die Vorgabe 
ist, 500Hz auf jeden Fall zu schaffen (absolutes minimum) und für die 
Zukunft bis auf 2kHz gehen zu können. D.h. wenn es technisch nicht oder 
nur sehr schwer machbar ist, kann man sich auch mit etwas weniger 
zufrieden geben. 1kHz würden es theoretish auch tun. Aber ich möchte 
natürlich versuchen, das Beste herausholen.
Vorerst geht es ja nur darum eine PWM Generierung hinzukriegen die 
überhaupt funktioniert und effizient ist danach kommt die Optimierung um 
zu sehen wie viel wirklich geht.

@Dennis
Das ist ein guter Vorschlag, danke.
Aber es wären glaube ich zu viele Werte um alle zu speichern.
Wie meinst du das mit dem Zeitstempel? Dass ich z.B. bestimmte 
Zeitintervalle herausnehme und diese vorberechne?
Ich glaube die Berechnungen würden insgesamt zu lange dauern.

@Peter
Danke für den Link. Den gehe ich gerade durch. In dem Beispiel wird 
leider die Phasenverschiebung nicht berücksichtigt, aber ich kann mir 
dort einiges auch an Ideen abgucken.

@Karl @Mark
Ich bin halt ein absoluter Anfänger(so wies in meinem Nickname auch 
steht haha). Tut mir leid, dass ich nicht so viel Erfahrung hab wie ihr, 
aber bis vor 1 Monat hatte ich auch nie mit C- bzw. µC Programmierung zu 
tun gehabt.
Und ich habe keinen Auftrag angenommen, um damit Geld zu verdienen oder 
so, sondern das ist eine Aufgabenstellung von meinem "Ausbilder". Neben 
dem eigentlichen Nutzen soll das Projekt für mich einen Lerneffekt 
bieten. Bei mir im Institut habe ich nur leider keinen direkten 
Ansprechpartner, da alles Elektrotechniker usw. sind und keine 
Informatiker. Ich bin hier weil ich denke, dass ich hier Hilfe kriege 
und nicht um mich runterziehen zu lassen weil ich nicht so viel Ahnung 
habe.
Wenn man als Anfänger mit wenig Erfahrung und vielen Fragen nicht 
erwünscht ist, werde ich mir halt ein anderes Forum suchen müssen.
- dennoch, danke für die bisherige Hilfe.

von Falk B. (falk)


Lesenswert?

@A. K. (prx)

>Wie war der Spruch doch? Um feststellen zu können, dass die Kenntnisse
>nicht ausreichen, reichen die Kenntnisse nicht aus. Oder so ähnlich.

"Der Weise weiß vor allem, was er nicht weiß."

Laotse

von (prx) A. K. (prx)


Lesenswert?

Falk Brunner schrieb:
> "Der Weise weiß vor allem, was er nicht weiß."
> Laotse

Zu dieser Erkenntis wird aber auch Laotse vermutlich nicht in früher 
Jugend gekommen sein. Ausserdem weiss man noch nicht einmal sicher, ob 
es Laotse überhaupt gab.

von Falk B. (falk)


Lesenswert?

Absolut!

von MaWin (Gast)


Lesenswert?

Falk Brunner schrieb:

> Schon mal 5 Minuten gerechnet und nachgedacht?
> Bei 16 MHz macht dein AVR pro us 16 Takte, wenn men es halbwegs
> intelligent macht 16 Einzelbefehle. 200 kHz sind 5us, sprich du hast 80
> CPU Takte pro PWM Takt. Das ist nicht allzu viel! Selbst mit einer guten
> ASM-Interruptroutine muss man sich da schon SEHR anstrengen!

Sorry, aber 6 Kanäle Software-PWM mit 5us Auflösung sind Kinderkram,
das schafft ein AVR locker nebenbei wenn man sich nicht zu blöd 
anstellt.

Wer es nicht kann, muss zahlen:

> Mach dir das Leben leicht und nimm einen großen AVR, der 6 PWMs in
> Hardware erzeugen kann.

von Falk B. (falk)


Lesenswert?

@ MaWin (Gast)

>Sorry, aber 6 Kanäle Software-PWM mit 5us Auflösung sind Kinderkram,
>das schafft ein AVR locker nebenbei wenn man sich nicht zu blöd
>anstellt.

Jaja, der allwissende MaWin mal wieder.

ZEIG DEIN LAUFFÄHIGES PROGRAMM MIT DEN ENDLOSEN RESERVEN ODER HALT DEN 
MUND!

von Dennis R. (dennis_r93)


Lesenswert?

Mit einer geforderten Genauigkeit von 1% sollten 256 Werte ausreichen. 
D.h. du musst im Ram 256*6 bit vorhalten, oder besser 256* 1 byte.
Dann hast du einen unsigned Char Counter der automatisch überlauft -> +1 
reicht, keine Zyklen zum Prüfen ob das ende erreicht ist.

Du kannst aber auch nur 100 Werte nehmen, dann sinkt dein 
Speicherverbrauch auf 100 byte, du musst aber nach jedem hochzählen 
prüfen ob du bei 100 angekommen bist.

Beim Ändern der PWM-Einstellungen musst du dann in diesem 
Speicherbereich die Bits für deinen Kanal ändern.

Das mit dem Zeitstempel ist so gedacht, dass du neben den Werten einen 
Zeitstempel hast der dir sagt, ab wann dieser wert übernommen werden 
soll.
Damit hast du bei jeder Änderung 2 Werte.
Die neuen Portwerte und einen Zeitstempel ab wann dieser Wert gilt.
Dabei solltest du dir aber mit einem Index merken, bei welchen WertZeit 
Paar du gerade bist, damit du dir das Suchen sparen kannst. damit kannst 
du z.B. mit 7 Paaren a 2 byte für 6 Kanäle die zeit merken.
Bsp:
Zeit wert
0    3F    --Start -> alle An
12   1F    --6. bit 0 setzen
108  18    --nur noch bit 4 und 5 an
250  00    -- letzten beiden bits auf 0 setzen

von MaWin (Gast)


Lesenswert?

Dennis R. schrieb:
> Damit hast du bei jeder Änderung 2 Werte.
> Die neuen Portwerte und einen Zeitstempel ab wann dieser Wert gilt.

So isses
1
struct
2
{
3
  uint8_t ocr;
4
  uint8_t portb;
5
}
6
times[13];
7
8
uint8_t *ptr; // Y
9
uint8_t *endptr; // X
10
11
ISR (TIMER0_COMPA_vect)
12
{
13
  OCR0A=*ptr++; // LD R4,Y+ ; OUT OCR0A,R4 
14
  PORTB=*ptr++; // LD R4,Y+ ; OUT PORTB,R4
15
  if(ptr==endptr) ptr=&times; // CPSE Y,X ; RETI ; LDI Y,@times ; RETI
16
}
Und da reichen 9 Takte für die Interrupt-Routine, bei 16Mhz und 
minimaler Zeit von 5us also locker ausreichend, vermutlich passt sogar 
die C-Version rein. Mittlere CPU-Belastung maximal 12 Interrupts in 
0.5msec, also unter 10 Prozent, vermutlich reichen sogar 7 (weil alle 
PWM Ausgänge gleichzeitig auf 0 gehen werden).

Falk Brunner schrieb:
> ZEIG DEIN LAUFFÄHIGES PROGRAMM MIT DEN ENDLOSEN RESERVEN ODER HALT DEN
> MUND!

Nicht schreien, selber denken.

von Falk B. (falk)


Lesenswert?

@ MaWin (Gast)

>Und da reichen 9 Takte für die Interrupt-Routine, bei 16Mhz und
>minimaler Zeit von 5us also locker ausreichend, vermutlich passt sogar
>die C-Version rein.

BLA! Reine Theorie! Nicht nur, dass ein Interrupt noch ein Einsprung und 
eine reti braucht, es braucht auch Register, die gesichter werden 
wollen. jaja, in ASM kann man die exklusiv nutzen, in C eher nicht.

>Nicht schreien, selber denken.

Falsch! Ich habe es sogar VOLLSTÄNDIG und LAUFFÄHIG gemacht, und das 
schon vor Jahren!

Soft-PWM

Es ist nicht der Weisheit letzter Schluß, zeigt aber Grenzen einer 
einfachen C-Umsetzung!

von Kaan A. (deranfaenger)


Lesenswert?

Hey Leute das hab ich jetzt zwar verstanden, aber hier habe ich doch 
dann immer die gleiche Frequenz oder etwa nicht?

Denn ich definiere Masken für jeden Zeitabschnitt.. ok aber so habe ich 
nur einen Zähler (also bis OCR0A). Aber bei 6 verschiedenen Frequenzen 
habe ich ja 6 verschiedene Zähler

Vielleicht bin ich ja einfach zu blöd Oo

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Kaan A. (deranfaenger)

>Hey Leute das hab ich jetzt zwar verstanden, aber hier habe ich doch
>dann immer die gleiche Frequenz

Ja, das ist normal bei PWM.

>Denn ich definiere Masken für jeden Zeitabschnitt.. ok aber so habe ich
>nur einen Zähler (also bis OCR0A). Aber bei 6 verschiedenen Frequenzen
>habe ich ja 6 verschiedene Zähler

Warum solltest du 6 verschiedene Frequenzen brauchen?

von Kaan A. (deranfaenger)


Lesenswert?

Ja das ist doch schon die ganze Zeit mein Problem ich habe ganz oben 
schon erläutert, dass die Phase, Frequenz und Tastverhältnis von 
einander unabhängig variabel sind.

Der Nutzen ist hier eigentlich nicht wichtig, aber wenn du schon fragst 
und es vielleicht andere auch interessiert:
Der Mikrocontroller soll die Netzteile von Magnetrons eines 
Mikrowellenofens ansteuern. Die flexible Ansteuerung soll dazu dienen, 
den Heizprozess zu optimieren.
So als grobe Vorstellung. Auf genaueres möchte ich jetzt nicht eingehen.
Meine Kollegen sind aber Elektrotechniker und keine Informatiker und ich 
im dritten Semester ohne große Vorkenntnisse, weshalb ich auf Hilfe aus 
Foren angewiesen bin.

Wie gesagt erstmal soll das Programm problemlos bei mindestens 500 Hz 
PWM-Frequenz sprich 50 kHz PWM-Takt laufen. Dann muss ich schauen, wie 
hoch ich mit der Frequenz kommen kann. 2 kHz wäre das gewünschte Ziel.

Durch diesen und weitere Threads habe ich schon einiges gelernt. Danke 
dafür nochmal.
Dieses Wissen werde ich dann versuchen anzuwenden, um ein bestmögliches 
Ergebnis zu erhalten.
Die Aufgabe verlangt von mir halt schon einiges an Hirnschmalz aber da 
muss ich durch xD

von Falk B. (falk)


Lesenswert?

@ Kaan A. (deranfaenger)

>Der Nutzen ist hier eigentlich nicht wichtig,

DOCH! Siehe Netiquette!!!

>Der Mikrocontroller soll die Netzteile von Magnetrons eines
>Mikrowellenofens ansteuern. Die flexible Ansteuerung soll dazu dienen,
>den Heizprozess zu optimieren.

facepalm

>So als grobe Vorstellung. Auf genaueres möchte ich jetzt nicht eingehen.
>Meine Kollegen sind aber Elektrotechniker und keine Informatiker und ich
>im dritten Semester ohne große Vorkenntnisse, weshalb ich auf Hilfe aus
>Foren angewiesen bin.

Also ein Expertengemium ;-)

Warum um alles in der Welt glaubst du

a) dafür 2 kHz PWM,
b) dieser mit Phasenverschiebung und
c) mit 6 unabhängigen Frequenzen zu benötigen?

>Durch diesen und weitere Threads habe ich schon einiges gelernt. Danke
>dafür nochmal.

Naja. Dein eigentliches Problem liegt tiefer.

>Dieses Wissen werde ich dann versuchen anzuwenden, um ein bestmögliches
>Ergebnis zu erhalten.

Falsch. Bei einer Problemlösung sollte man zuerst das Problem gut 
analysieren und dann erst mögliche Lösungen betrachten. Du greifst 
einfach die nächstbeste Lösung, ohne zu wissen, ob sie sinnvoll und 
brauchbar ist.

>Die Aufgabe verlangt von mir halt schon einiges an Hirnschmalz aber da
>muss ich durch xD

Viel wichtiger als so ein technisches Detail ist ein gutes Grundkonzept. 
Das entscheidet über Erfolg oder Niederlage einers Projekt. Dabei darf 
man sich am Anfang nicht in technische Details verlieren. Genau das tust 
du aber.

von Kaan A. (deranfaenger)


Lesenswert?

> DOCH! Siehe Netiquette!!!
Ok mein Fehler, die hab ich nicht gelesen.

> Warum um alles in der Welt glaubst du
>
> a) dafür 2 kHz PWM,
> b) dieser mit Phasenverschiebung und
> c) mit 6 unabhängigen Frequenzen zu benötigen?
Weil wir in der Forschung tätig sind und dies die Vorgaben von meinem 
"Ausbilder" sind. Wie gesagt 500 Hz sind das Minimum, da in dem Bereich 
bis 1 kHz gearbeitet wird. Aber da das zu entwickelnde Board flexibel 
und für die zukunftsorientiert (wenn man mit der Frequenz hoch gehen 
möchte) einsetzbar sein soll, soll eine mögliche maximale Frequenz von 2 
kHz erreicht werden. Wenns nicht geht muss man eben auf diesen "Luxus" 
verzichten und sich mit weniger zufrieden geben. Mindestens 1 kHz 
sollten aber drin sein.

> Falsch. Bei einer Problemlösung sollte man zuerst das Problem gut
> analysieren und dann erst mögliche Lösungen betrachten. Du greifst
> einfach die nächstbeste Lösung, ohne zu wissen, ob sie sinnvoll und
> brauchbar ist.
Wie meinst du das mit dem analysieren. Ich denke das ist schon klar 
Oo...
Ja da hast du wohl recht. Die Mischung aus Zeitmangel, Stress und 
fehlender Erfahrung hat mir wohl einen Tunnelblick verpasst.
Vorschläge, wie ich es denn das nächstes mal besser machen kann sind 
willkommen :)

> Viel wichtiger als so ein technisches Detail ist ein gutes Grundkonzept.
> Das entscheidet über Erfolg oder Niederlage einers Projekt. Dabei darf
> man sich am Anfang nicht in technische Details verlieren. Genau das tust
> du aber.
Verstehe. Ich soll mir zuerst so ein Grundgerüst bauen, wie das Ganze 
denn aufgebaut werden soll bevor ich mich an das technische und die 
Implementierung mache.

von Kaan A. (deranfaenger)


Lesenswert?

Aber um nochmal zum Thema zurückzukommen:

Ist mein Vorgehen grundsätzlich falsch bzw. schlecht?

Da ich ja (im worst case) 6 verschiedene Frequenzen habe, aber nur mit 
einem Timer inkrementiere, Takten alle pwmCounter in der Timer Frequenz.
Der pwmCounter wird jedesmal umgerechnet(/Timerfrequenz *pwmFrequenz), 
um  herauszufinden, ob sie das Tastverhältnis oder das Periodenende 
erreicht hat. Diese Berechnung nimmt leider die meiste Zeit in Anspruch, 
ist in meinen Augen aber unumgänglich. Um das Dividieren zu verhindern, 
werden Konstanten vordefiniert mit denen ich multiplizieren kann.

Eine Lösung, die mir gerade einfällt wäre:
Werte (abhängig von der jeweiligen PWM-Frequenz) zu definieren, um die 
ich dann den zugehörigen pwmCounter inkrementiere.

von Falk B. (falk)


Lesenswert?

@ Kaan A. (deranfaenger)

>Weil wir in der Forschung tätig sind und dies die Vorgaben von meinem
>"Ausbilder" sind.

Man braucht 500-2000 Hz PWM um eine HEIZUNG zu steuern? Und 6 
verschiedene Frequenzen? Glaub ich nicht so ganz. Ich wette, in der 
Heizungssteuerung wird die PWM über einen einfachen Filter in 
Gleichspannung gewandelt und gut.

> Wie gesagt 500 Hz sind das Minimum, da in dem Bereich
>bis 1 kHz gearbeitet wird. Aber da das zu entwickelnde Board flexibel
>und für die zukunftsorientiert (wenn man mit der Frequenz hoch gehen
>möchte) einsetzbar sein soll, soll eine mögliche maximale Frequenz von 2
>kHz erreicht werden. Wenns nicht geht muss man eben auf diesen "Luxus"
>verzichten und sich mit weniger zufrieden geben. Mindestens 1 kHz
>sollten aber drin sein.

Wenn es denn WIRKLICH min. 1 kHz und 6 unabhängige Frequenzen sein 
müssen, solltest du erst recht einen passenen Mikrocontroller nutzen, 
der genügen (6) Timer hat, die deine unabhängigen PWMs ereugen kann. 
Z.B. einer der neueren ATXmegas oder einen noch leistungsfähigeren ARM. 
In Software wird as nix gescheites, zum du als Anfänger genügend andere 
Sachen zu tun hast. Und da es um wenige Einzelexemplare geht, ist auch 
der Preis des Controllers vollkommen egal.

von Falk B. (falk)


Lesenswert?

@ Kaan A. (deranfaenger)

>Ist mein Vorgehen grundsätzlich falsch bzw. schlecht?

Ja.

>Da ich ja (im worst case) 6 verschiedene Frequenzen habe, aber nur mit
>einem Timer inkrementiere, Takten alle pwmCounter in der Timer Frequenz.
>Der pwmCounter wird jedesmal umgerechnet(/Timerfrequenz *pwmFrequenz),
>um  herauszufinden, ob sie das Tastverhältnis oder das Periodenende
>erreicht hat. Diese Berechnung nimmt leider die meiste Zeit in Anspruch,
>ist in meinen Augen aber unumgänglich. Um das Dividieren zu verhindern,
>werden Konstanten vordefiniert mit denen ich multiplizieren kann.

Vergiss die Softwarelösung. Du steckst sinnlos Energie und Zeit in eine 
Nebensächlichkeit, die du mit dem passenden Controller am einem Tag 
fertig hast.

von Irgendwer23 (Gast)


Lesenswert?

Wie andere schon sagten:

Ich persönlich würd ja einen Controller mit OC-Timern oder PWM-Blöcken 
nehmen.
Schöne Beispiele sind viele STM32 oder diverse PICs.

Die STM32 haben diese praktischen Flex-Timer, von denen macht 1 Timer 4 
PWMs (mit gleicher Frequenz).
Viele PICs haben mehrere OC-Timer, die sich auch hervorragend für PWM 
eignen.

Beide generieren die PWM in Hardware, schnell und mit wenig Software 
Overhead.

Merke: spezialisierte Hardware schlägt jede Software um Kilometer. Und 
weil PWM-Blöcke Standardfeatures in Controllern sind, warum sich damit 
in Software abplagen?

Für eine Heizung würde ich das allerdings tatsächlich in Softare lösen. 
Mit 0,5Hz, was schon übertrieben schnell ist ;-)

von Kaan A. (deranfaenger)


Lesenswert?

Eine Heizung muss nicht angesteuert werden, sondern eine 
Mikrowelle(keine gewöhnliche Haushaltsmikrowelle). Glaubt mir die 
Aufgabenstellung lautet wirklich, dass alle Einstellungen der PWM 
variabel sein sollen.

Und ja, das mit der Hardwarelösung hatte ich zu Beginn auch 
vorgeschlagen. Doch das würde den Sinn der Sache verfehlen (nämlich das 
Programmieren an sich zu üben) hieß es. Und eine Softwarelösung war 
erwünscht.

Ich hatte erst ATXmega im Sinn. Aber wie gesagt da eine Softwarelösung 
erwünscht war hätte auch der ATMega88pa gereicht...
Jetzt merke ich ja, dass das nicht gerade easy ist.

Naja ich werde trotzdem schauen wie viel maximal geht um dann Begründen 
zu können, warum das Ganze hardwaretechnisch gelöst werden sollte.

Danke trotzdem für eure Hilfe und Zeit.

Wenn jemand trotzdem eine Anregung hat, wie man die Frequenz variabel 
gestalten kann, nehme ich sie gerne an :)

von Dennis R. (dennis_r93)


Lesenswert?

Ich denke der Code von MaWin ist gut.
An seinem Umgangston sollte er noch etwas arbeiten.

Hast du ihn mal ausprobiert?
Ich habe leider keine AVR's, kann mir aber vorstellen, dass er
weit unter den 80 Zyklen bleibt.

Die Struktur times ist 13 Felder lang, das reicht um 6 PWMs 
Phasenmoduliert abzuspeichern.

Wenn die die Struktur im RAM ist kannst du sie auch zur Laufzeit 
außerhalb der ISR anpassen.


MaWin schrieb:
> struct
> {
>   uint8_t ocr;
>   uint8_t portb;
> }
> times[13];
>
> uint8_t *ptr; // Y
> uint8_t *endptr; // X
>
> ISR (TIMER0_COMPA_vect)
> {
>   OCR0A=*ptr++; // LD R4,Y+ ; OUT OCR0A,R4
>   PORTB=*ptr++; // LD R4,Y+ ; OUT PORTB,R4
>   if(ptr==endptr) ptr=&times; // CPSE Y,X ; RETI ; LDI Y,@times ; RETI
> }

Ansonsten kannst du auch auf Prozessoren wechseln die 6 Hardwaretimer 
haben oder ein schnelleren Prozessortakt.
Die STM32 Serie kann ich auch nur empfehlen.

Viele Grüße
Dennis

von Kaan A. (deranfaenger)


Lesenswert?

Den Code selbst hab ich zwar nicht verstanden(insbesondere die letzte 
Zeile, die mit der if-Bedingung), aber ich nehme an dass er zu deinem 
vorangehenden Beitrag gehört.
> Das mit dem Zeitstempel ist so gedacht, dass du neben den Werten einen
> Zeitstempel hast der dir sagt, ab wann dieser wert übernommen werden
> soll.
> Damit hast du bei jeder Änderung 2 Werte.
> Die neuen Portwerte und einen Zeitstempel ab wann dieser Wert gilt.
> Dabei solltest du dir aber mit einem Index merken, bei welchen WertZeit
> Paar du gerade bist, damit du dir das Suchen sparen kannst. damit kannst
> du z.B. mit 7 Paaren a 2 byte für 6 Kanäle die zeit merken.
Aber hierbei habe ich ja wieder für alle PWM Ausgänge die gleiche 
Frequenz. Wenn ich mich nicht irre, ist das ja sogar der "intelligente 
Lösungsweg" aus dem Soft-PWM Tutorial 
http://www.mikrocontroller.net/articles/Soft-PWM#Erster_Versuch

von Falk B. (falk)


Lesenswert?

@ Kaan A. (deranfaenger)

>Eine Heizung muss nicht angesteuert werden, sondern eine
>Mikrowelle(keine gewöhnliche Haushaltsmikrowelle).

Schon klar.

> Glaubt mir die
>Aufgabenstellung lautet wirklich, dass alle Einstellungen der PWM
>variabel sein sollen.

Glaub ich dir. Ersten, weil man flexibel bleiben will und zweitens weil 
die Leute wahrscheinlich auch nicht den vollen Durchblick haben, was sie 
WIRKLICH BRAUCHEN.

>Und ja, das mit der Hardwarelösung hatte ich zu Beginn auch
>vorgeschlagen. Doch das würde den Sinn der Sache verfehlen (nämlich das
>Programmieren an sich zu üben) hieß es.

Programmieren üben ist gut, im Lehrbereich ist es schließlich der 
wesentliche zweck. ABER!

> Und eine Softwarelösung war erwünscht.

>Ich hatte erst ATXmega im Sinn. Aber wie gesagt da eine Softwarelösung
>erwünscht war hätte auch der ATMega88pa gereicht...

HIER beiginnt das Problem! Denn es ist NIE sinnvoll, einen Lösungsweg 
vorzugeben! Dieser muss sich aus der Problemanalyse und Lösungssysthese 
ergeben! WENN dann mehrere Lösungen aufgezeigt werden UND die 
Softwarelösung als machbar, wenn gleich aufwändiger erscheint, DANN kann 
man sich dafür entscheiden.
Wenn es nur um 6 Kanäle mit gleicher Frequenz gehen würde, könnte man es 
per Software und etwas Anstrengung (ISR in reinem Assembler) hinkriegen.
Mit verschiedenen Frequenzen ist das deutlich schwieriger. Damit übst du 
nicht wirklich das Programmieren sonder brichst dir sinnlos einen ab, 
beim Versuch, eine bestimmte Hardware bis an die Grenze des Machbaren 
auszureizen. Das ist kein Job für Anfänger und Lernende, sondern für 
Fortgeschrittene und Profis. Lernen wirst du dabei nicht so viel, wohl 
aber
viel fluchen.

>Naja ich werde trotzdem schauen wie viel maximal geht um dann Begründen
>zu können, warum das Ganze hardwaretechnisch gelöst werden sollte.

Oder eben halt so. Der akademische Weg . . .

>Wenn jemand trotzdem eine Anregung hat, wie man die Frequenz variabel
>gestalten kann, nehme ich sie gerne an :)

Du musst in gewisser Weise mit deinem 200kHz Interrupt eine Tabelle 
ausgeben, genau so, wie es ein programierbarer Funktionsgenerator macht. 
Ein anderes Stück Software muss diese Tabelle sinnvoll mit Inhalten 
füllen. Der Knackpunkt dabei ist, dass die Periodendauer deiner Ausgabe 
konstant ist, und zwar für alle Kanäle. Also muss sie ein ganzzahliges 
Vielfaches der einzelnen Frequenzen sein. Wenn man nur 2, 1, 0,5 und 
0,25 kHz zulässt ist das kein Problem. Ansonsten, viel Spaß.

von Udo S. (urschmitt)


Lesenswert?

Mal ne blöde Zwischenfrage:

Kann man Mikrowellen-Magnetrons überhaupt so schnell schalten?

von Falk B. (falk)


Lesenswert?

@ Udo Schmitt (urschmitt)

>Kann man Mikrowellen-Magnetrons überhaupt so schnell schalten?

Er schaltet doch nicht das Magnetron, sondern diverse Steuereingänge 
einer Steuerelektronik. Dort sitzen mit hoher Wahrscheinlichkeit 
Tiefpässe, die daraus wieder Gleichspannung zu Ansteuerung machen. Und 
selbst wenn nicht, kann man ein Magnetrom auch im Burstbetrieb der PWM

von avion23 (Gast)


Lesenswert?

Du kannst dir Ideen von DDS klauen:
http://en.wikipedia.org/wiki/Direct_Digital_Synthesis

Damit kann man z.B. schön die Ansteuerung von Servos lösen.

Deine konkrete Aufgabe kann man herunterbrechen auf events, die in einem 
bestimmten Zeitabstand von einander passieren sollen.

von Udo S. (urschmitt)


Lesenswert?

Falk Brunner schrieb:
> Dort sitzen mit hoher Wahrscheinlichkeit
> Tiefpässe, die daraus wieder Gleichspannung zu Ansteuerung machen.

Zumindest Magnetrons, die in Mikrowellengeräten verbaut sind kann man 
nicht im Teillastbetrieb laufen lassen, also sehe ich hier keinen Sinn 
in Tiefpass und lineare Spannung zur Steuerung.

Falk Brunner schrieb:
> Und
> selbst wenn nicht, kann man ein Magnetrom auch im Burstbetrieb der PWM

Das ist ja meine Frage:
Bei einem herkömmlichen Mikrowellengerät für die Küche geschieht das 
Ein/Ausschalten für reduzierte Leistung aber im Bereich von einigen 
Sekunden.
Was wird denn da an oder abgeschaltet? Die Hochspannung?
Und wie schnell kann man das machen? Wirklich im Bereich von bis zu 
einigen 10kHz?

von Falk B. (falk)


Lesenswert?

@ Udo Schmitt (urschmitt)

>Zumindest Magnetrons, die in Mikrowellengeräten verbaut

Es geht nicht um Küchenmikrowellenherde!

>Bei einem herkömmlichen Mikrowellengerät für die Küche geschieht das
>Ein/Ausschalten für reduzierte Leistung aber im Bereich von einigen
>Sekunden.
>Was wird denn da an oder abgeschaltet? Die Hochspannung?

Wahrscheinlich.

>Und wie schnell kann man das machen? Wirklich im Bereich von bis zu
>einigen 10kHz?

Magnetrons werden u.a. im Radar für kurze Pule im us Bereich eingesetzt.
Magnetrons sind modulierbar.

von Kaan A. (deranfaenger)


Lesenswert?

Falk Brunner schrieb:
> Du musst in gewisser Weise mit deinem 200kHz Interrupt eine Tabelle
> ausgeben, genau so, wie es ein programierbarer Funktionsgenerator macht.
> Ein anderes Stück Software muss diese Tabelle sinnvoll mit Inhalten
> füllen. Der Knackpunkt dabei ist, dass die Periodendauer deiner Ausgabe
> konstant ist, und zwar für alle Kanäle. Also muss sie ein ganzzahliges
> Vielfaches der einzelnen Frequenzen sein. Wenn man nur 2, 1, 0,5 und
> 0,25 kHz zulässt ist das kein Problem. Ansonsten, viel Spaß.
Danke, die Lösung funktioniert ganz gut, jedoch schränkt sie die 
Flexibilität der wählbaren Frequenzen ein. Ist also leider nicht 
erwünscht.

Es scheint, dass wir eine mögliche Implementierung gefunden haben. Ich 
werde sie demnächst ausprobieren und hier berichten, falls jemand 
Interesse daran hat.

Für den äußersten Notfall habe ich auch einen geeigneten Mikrocontroller 
gefunden. Nämlich den AT32UC3L016. Das ist der "kleinste" µC mit 6 
Timern den ich von Atmel gefunden habe.

Danke nochmal für eure Zeit.
Grüße

von Mark B. (markbrandis)


Lesenswert?

Kaan A. schrieb:
> Für den äußersten Notfall habe ich auch einen geeigneten Mikrocontroller
> gefunden. Nämlich den AT32UC3L016. Das ist der "kleinste" µC mit 6
> Timern den ich von Atmel gefunden habe.

Warum sollte dies den "äußersten Notfall" darstellen?

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.