Forum: Mikrocontroller und Digitale Elektronik Fast PWM Abschalten


von Juli D. (juli_d)


Lesenswert?

Hi Leute :),
ich habe hier ein kleines Projekt mit einem Mega16 am laufen bei dem ich 
einen Gleichstrommotor mit 9V bidirektional ansteuer. Ich hatte bereits 
ne Softwarelösung für die PWM und das hat wunderbar funktioniert. Jetzt 
bin ich aber auf FastPWM umgestiegen und habe ein kleines Problem.

Mein Motortreiber (selbstgebaute H-Brücke) wird über zwei Signale 
angesteuert. die dürfen nicht gleichzeitig high sein, sonst geht die 
H-Brücke drauf.

Beim Richtungswechsel muss ich also die PWM für den einen Pin abschalten 
und dann beim anderen Pin starten. Genau da liegt auch mein Problem. wie 
bekomme ich die PWM abgeschaltet? Also, dass der abgeschaltete Pin auf 
low bleibt und der andere zu arbeiten beginnt?

Ich habe das Programm mal stark abgespeckt. es geht mir eigentlich nur 
um die Zeile mit "Hier möchte ich die PWM-Ausgabe an dem OC1B pin 
stoppen"
1
int main(void)
2
  {
3
  DDRD  =0b11111111;
4
  PORTD  =0b00000000;
5
     srand(get_seed());
6
  int dauer, dir, speed, i, count, changeid; 
7
  char speedstring [2];
8
  
9
  
10
  //FastPWM Einstellung
11
  DDRD = 0b00110000;
12
  PORTD = 0b00000000;
13
  TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM10);
14
  TCCR1B = (1<<WGM12) | (1<<CS11);
15
     
16
       
17
  while(1)
18
  {
19
    
20
    change(&speed, &dir);
21
    dauer=rand()%15+1;
22
23
    if(dir==0) //Rückwärts-Modus
24
    {
25
      TCCR1A = (1<<COM1A1);
26
      TCCR1A &= ~(1<<COM1B1); //Hier möchte ich die PWM-Ausgabe an dem OC1B pin stoppen
27
      OCR1B = (int)speed*256/20;
28
    }
29
    else if(dir==1) //Stop-Modus
30
    {
31
      TCCR1A &= ~(1<<COM1A1);
32
      TCCR1A &= ~(1<<COM1B1);
33
    }
34
    else //Vorwärts-modus
35
    {
36
      TCCR1A = (1<<COM1B1);
37
      TCCR1A &= ~(1<<COM1A1);
38
      OCR1B = (int)speed*256/20;
39
    }
40
      
41
      
42
    for(i=0; i<dauer; i++)
43
    _delay_ms(200);
44
  }       
45
}

: Bearbeitet durch User
von Juli D. (juli_d)


Lesenswert?

Das mit "TCCR1A &= ~(1<<COM1B1);" war nur ein versuch um es zu stoppen. 
hat aber nicht hingehauen. gebt es vielleicht anders eine möglichkeit 
die pwm zu stoppen?

von Thomas E. (thomase)


Lesenswert?

1
OCR1B = 0;  //Hier möchte ich die PWM-Ausgabe an dem OC1B pin stoppen

mfg.

von Peter D. (peda)


Lesenswert?

Juli D. schrieb:
> Das mit "TCCR1A &= ~(1<<COM1B1);" war nur ein versuch um es zu stoppen.
> hat aber nicht hingehauen.

Doch, sollte gehen.
Nur sollte man erst den einen abschalten und danach den anderen ein.
Dazwischen ein kleines Delay kann auch nicht schaden.

von Holger L. (max5v)


Lesenswert?

Juli D. schrieb:
> TCCR1A = (1<<COM1A1);

Setzt das komplette Register, (1<<WGM10) wird gelöscht und der CTC modus 
wird gesetzt.
TCCR1A |= ( 1 << COM1A1 ) wolltest du vermutlich schreiben ?

Sehe ich es richtig das der Timer als Fast PWM, 8-bit mit Top 0x00FF 
eingestellt ist ?

von Juli D. (juli_d)


Lesenswert?

Danke euch beiden.
@Thomas Eckmann:
Das habe ich gerade ausprobiert und es klappt einwandfrei. Gestern Abend 
hatte ich das schon probiert und hatte wohl noch einen anderen Bug drin.
Schaltet der µC denn pro Periode kurz ein und sofort wieder aus oder 
geht er gar nicht erst auf high?

