Hallo,
ich habe ein kleines Problem mit Timern und PWM an einem ATmega16.
Es handelt sich um einen kleinen DC Motor angesteuert per IRLZ34N Mosfet
an PB3.
Ich möchte nun lediglich alle 2 Sekunden (muss nicht genau sein!) die
PWM Geschwindigkeit erhöhen, Timer Überlauf und co habe ich erstmal
rausgenommen (der Timer1 sollte 67 Sekunden laufen bei 1MHz und
clk/1024?).
Im Anhang befindet sich eine Minimalversion vom Quelltext (die habe ich
auch kompiliert und zum Testen verwendet).
was ich erwarte : Alle 2 Sekunden die nächste Geschwindigkeit und dann
wieder von vorne. Wenigstens 67 Sekunden lang.
was der Motor tut : Alles nur nicht das, er wechselt zwar die
Geschwindigkeiten aber weder in der Reihenfolge wie im Array, noch alle
2 Sekunden.
Ich denke also ich hab da irgendwie einen großen Denkfehler, den ich
ständig übersehe. Bin noch sehr unerfahren in der Arbeit mit
Mikrocontrollern.
Vielen Dank für eure Hilfe!
fanick
@ Fabian B. (fanick)
>Ich möchte nun lediglich alle 2 Sekunden (muss nicht genau sein!) die>PWM Geschwindigkeit erhöhen, Timer Überlauf und co habe ich erstmal>rausgenommen
Warum? Gerade DAS ist eine perfekte Zeitbasis und genau der richtige Ort
für deinen Zähler!
>was ich erwarte : Alle 2 Sekunden die nächste Geschwindigkeit und dann>wieder von vorne. Wenigstens 67 Sekunden lang.>ständig übersehe. Bin noch sehr unerfahren in der Arbeit mit>Mikrocontrollern.
Pack die ISR für den Timerüberlauf wieder rein und dort deinen Zähler.
vielen Dank!
Ich denke die Interrupts sind noch nicht vollständig initialisiert?
Im Anhang ist mein aktueller Stand, ich habe nur noch eine globale cnt
Variable als volatile definiert und in dem Interrupt zähle ich nur noch
diesen hoch.
Den Prescaler habe ich auf 64 gestellt und einen Preload von 34286
eingestellt, damit sollte ich 2 Sekunden pro Overflow haben.
Es funktioniert nun nach einigem Testen auch recht rund :-)
Ist das so der "konforme" Weg?
herzlichen Dank noch einmal für die schnelle Hilfe
fanick
Es funktioniert leider immer noch nicht so richtig.
Entweder ist was falsch mit der Frequenz oder aber mit dem Array zur PWM
Ausgabe.
Zumindest bleibt der Motor grad immer mit der letzten Version auf der
gleichen Geschwindigkeit.
Edit: Die Geschwindigkeit kann es nicht sein. Mit runtergesetzter
Geschwindigkeit dauert es lange bis der Motor anfängt (also bis zum
ersten Mal in die if Bedingung gegangen wird.
Es scheint dann wohl irgendwo ein kleiner Fehler mit dem Array zu sein,
in der Simulation funktioniert es allerdings..
Fabian B. schrieb:> Es funktioniert leider immer noch nicht so richtig.
Mit dem Programm, das du zuletzt gepostest hat?
Du änderst die Motor_PWM alle 0.5 Sekunden.
So ein Motor ist doch kein Federgewicht. Du musst der trägen Masse schon
etwas Zeit lassen um auf deine veränderte PWM zu reagieren.
PS: verstreu die wesentlichen Konstanten nicht quer übers ganze
Programm. Gerade in der Entwicklungsphase ist es IMHO keine so gute
Idee, die Bit-Werte aus main rauszunehmen. Man muss dann ständig hin und
her scrollen um zu sehen, was du eigentlich wo eingestellt hast.
Danke erstmal, ich gucke dass ich das nochmal etwas übersichtlicher
aufbaue.
Zu der PWM Geschwindigkeit:
Ich habe eine Periodendauer von 2s mir ausgerechnet:
Wenn ich dann also
1
2
if (cnt > lasttime) {
3
lasttime = cnt;
4
if(cnt==1)
5
MOTOR = 40;
6
else if(cnt>2)
7
MOTOR = 0;
8
}
für die Geschwindigkeit auswählen würde, würde ich erwarten, dass der
Motor kurz angeht für 2s und dann wieder ausgeht. Es ist aber so, dass
der Motor nur einmal mit Geschwindigkeit 40 angeht und dann auch an
bliebt.
"cnt" wird also im Interrupt nicht erhöht.
Ich habe das ganze jetzt in die Interrupt Routine gesetzt und es
funktioniert!
Nur sehe ich noch nicht den Fehler, warum das in der main nicht
funktioniert, schließlich will ich ja bei erweitertem Programm nicht
alles im ISR machen.
Danke nochmals an euch für die sehr schnelle Hilfe!
Fabian B. schrieb:> Danke erstmal, ich gucke dass ich das nochmal etwas übersichtlicher> aufbaue.>> Zu der PWM Geschwindigkeit:>> Ich habe eine Periodendauer von 2s mir ausgerechnet:
Es sind sogar 4 Sekunden. Ich hab mich von deiner Timer Vorladerei ins
Boxhorn jagen lassen.
Fabian B. schrieb:
Sorry. Hab mich verrechnet.
> Ich habe das ganze jetzt in die Interrupt Routine gesetzt und es> funktioniert!>> Nur sehe ich noch nicht den Fehler, warum das in der main nicht> funktioniert, schließlich will ich ja bei erweitertem Programm nicht> alles im ISR machen.
Ich seh dein jetziges Programm nicht.
Aber
cnt muss volatile sein. Und es sollte ein uint8_t sein. Mit einem
uint16_t hast du das Problem des atomaren Zugriffs.
dann ist es das ein Problem mit uint16_t. Schade, ich hatte gehofft ich
muss nicht noch eine überlaufende cnt variable in betracht ziehen.
Ich schreibe das gleich nochmal neu zusammen, teste und lade dann
nochmal zur Vollständigkeit hoch.
Fabian B. schrieb:> dann ist es das ein Problem mit uint16_t. Schade, ich hatte gehofft ich> muss nicht noch eine überlaufende cnt variable in betracht ziehen.
Das hat mit Überlauf nichts zu tun. Die Sache ist wesentlich
unangenehmer. Vergleichbar mit der Situation in der du steckst, wenn du
eine Geschichte in einem Buch liest und während du aufs Klo gehst,
tauscht jemand das Buch aus. Dann passt die Fortsetzung der Geschichte
nicht zu dem, was du vor dem Klogang gelesen hast.
Und es muss nicht das Problem sein. Es könnte es sein.
>> Ich schreibe das gleich nochmal neu zusammen, teste und lade dann> nochmal zur Vollständigkeit hoch.
Das ist IMMER gut.
Wenn du das Programm veränderst, dann sehen wir das nicht. Unser
WIssenstand ist immer die letzte Programmversion, die du postest.
So ich hab nochmal eine kompakte, leider nicht funktionierende Datei in
den Anhang gepackt.
Ich hab nun hoffentlich das mit den Konstanten usw. vernünftig
berücksichtigt und den Quelltext so kurz wie möglich gehalten.
Ich hab mal scherzweise probiert mit
1
ISR(TIMER1_OVF_vect){
2
cnt++;
3
MOTOR=speed_normal[cnt];
4
}
und habe erwartet, dass der Motor die Stufen schneller wird, bis dann
eben das Array nicht mehr definiert ist.
Stattdessen wird der Motor mal schneller mal langsamer, aber meine
Schritte erkenne ich da nicht.
Nochmals danke für die ganze Hilfe, ich habe nicht erwartet, dass ich so
große Probleme mit einem eigentlich relativ einfachem Problem :(
>Ich hab mal scherzweise probiert mit>>ISR(TIMER1_OVF_vect) {> cnt++;> MOTOR = speed_normal[cnt];>}
Das ist echt ein Scherz. Wie viele Elemente
hat speed_normal[]? Und wie schnell zählt cnt?
Wann passt der Index nicht mehr für das Array?
Wann greifst du dann über cnt ins Klo?
holger schrieb:> Das ist echt ein Scherz.
So scherzweise doch wohl auch hoffentlich wieder nicht ;-)
Gemäß http://www.mikrocontroller.net/articles/AVR-Tutorial:_Timer habe
ich an 4,2 Sekunden pro Timer Overflow gedacht und dementsprechend auch
rund 20 Sekunden ein vernünftiges Verhalten erwartet.
@ Fabian B. (fanick)
>So ich hab nochmal eine kompakte, leider nicht funktionierende Datei in>den Anhang gepackt.
Du brauchst nur einen Timer, der kann PWM und Zeitbasis gleichzeitg
erzeugen. Siehe Anhang.
Das Programm macht bei mir 2,5 sek lang nichts, geht dann auf langsame
Geschwindigkeit (Geschwindigkeit 40) und dann dauerhaft auf einer
"mittleren" Geschwindigkeit, entsprechend etwa 80, dem Mittelwert der
Geschwindigkeitsstufen.
Im Simulator funktioniert es allerdings wiedermal.
Mit den 2 Timern wollte ich mir die einfache Möglichkeit zur Erweiterung
bzw Timing im Sekunden/Minuten Bereich für andere Anwendung abseits von
dem PWM lassen.
Fabian B. schrieb:> Das Programm macht bei mir 2,5 sek lang nichts, geht dann auf langsame> Geschwindigkeit (Geschwindigkeit 40) und dann dauerhaft auf einer> "mittleren" Geschwindigkeit, entsprechend etwa 80, dem Mittelwert der> Geschwindigkeitsstufen.> Im Simulator funktioniert es allerdings wiedermal.
Der Simulator hat aber auch keinen realen Motor, der eine
Mindestspannung braucht um erst mal die Haftreibung zu überwinden und
der träge Masse hat um den Rotor zu beschleunigen bzw. abzubremsen.
In deinem Simulator hat der simulierte Motor auch nicht die
Eigenschaften Bürstenfeuer zu erzeugen, welche den µC zum Absturz
bringen können. Dein simulierter Motor bzw. der simulierte µC hat auch
keine Probleme mit der SPannungsversorgung bzw. fehlenden
Blockkondensatoren bzw. fehlenden Entstörkondensatoren am Motor. Er hat
weder die Eigenschaft, dass sein simulierte Versorgungsspannung
einbricht, noch dass der Motor Störspikes einkoppelt.
Es scheint die einzige Möglichkeit zu sein. Die Programme laufen ja
vernünftig.
Ich baue in den nächsten Tagen die Schaltung auf meinem Breadboard neu
auf und teste weiter, vermutlich ist ja doch irgendwas verschaltet.
Danke auf jeden Fall an alle die geholfen haben!