Hallo in die Runde.
Ich möchte ein sinusförmiges Ausgangssignal (Grundschwingung) an meinen
beiden PWM-Ausgangspins meines Atmega8A erzeugen.
Ich verwende den Phase-Correct Modus, 8-Bit Timerauflösung, sowie eine
256-stellige Lookup-Tabelle.
Mein Problem:
Ich möchte innerhalb 1s einen Hochlauf meiner Ausgangsfrequenz auf den
maximalen Wert erreichen.
Hierzu Teile ich meine max. Schrittweite (für die Indexauswahl der
Lookup-Tabelle) durch meine PWM Frequenz und erhöhe dann bei jedem
Timerüberlauf meine Schrittweite bis zum max. Wert.
Leider erreiche ich die max. Schrittweite nicht, d.h. meine
Ausgangsfrequenz ist deutlich kleiner als gewünscht. Vielleicht erreiche
ich auch die max. Schrittweite und das Problem liegt an einer anderen
Stelle.
Leider weiß ich nicht wo der Fehler im Code liegt. (Ich vermute mal,
dass die Umwandlung von 16-Bit in 32-Bit Variablen und umgekehrt die
Ursache ist).
Bei fester Schrittweite funktioniert das Ganze einwandfrei.
Variablen i und j bleiben ungenutzt. Ich habe sie im nachhinein
entfernt.
Ich habe das ganze mit dem Atmel Studio 6 erzeugt.
Mit dem Software Debugger kann ich allerdings nicht feststellen was in
meiner ISR passiert.
Debug-Maßnahmen habe ich nicht eingeplant.(So tief bin ich nicht in der
Programmiermaterie drin)
Wenn ich das jetzt richtig gesehen habe:
Der Timer 1 zählt ohne Prescaler von 0 bis 255, dann wieder runter ->
Dann kommt der Overflow-Interrupt.
(2 * 255) / 3686000 => alle 138 Mikrosekunden.
Um die ISR abzuarbeiten werden schon mal mindesten 186 Mikrosekunden
gebraucht. Da beißt sich was.
Peter A. schrieb:> Leider weiß ich nicht wo der Fehler im Code liegt. (Ich vermute mal,> dass die Umwandlung von 16-Bit in 32-Bit Variablen und umgekehrt die> Ursache ist).
Das denke ich ehrlich gesagt nicht.
Ich denke, du hast dich da irgendwo bei der Mathe verhaut. Einen
Overflow bei einem Zwischenergebnis nicht bedacht, oder das bei einer
Integerdivision keine Kommastellen anfallen, oder sowas in der Richtung.
Unglücklicherweise ist der Code etwas ... unübersichtlich und ich hab
jetzt ehrlich gesagt auch nicht die Nerven und die Lust um den Code erst
mal soweit aufzudröseln um die hier programmierte Idee erkennen zu
können, bzw. ob und wenn ja wo bei der Umsetzung der Idee Fehler gemacht
wurden, bzw. ob und wo da jetzt arithmetische Probleme auftauchen.
Die PWM ist ja nur Nebenschauplatz. Das was dir Sorgen macht, ist doch
die Veränderung des OCR Wertes. Das kannst du aber mit einem
Testprogramm auf dem PC genausogut erledigen. Denn letzten Endes geht es
ja nur darum die Veränderung einiger Kennzahlen nachzuvollziehen.
Martin Kreiner schrieb:> Um die ISR abzuarbeiten werden schon mal mindesten 186 Mikrosekunden> gebraucht. Da beißt sich was.
Wie kommst du jetzt konkret auf die 186 Mikrosekunden?
In der ISR werden lediglich meine Comparewerte inkrementiert.
Mein Timer braucht 138us je Durchlauf meiner Werte. Die ISR selbst kann
nicht solange brauchen.
Peter A. schrieb:> In der ISR werden lediglich meine Comparewerte inkrementiert.> Mein Timer braucht 138us je Durchlauf meiner Werte. Die ISR selbst kann> nicht solange brauchen.
Nun ja, wenn du meinst.....
1
if((stepsizecnt/10000)<(stepsizemax))
Alleine diese in deinen Augen vielleicht lächerliche Abfrage verheizt
schon mal 163 Mikrosekunden.
> Wie kommst du jetzt konkret auf die 186 Mikrosekunden?
Für soetwas ist der eingebaute Simulator perfekt.
Karl Heinz Buchegger schrieb:> Der Teil hier> erscheint mir zb reichlich suspekt.> Was immer auch hier ausgerechnet wird, das lässt sich doch sicherlich> auch einfacher berechnen.
Hier wird meine maximale Schrittweite ausgerechnet. Also konkret der
Index meiner samples-Werte.
Bsp.: f_pwm = 7200, samples=256-Werte, fout=50:
Schrittweite-Indizes=256/comparechange=3,55555555...
Als Schrittweite definiere ich dann 0x0355.
Aber das Ganze wird nur einmal beim start abgearbeitet und sollte nicht
das Problem darstellen.
> Alleine diese in deinen Augen vielleicht lächerliche Abfrage verheizt> schon mal 163 Mikrosekunden.
Ok also ist die 32Bit-Berechnung wohl das Problem. Sind wohl zuviele
Speicherzugriffe.
Hmm gibt´s da eine sinnvolle alternative? Bitschieberoperanden
verwenden?
Peter A. schrieb:> Bsp.: f_pwm = 7200, samples=256-Werte, fout=50:> Schrittweite-Indizes=256/comparechange=3,55555555...> Als Schrittweite definiere ich dann 0x0355.>> Aber das Ganze wird nur einmal beim start abgearbeitet und sollte nicht> das Problem darstellen.
Wenn das Rechenergebnis nicht stimmt, dann ist das schon ein Problem.
> Schrittweite-Indizes=256/comparechange=3,55555555...> Als Schrittweite definiere ich dann 0x0355.
0x? (Halte ich jetzt mal wegen stepsizecnt/10000)<(stepsizemax für
einen Tippfehler:-) )
Warum schreibst du dann die Berechnung nicht einfach genau so hin,
sondern pfriemelst da mit Einzelbytes rum?
Im übrigen: 32 Bit Rechnerei in der ISR ist auch nicht so ohne.
Da könntest du dir den ganzen Aufwand auch sparen und die
Prozentrechnerei (denn nichts anderes ist diese Frequenzzunamhe ja) auch
in 16 Bit direkt in der ISR ausrechnen. Grob geschätzt würde sich das
nicht um viel reissen.
Um nochmal zum Anfang zu gehen:
> Leider erreiche ich die max. Schrittweite nicht, d.h. meine> Ausgangsfrequenz ist deutlich kleiner als gewünscht.
Was meinst du damit?
Wann wäre sie denn erreicht? Wenn diese Codezeile hier ausgeführt wird:
1
else
2
{
3
stepsizecntx=stepsizemax;
4
}
Diese Zeile wird zumindest im Simulator nach 2,723 Sekunden ausgeführt.
Allgemeiner Tipp:
Am Anfang der ISR einen Pin auf High setzen und danach auf Low. Damit
kann man Oszi schön sehen, wann die ISR real aufgerufen wird und wie
lange sie braucht. Man muss etwas Reserve für die PUSHs am Anfang und
POPs am Ende rechnen.
Danke für die vielen Antworten.
Ich komm heut leider nicht mehr dazu das Programm abzuändern.
Aber ich bin mir ziemlich sicher, dass ich irgendwo, wie Herr Buchegger
bereits erwähnt hat, einen Rechenfehler im Code habe.
Von den 32-Bit Multiplikationen muss ich auch weg. Das kostet zuviel
Zeit.
Das mit 0x war kein Tippfehler, ich habe mich da von jemand anderem
Einlullen lassen die Nachkommastellen meiner Indexschrittweite in das
untere Byte meiner Variable zu schreiben. Das soll den Rundungsfehler
verkleinern. Von der korrekten Schrittweite ist das aber bei kleinen
Frequenzen meilenweit entfernt.
Martin Kreiner schrieb:> Was meinst du damit?> Wann wäre sie denn erreicht? Wenn diese Codezeile hier ausgeführt> wird:else> {> stepsizecntx=stepsizemax;> }>> Diese Zeile wird zumindest im Simulator nach 2,723 Sekunden ausgeführt.
Ja korrekt.
Ich scheine die Probleme in den Griff bekommen zu haben.
Der Code ist jetzt deutlich einfacher. Statt multiplikation/division
verwende ich jetzt Schieberegister. Ich werde das Ganze jetzt mal am
Oszi begutachten, ob ich denn wirklich alles gelöst habe.
Anbei die Bilder bei einem Hochlauf auf 100Hz.