Forum: Mikrocontroller und Digitale Elektronik Atmega32 PWM dead time


von Lesso (Gast)


Lesenswert?

Hallo!
Ich habe eine Frage, ich komme nicht drauf wie ich das am einfachsten 
machen kann, für euch aber wohl kein Problem ich habe den Quellcode 
hier:
1
#include <avr/io.h>
2
 
3
int main()
4
{
5
  DDRD = (1 << PD4) | (1 << PD5); 
6
 
7
  TCCR1A = (1<<COM1A1) | (1<<WGM11) | (1<<COM1B1) |(1<<COM1A0);
8
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
9
 
10
  ICR1 = 9;
11
 
12
 
13
  OCR1A = 4;
14
  OCR1B = 4;
15
 
16
 
17
  while( 1 )
18
    ;  
19
}
Also eine PWM mit 50% duty cycle und PD4 und PD5 sind jeweils 
invertierend, das Problem, ich brauche eine kleine dead time dazwischen, 
nur wie kann ich das mit dem AVR am einfachsten bewerkstelligen? Habt 
ihr ne Idee? denn auch wenn ich jetzt den OCR1A auf 3 setze dann habe 
ich zwar nur einmal eine Flanke die an den beiden Ausgängen gleichzeitig 
in umgekehrter Richtung laufen, aber ich darf eben garkeine 
gleichzeitigen Spannungsänderungen haben, deshalb die dead time.

Vielen Dank schonma im vorraus

Lesso

von Jim G. (jimg)


Lesenswert?

Einfachste lösung, auch wenn ich von meine Nachposter erschlagen werde.
Du baust zwischen OCR1A und OCR1B folgendes ein:
1
 for(i=0;i<d;i++){
2
 }

Diese schleife macht im Grunde garnichts, außer den µC für ein kurzen 
Moment zu beschäftigen. Dannach macht der µC einfach weiter im 
Programm...