@Peter Dannegger:
Thomas Eckmanns Lösung funktioniert ja soweit ganz gut. Ich werde aber 
trotzdem noch kurz probieren die "alte" Methode zum laufen zu bringen. 
Danke dir

von Juli D. (juli_d)


Lesenswert?

@Holger L:
achso, du meinst, wenn ich "TCCR1A = (1<<COM1A1)" verwende beschreibe 
ich das ganze Register und die vorherigen Einstellungen (zb (1<<WGM10) ) 
werden mit 0 überschrieben?

von Falk B. (falk)


Lesenswert?

Ja, siehe Bitmanipulation.

von c-hater (Gast)


Lesenswert?

Juli D. schrieb:

> ich habe hier ein kleines Projekt mit einem Mega16 am laufen bei dem ich
> einen Gleichstrommotor mit 9V bidirektional ansteuer. Ich hatte bereits
> ne Softwarelösung für die PWM und das hat wunderbar funktioniert. Jetzt
> bin ich aber auf FastPWM umgestiegen und habe ein kleines Problem.
>
> Mein Motortreiber (selbstgebaute H-Brücke) wird über zwei Signale
> angesteuert. die dürfen nicht gleichzeitig high sein, sonst geht die
> H-Brücke drauf.
>
> Beim Richtungswechsel muss ich also die PWM für den einen Pin abschalten
> und dann beim anderen Pin starten. Genau da liegt auch mein Problem.

Das ist aber eigentlich überhaupt kein Problem. Man muß nur zwei 
Eigenschaften der AVR-Timer-PWM kennen:

1) Es gibt immer genau einen OCR-Wert, bei dem die PWM garnichts macht,
   der Pegel am OCx-Pin also konstant ist.
2) In allen PWM-Modi (also auch bei Fast-PWM) werden neu zugewiesene 
Werte
   der OCR-Register von der Hardware immer synchron übernommen und zwar 
an
   einem ganz bestimmten Punkt des PWM-Zyklus (der sich allerdings je 
nach
   PWM-Modus unterscheiden kann).

Das alles steht haarklein im Datenblatt aufgedröselt für jeden zum 
Nachlesen.

Der einzige kritische Punkt bei der Ansteuerung eine DC-Motors könnte 
also beim Richtungswechsel sein, wenn die Software nix taugt, die ihn 
ansteuert, also dein Werk. Die muß einfach nur folgendes sicherstellen:

1) Die OCR-Werte für beide Bewegungsrichtungen sind immer 
"gleichzeitig"
   zu schreiben
2) Mindestens für eine Bewegungsrichtung muß immer der "neutrale"
   OCR-Wert geschrieben werden.

2) ist absolut trivial zu erreichen, 1) hingegen erfordert eine 
Synchronisation des Schreibvorgangs der OCR-Register mit dem PWM-Zyklus 
der Hardware und die Herstellung der Sicherheit, dass dieser 
Schreibvorgang durch nichts und niemanden unterbrochen wird.

Sprich: eine exclusiv ausgeführte ISR. Und zwar idealerweise eine, die 
möglichst kurz nach dem Zeitpunkt ausgeführt wird, zu dem die Hardware 
die OCR-Werte für den aktuellen Zyklus übernommen hat.

> wie
> bekomme ich die PWM abgeschaltet?

Das ist die falsche Frage. Weil: sie muß überhaupt nicht abgeschaltet 
werden, um dein Problem sinnvoll zu lösen, ganz im Gegenteil, die 
Hardware gibt hier vor, dass die beste, sinnvollste und effizienteste 
Lösung ist, genau das nicht zu tun...

von Peter D. (peda)


Lesenswert?

c-hater schrieb:
> 1) Es gibt immer genau einen OCR-Wert, bei dem die PWM garnichts macht,
>    der Pegel am OCx-Pin also konstant ist.

Aber nicht im fast Mode, da gibt es bei 0 einen Spike:

"If the OCR1x is set equal to BOTTOM (0x0000) the output will be a 
narrow spike for each TOP+1 timer clock cycle. Setting the OCR1x equal 
to TOP will result in a constant high or low output (depending on the 
polarity of the output set by the COM1x1:0 bits.)"

von Karl H. (kbuchegg)


Lesenswert?

