Forum: Mikrocontroller und Digitale Elektronik Atmega32u4 PWM Motor Kontrolle


von hoalu (Gast)


Lesenswert?

Ich bin ein Beginner wenn es um Microcontroller geht und versuche gerade 
mithilfe von PWM die Geschwindigkeit eines Motors zu regeln.
Ich benutze den Atmega32U4 und den 16-bit Timer1.

Mein Vorgehen ist, den Fast PWM Mode zu benutzen (Mode 14) wobei ich den 
ICRn als Top und den OCRnx als Output Generator für OCnA.

Als Beispiel habe ich es an den OC1A / PB5 probiert.


1
void initMotors()
2
{   
3
   DDRB |= (1<<DDB5) | (1<<DDB6);  //Output
4
  TCCR1A |= (1<<WGM11) | (1<<COM1A1);  //Fast PWM Mode, Non-Inverted
5
  TCCR1B |= (1<<WGM12) | (1<<WGM13) | (1<<CS10);  //No Prescaler
6
  ICR1 = 799;  //ICR1 als TOP, Frequenz bei 20.000HZ
7
  OCR1A = 200;  //Duty Cycle bei 200/800 = 25%
8
}

Was passieren sollte: Der Motor läuft mit 25% Geschwindigkeit.

Wenn ich dies nun ausführe, läuft der Motor bei voller Geschwindigkeit. 
Es kommt nie zu Compare Matches mit dem OCR1A und somit ist es einfach 
die ganze Zeit auf HIGH.
Wenn ich inverted-mode gehe, dann läuft der Motor gar nicht, da es die 
ganze Zeit auf LOW ist.

Also liegt es anscheinend irgendwie daran, dass es nie zu Compare 
Matches kommt nehme ich an?
Hat jemand eine Idee woran es liegen könnte?

MfG

von S. Landolt (Gast)


Lesenswert?

Mangels eines ATmega32u4 kann ich nichts ausprobieren, rein theoretisch 
sieht es für mich gut aus; bis auf dieses Ver-odern in der 
Initialisierung, das ist eine dumme Angewohnheit, sollte aber allenfalls 
bei einem schlechten Bootloader eine Rolle spielen.

von derjaeger (Gast)


Lesenswert?

sei() vergessen?

Flag gesetzt? TIMSK1  OCIE1A

von Mick (Gast)


Lesenswert?


von S. Landolt (Gast)


Lesenswert?

> sei() vergessen?
> Flag gesetzt? TIMSK1  OCIE1A

Doch nicht nötig bei PWM.
Aber das komplette Programm wäre wirklich von Interesse, das stimmt.

von c-hater (Gast)


Lesenswert?

S. Landolt schrieb:

> Mangels eines ATmega32u4 kann ich nichts ausprobieren, rein theoretisch
> sieht es für mich gut aus; bis auf dieses Ver-odern in der
> Initialisierung, das ist eine dumme Angewohnheit

Das ist mehr als eine dumme Angewohnheit. Wenn eine bestimmte 
Konfiguration erreicht werden muss, muss man sie auch explizit 
herstellen. Das kann man nicht durch verodern mit einem (zumindest 
potentiell unbekannten) Ausgangszustand.

Es gibt natürlich Register, wo diese Veroderei (unter bestimmten 
Randbedingungen, z.B. halt den definierten Resetzustand) einen Sinn 
ergibt, z.B. die DDRn oder PORTn, aber für die allermeisten Register zur 
Kontrolle der Peripherie ergibt das auch dann schlicht absolut keinen 
Sinn. Also besser einfach nicht machen.

Was nun das Problem des TO betrifft: Bei solchen Sachen sollte man immer 
auch sämtliche sonstigen "alternate port functions" im Blick haben. 
Sprich: dringende Frage an den TO: benutzt du eventuell auch Timer4, 
möglicherweise sogar mit einer ähnlich schwachsinnigen Konfiguration per 
Veroderung?

von hoalu (Gast)


Lesenswert?

Das mit dem Ver-odern war mir nicht bewusst. Ich habe es einfach 
aufgeschnappt von anderen Tutorials.

Timer4 benutze ich nicht.

Hier ein paar mehr Infos:
Ich benutze noch eine H-Bridge, der Aufbau sieht dem hier sehr ähnlich:
https://youtu.be/dyjo_ggEtVU?t=690
Die Ports PB5 und PB6 nutze ich als Outputs, und die gehen nach IN von 
der Bridge (wie in dem Bild im Video halt). Am PB5 ist auch OC1A.
Also lege ich das PWM Signal nicht an den ENAble, sondern an den Input, 
aber das sollte ja theoretisch das gleiche machen.
1
#include <avr/io.h>
2
#include "Motor.h"
3
4
void initMotors()
5
{   
6
  DDRB |= (1<<DDB5); //output
7
  DDRB |= (1<<DDB6); //output
8
  TCCR1A |= (1<<WGM11); 
9
  TCCR1A |= (1<<COM1A1); //non-inverted
10
  TCCR1B |= (1<<WGM12); 
11
  TCCR1B |= (1<<WGM13); //Fast PWM Mode
12
  TCCR1B |= (1<<CS10); //no prescaler
13
  ICR1 = 799; //frequency: 20KHZ
14
  OCR1A = 200; // 200/800 = 25% duty cycle
15
}
16
17
  int main()