Vergiss nicht nach
1
int main()
2
{
folgende zeile:
1
int i,d;

in d kannst du ein Wert speichern bis wohin der µC erst zählen muss, 
bevor er weiter macht... Kannst auch alternativ d weg lassen und den 
Wert direkt hinschreiben.

wie schnell der µC gezählt hat, liegt an seine Frequenz. 
(logischerweise)... daher kann man, wenn man die Frq. kennt, genau 
bestimmen wie lange er warten soll.

Ach ja... warum ich gleich geschlagen werde:
Du beschäftiges den kompletten µC und  der kann wärend der "sinnlosen" 
Schleife nichts machen, außer i aufwärts zählen.

EDIT:
1
#include <avr/io.h>
2
 
3
int main()
4
{
5
  DDRD = (1 << PD4) | (1 << PD5); 
6
 
7
  TCCR1A = (1<<COM1A1) | (1<<WGM11) | (1<<COM1B1) |(1<<COM1A0);
8
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
9
 
10
  ICR1 = 9;
11
 
12
 
13
  OCR1A = 4;
14
  OCR1B = 4;
15
 
16
 
17
  while( 1 )
18
    ;  
19
}

^^ Irgend eine wichtige Komponente fehlt da noch...
1
while(1);
 ist zwar eine Schleife, aber du führst dein Programm außerhalb der 
Schleife aus... der µC macht also dies nur einmal beim Start und 
niewieder. Weiß ja nicht, was der µC genau um großen und ganzen machen 
soll.
Soll er das nur einmal beim start machen?

von Lesso (Gast)


Lesenswert?

Hallo, Danke für deinen Post

Nein das soll er immer machen heißt das mein Progamm müsste so ausehen:
1
#include <avr/io.h>
2
 
3
int main()
4
{ int i;
5
  DDRD = (1 << PD4) | (1 << PD5); 
6
 
7
  TCCR1A = (1<<COM1A1) | (1<<WGM11) | (1<<COM1B1) |(1<<COM1A0);
8
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
9
 
10
  ICR1 = 9;
11
 
12
 
13
  while( 1 )
14
  {  OCR1A = 4;
15
     for(i=0;i<100;i++)
16
     OCR1B = 4;
17
  };  
18
}

Oder muss ich hier trotzdem den OCR1A auf 3 setzen?
Mein Takt ist 6MhZ heißt das also er wartet 0,1ms mit dieser Schleife?
Achja, und mein µC hat sowieso nichts anderes zu tun als diese 2 PWM zu 
erzeugen, also ist es egal wie ausgelastet er nur mit diesen PWM ist.
Danke

von lesso (Gast)


Lesenswert?

aber das kann ja garnicht funktionieren weil der timer ja nen interrupt 
auslöst wenn er bei 10 ist und dabei werden ja die beiden pwm 
gleichzeitig gesetzt bzw. Gelöscht werden aber gibts eine andere 
möglichkeit zb. Den timer 0 oder 2 zu verwenden ? Aber bei denen kann 
ich ja keine obergrenze einstellen wo mein interrupt auslöst der ist ja 
immer bei 255 oder?

von Jim G. (jimg)


Lesenswert?

Welcher Interrup?

Das was ich sehe, sieht nach kein Interrup aus. Kann auch sein, dass ich 
bei AVRs den Interrup noch nicht kenne... Habe bis jetzt nur SAB-µC 
programmiert.


Ich würde es so schreiben:
1
#include <avr/io.h>
2
 
3
int main()
4
{ int i;
5
6
  do
7
  {
8
  DDRD = (1 << PD4) | (1 << PD5); 
9
 
10
  TCCR1A = (1<<COM1A1) | (1<<WGM11) | (1<<COM1B1) |(1<<COM1A0);
11
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
12
 
13
  ICR1 = 9;  
14
15
   OCR1A = 4; 
16
     for(i=0;i<100;i++)
17
     {}
18
   OCR1B = 4;
19
  }
20
  while(1);  
21
}

von lesso (Gast)


Lesenswert?

hallo
Habe deinen code probiert aber es funktioniert nicht hat noch jemand 
eine idee?

Mfg

von Mehmet K. (mkmk)


Lesenswert?

Das Stichwort heisst "Dead Time Generator" und ist z.Bsp. bei einigen 
AtTiny's eingebaut (z.Bsp. AtTiny45).

von Lesso (Gast)


Lesenswert?

Ja diese µC kenn ich wo das eingebaut ist, allerdings habe ich den nicht 
bei der Hand und möchte ihn auch nicht extra nur für diese 
verhältnismäßig "einfache" Anwendung kaufen. Muss doch auch eine andere 
Möglichkeit geben

von Jim G. (jimg)


Lesenswert?

Hast du auch die Verzögerung groß genung gewählt... du muss 
berücksichtigen, dass der mit voller Kapa zählt... also 16Mio 
Zählvorgänge in der Sekunde... und da er nur bis 100 zählt schaft er das 
in 0,00000625 Sekunden (6,25µs)... kann eventuel was kurz sein. Ich weiß 
ja nicht wieviel zeit unterschied sein muss. Ich würde zum test wirklich 
mal was übertreiben und 50ms wählen, also bis 800.000 zählen lassen.

Ach ja... die Zählgeschwindigkeit ist +-... ich gehe mal davon aus, dass 
du keinen Quarz angschlossen hast, der genau 16Mhz liefert.

von Gast (Gast)


Lesenswert?

Wenn der µC eh nichts anderes tun soll. Polle die ganze Zeit den 
Ausgangspin der PWM und wenn er gesetzt wird wartest deine "Totzeit" ab 
und dann schaltest ihn erst auf 0. Analog hierzu dann das 1 setzen.

Statt dem pollen kann man das natürlich auch per Interrupt lösen. Dann 
eben die Interrupts die der Timer bereitstellt nutzen.

von Lesso (Gast)


Lesenswert?

Hallo, kannst mir das genauer erklären verstehe gerade nicht ganz wie du 
das meinst !?
Danke

von Jim G. (jimg)


Lesenswert?

Ein Interrup ist eine Anweisung, die neben den Hauptprogramm läuft...

der Timer-interrup kann also im Hintergrund zählen und unterbricht das 
Hauptprogramm und führ seine anweisung aus... nach der anweisung macht 
das Hauptprogramm an der stelle weiter, wo es auf gehört hat.

von Lesso (Gast)


Lesenswert?

Ja, was ein Interrupt ist, weiß ich, nur was "Gast" mit seinem Posting 
meinte, hab ich absolut nicht verstanden

von Peter D. (peda)


Lesenswert?

Jim G. schrieb:
>
1
>   TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
2
>   ICR1 = 9;
3
>

Deine PWM dauert also 10 CPU-Zyklen, das ist sportlich.
Da kannst Du nichts mehr in C machen und erst recht nichts mit 
Interrupts.

Die einzige Möglichkeit ist purer Assembler.
Aber da ist der Mega32 mit Atombomben auf Pantoffeltierchen geschossen.
Ein ATtiny13 reicht da dicke.

>
1
>    OCR1A = 4;
2
>      for(i=0;i<100;i++)
3
>      {}
4
>    OCR1B = 4;
5
>

Das ist Quatsch.
Es ist wurscht, wann Du die PWM-Register setzt, sie werden immer mit 
TCNT1 verglichen. Ein gleicher Wert setzt also die Pins zur gleichen 
Zeit.


Peter

von Matthias (Gast)


Lesenswert?

>      for(i=0;i<100;i++)
>      {}

Was ich hier so die letzten Tage gelesen habe könnte es sein, dass 
dieser Code-Schnippsel sowieso vom Compiler wegoptimiert wird?

von MeinerEiner (Gast)


Lesenswert?

Wird wegoptimiert, weil nutzlos.
Die Zählvariable als volatile markieren, dann bleibt sie drin.
Oder in der for ein nop ausführen lassen.

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.