Auch sollte man nicht vergessen, das man mit den COM Bits den Ausgang 
lediglich an den Timer koppelt.
Wird der Pin durch löschen der COM Bits wieder vom Timer abgekoppelt, 
ist noch lange nicht sicher gestellt, dass der Pin danach auch wieder 
auf low ist. Die COM Bits sorgen dafür, dass vom Timer das PORT Register 
angesteuert wird. Will man also sicher gehen, dass der Pin nach dem 
Lösen vom Timer auf Low ist, dann muss man im PORT Register das 
jeweilige Ausgabebit löschen.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Peter D. schrieb:

> c-hater schrieb:
>> 1) Es gibt immer genau einen OCR-Wert, bei dem die PWM garnichts macht,
>>    der Pegel am OCx-Pin also konstant ist.
>
> Aber nicht im fast Mode, da gibt es bei 0 einen Spike:

Wer hat behauptet, daß der Wert, bei dem garnichts passiert, immer Null 
wäre?

Noch viel schlimmer: Die Lösung postest du doch auch gleich in deinem 
eigenen Zitat mit:

> Setting the OCR1x equal
> to TOP will result in a constant high or low output (depending on the
> polarity of the output set by the COM1x1:0 bits.)"

Wie doof muß man nach meiner doch ziemlich expliziten Ansage eigentlich 
sein, um sie nicht zu erkennen? OK, man muß wohl C-Fetischist sein, 
zumindest das wird hier wohl doch irgendwie endgültig klar...

Paßt nicht zu Implementierung der vorhandene Lib, also geht's nicht, 
mehr noch: es kann generell garnicht gehen...

Genau das ist, was ich so vehement anprangere: die Vernichtung der 
Fantasie und des gesunden Menschenverstandes allein durch die excessive 
und exclusive Verwendung von C. Das macht offensichtlich einfach nur 
dumm und unflexibel. Nicht mehr und nicht weniger.

von Thomas E. (thomase)


Lesenswert?

c-hater schrieb:
> Wie doof muß man nach meiner doch ziemlich expliziten Ansage eigentlich
> sein, um sie nicht zu erkennen? OK, man muß wohl C-Fetischist sein,
> zumindest das wird hier wohl doch irgendwie endgültig klar...
>
> Paßt nicht zu Implementierung der vorhandene Lib, also geht's nicht,
> mehr noch: es kann generell garnicht gehen...
>
> Genau das ist, was ich so vehement anprangere: die Vernichtung der
> Fantasie und des gesunden Menschenverstandes allein durch die excessive
> und exclusive Verwendung von C. Das macht offensichtlich einfach nur
> dumm und unflexibel. Nicht mehr und nicht weniger.

Deine Domina immer noch im Urlaub?

Warum soll der von dir beschriebene Kleinkram in C nicht gehen?

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Thomas E. schrieb:

> Warum soll der von dir beschriebene Kleinkram in C nicht gehen?

Weil er sich unbedingt eine ISR einbildet, die dann auch noch möglichst 
schnell sein muss, weil er genau weiss, dass der C Compiler am Anfang 
einer ISR ein paar Register pusht, die er sich in Assembler sparen kann.

ISR braucht da überhaupt keiner. Die eine PWM abschalten (aber richtig), 
die andere anschalten und gut ists. Dazwischen noch ein kleines Päuschen 
einlegen, denn ein Motor wird da nicht so glücklich darüber sein, wenn 
man aus Vollgas/links in einem Zug auf Vollgas/rechts umschaltet.

Eine andere Möglichkeit wäre wohl die PWM zu invertieren. Aber dann wird 
es zu Hardware-Umbauten kommen. Da es aber bei einem Motor nicht 
zeitkritisch ist, ob da beim Umschalten eine PWM Periode komplett 
ausfällt, geht es auch so. Er muss nur dafür sorgen, dass er keine 
0-Spikes hat, während die andere PWM arbeitet. Denn sonst: 2 mal High 
(wenn auch nur für kurze Zeit) -> nicht gut für die H-Brücke.

Und wie meistens: Mit C hat das ganze wieder mal nur insofern zu tun, 
dass man die Syntax zum Setzen und Löschen von Bits kennen sollte. 
Abgesehen davon, würde man das in Assembler genau gleich machen.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Thomas E. schrieb:

> Warum soll der von dir beschriebene Kleinkram in C nicht gehen?

Das habe ich an keiner Stelle behauptet. Natürlich geht das auch in C. 
Ich kann es in C genauso umsetzen wie in Assembler.

Nur sind offensichtlich die reinen C-ler zu dumm dazu, es umzusetzen und 
darüber hinaus sogar dazu, auch nur die Möglichkeit zu erkennen, es 
umsetzen zu können. Genau das war der Punkt.