18
  {
19
    initMotors();
20
    while(1){}
21
  }

Was ich will: Motor soll mit 25% Geschwindigkeit laufen
Was wirklich passiert: Motor läuft mit max Geschwindigkeit

von Wirrsing (Gast)


Lesenswert?

Redet c-hater hier wirr?

von Hendrik (Gast)


Lesenswert?

Für Motoren empfiehlt Atmel den Einsatz des Phase Correct PWM Mode. Auch 
ist fraglich ob dein Motor überhaupt mit 20kHz ansteuerbar ist. Zur 
Beschaltung gibt es ja keine Angaben. Aber sei es drum. Du beschreibst 
da Problem ja als ausbleiben des "Endanschlages"

Für mich sieht der Code erstmal korrekt aus. Bis auf diese Stelle im 
Datenblatt, die du wohl übersehen hast:

The Timer/Counter (TCNTn), Output
Compare Registers (OCRnA/B/C), and Input Capture Register (ICRn) are
all 16-bit registers. Special procedures must be followed when accessing 
the 16-bit registers.

Da der Atmega ein 8-Bit breiten Bus hat, müssen die 16 Bit Register von 
Timer1 entsprechend in zwei Schritten beschrieben werden. Zuerst High 
Byte, dann Low Byte.

Vielleicht liegt da der Hund begraben?

von c-hater (Gast)


Lesenswert?

Hendrik schrieb:

> The Timer/Counter (TCNTn), Output
> Compare Registers (OCRnA/B/C), and Input Capture Register (ICRn) are
> all 16-bit registers. Special procedures must be followed when accessing
> the 16-bit registers.
>
> Da der Atmega ein 8-Bit breiten Bus hat, müssen die 16 Bit Register von
> Timer1 entsprechend in zwei Schritten beschrieben werden. Zuerst High
> Byte, dann Low Byte.
>
> Vielleicht liegt da der Hund begraben?

Nein, da kümmert sich der Compiler drum. Der kennt die nötige 
Zugriffsreihenfolge. Wenn man ganz sicher gehen will, darf man aber auch 
gerne mal in's Listfile schauen.

von S. Landolt (Gast)


Lesenswert?

> Das mit dem Ver-odern war mir nicht bewusst.

Der Hinweis wurde leider falsch verstanden, gemeint war:
1
}
2
  DDRB = (1<<DDB5) | (1<<DDB6);  //Output
3
  TCCR1A = (1<<WGM11) | (1<<COM1A1);  //Fast PWM Mode, Non-Inverted
4
  TCCR1B = (1<<WGM12) | (1<<WGM13) | (1<<CS10);  //No Prescaler
Wenn nämlich die SFRs mit anderen als den Defaultwerten vorbesetzt sind, 
z.B. durch einen schlechten Bootloader, dann führt '|=' ins Chaos.

Ansonsten kann ich nach wie vor keinen Fehler erkennen; wenn vorhanden, 
sollte mal die Spannung an den Outputs mit einem Voltmeter nachgemessen 
werden.

von MaWin (Gast)


Lesenswert?

hoalu schrieb:
> Also lege ich das PWM Signal nicht an den ENAble, sondern an den Input,
> aber das sollte ja theoretisch das gleiche machen

Nein, das macht nicht das gleiche, aktiv bremsen vs. frewheeling, aber 
in beiden Fällen sollte ein Motor langsamer werden.

Aber was soll der Unsinn mit 20kHz, welchen Motor besitzt du, 
Mückenflugmuskeln ?

Meinst du nicht, dass dein Motor wie jeder Motor zu träge sein sollte um 
selbst bei 50Hz eine mittlere Geschwindigkeit einzunehmen ?

von Georg M. (g_m)


Lesenswert?

hoalu schrieb:
> Ich benutze den Atmega32U4 und den 16-bit Timer1.
>
> Mein Vorgehen ist, den Fast PWM Mode zu benutzen (Mode 14)
>
1
 ICR1 = 799;  //ICR1 als TOP, Frequenz bei 20.000HZ
>
Muss es unbedingt 800 sein? Denn es sind Fast PWM 9-bit und Fast PWM 
10-bit verfügbar.

von Oliver S. (oliverso)


Lesenswert?

c-hater schrieb:
> Das kann man nicht durch verodern mit einem (zumindest
> potentiell unbekannten) Ausgangszustand.

Prinzipiell richtig, allerdings ist der Ausgangszustand der Register 
nach einem Reset weder potentiell noch überhaupt unbekannt, sondern wohl 
definiert.

Wenn da also vorher niemand an den Registern rungefummelt hat, passt das 
schon.

Oliver

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.