Deine frechen Lügen und Unterstellungen werden dir hier nicht helfen, 
der Thread spricht für sich selber. Im entscheidenden Posting findest du 
nichtmal eine Erwähnung irgendeiner Programmiersprache, sondern allein 
eine Darstellung der hardwaretechnisch gegebenen Sachverhalte.

Quasi eine Anleitung für alle Leute mit hinreichender Eigenintelligenz, 
das Problem auf einem AVR8 zu lösen. Ganz egal in welcher Sprache.

von c-hater (Gast)


Lesenswert?

Karl H. schrieb:

> Weil er sich unbedingt eine ISR einbildet, die dann auch noch möglichst
> schnell sein muss, weil er genau weiss, dass der C Compiler am Anfang
> einer ISR ein paar Register pusht, die er sich in Assembler sparen kann.

???

Mir scheint, du hast immer noch nicht mal annähernd das Konzept der 
Lösung verstanden. Der Trick dabei ist ja gerade: Sie läßt sich selbst 
in C völlig problemlos umsetzen. Es ist eben gerade kein sehr kritisches 
Software-Timing erforderlich, weil man die größten Timing-Probleme mit 
dieser Lösung an die Hardware delegiert, wo sie eigentlich hingehört.

Du bist also doch sehr viel dümmer, als ich eigentlich dachte...

von Karl H. (kbuchegg)


Lesenswert?

c-hater schrieb:

> Du bist also doch sehr viel dümmer, als ich eigentlich dachte...


Ja schon gut.
Wer unbedingt eine ISR propagiert, wo es ein 4 Zeiler auch tut ....

von c-hater (Gast)


Lesenswert?

Karl H. schrieb:

> Wer unbedingt eine ISR propagiert, wo es ein 4 Zeiler auch tut ....

Nochmal ein Tick dümmer. Nein, der "Vierzeiler" (vermutlich gemeint: die 
eigentliche Aktion in einen cli/sei-Rahmen verpacken) tut es eben nicht 
immer.

Die Hardware interessiert sich bei der Übernahme der OCR-Werte nämlich 
rein garnicht für eine bestehende Interruptsperre. "Sicher" ist der 
Schreibvorgang deshalb nur, wenn die Hardware möglichst wahrscheinlich 
gerade nicht die "OCR-Shadow-Register" liest, also zeitlich möglichst 
kurz nachdem sie das zuletzt getan hat. Und die beste (wenn natürlich 
auch immer noch nicht perfekte) Möglichkeit dazu ist nunmal eine ISR. 
Immerhin kann man dieser ISR ja zusätzlich beibiegen, notfalls auf den 
nächsten "sicheren" Punkt zu warten, wenn sie durch die indifferente 
variable Latenz des genauso idiotisch programmierten restliche C-Codes 
erst zu einem Zeitpunkt aktiv wird, wenn es nicht mehr sicher ist. Das 
ist absolut trivial und spätestens dann wirklich sicher (deshalb hier 
ohne Anführungszeichen).

Kann man eigentlich noch deutlicher zeigen als du, daß man eigentlich 
keine Ahnung von hardwarenaher Programmierung hat?

von c-hater (Gast)


Lesenswert?

Karl H. schrieb im Beitrag #4303166:

> Und die Leute bei Atmel sind alle Volltrottel.

Das habe ich wo behauptet? Und welches paper von Atmel gibt auch nur im 
entferntesten eine Rechtfertigung auch nur für die Andeutung, daß ich 
eine solche Meinung über die Leute von Atmel hätte?

Oder auch nur dafür, das das vorgestellte Konzept ineffizient wäre oder 
sogar nicht funktionieren würde? Es resultiert doch einfach nur aus den 
Fakten zur Hardware, die die AVR-Datenblätter selber liefern...

von Peter D. (peda)


Lesenswert?

Karl H. schrieb:
> Wird der Pin durch löschen der COM Bits wieder vom Timer abgekoppelt,
> ist noch lange nicht sicher gestellt, dass der Pin danach auch wieder
> auf low ist.

Der Pin geht dann sofort auf den Pegel des PORTx.y-Bits ohne 
Verzögerung.
Man kann also bequem die eine PWM abschalten, die Zeit zum Sperren der 
H-Brücke abwarten und dann die andere einschalten.
Man muß nichtmal die Werte in den OCR1x Registern ändern, sondern läßt 
die PWMs einfach intern weiter laufen.

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.