Hallo Leute, ich habe eine SPWM auf einem Atmega8 realisiert. Diese Funktioniert auch soweit ganz gut (siehe Bild SPWM.jpg). Frequenz der Grundwelle soll 50Hz betragen. Schaltfrequenz beträgt (der Übersichtlichkeit halber) 2kHz. Der Atmega8 läuft mit dem internen RC Oszillator bei 2MHz. Ich habe in diesem Thread Beitrag "Sinustabelle, header und Werte verwenden" bereits anfängliche Fragen bezüglich Sinustabelle etc. gestellt. Nun ist der Code fertig und ich möchte euch gerne um euer Feedback bitten, was am Code optimiert werden könnte. Das hat zweierlei Hintergründe: (1) Ich möchte meine Programmierkenntnisse festigen, verfeinern und ausbauen (2) Verbraucht der Code knapp 50% meines Speichers - was sicherlich weit weg vom Optimum ist :D Ich bin mir ziemlich sicher, dass die Sinustabelle einen nicht unerheblichen Faktor dazu beiträgt, da ich 256 uint16 Werte habe. Meine Frage an die erfahrenen Leute wäre jetzt, aus wie vielen Werten der Sinus bestehen sollte bzw. ob es einen Pi mal Daumen Richtwert gibt, bis wohin der Sinus noch als sauber anzusehen ist. Ich danke euch für eure Meinung. Viele Grüße, Michael
Michael schrieb: > ob es einen Pi mal Daumen Richtwert gibt, bis wohin der Sinus noch > als sauber anzusehen ist Das kommt auf den angelegten Maßstab drauf an. Manche Geräte sehen auch ein Trapez als hinreichend gute Näherung für einen Sinus ;-)
Moin Michael, du kannst dir 3/4 deiner Sinustabelle sparen. Genaugenommen die letzten 3/4.Du kannst aus dem ersten Viertel nen kompletten Sinus generieren, indem du die Tabelle auch rückwärts ausliest, und in der 2ten Hälfte musst du von den Werten jeweils errechnen, wie weit der Wert vom Mittelwert weg ist, und dann diese Abweichung nach unten vom Mittelwert´abziehen. Also probiert hab ich das auch noch nicht, ich hatte auch mal n Sinus per Tabelle erzeugt, und den kompletten Sinus verwendet, da kam auch dieser Tip. Wobei mir auch nicht ganz klar war, wie genau das zu handeln wäre. Mathematisch bin ich mir inzwischen klar darüber, aber ich hatte es noch nicht in Software umgesetzt, ich hatte die Befürchtung,das der Sinus bei hohen Frequenzen ganz schön verformt wird, wenn man zwischendrin Berechnungen ausführen muss, um den nächsten Wert zu erhalten. Aber da hilft Googel sicher weiter =) MfG Chaos
@ Michael (Gast) >ich habe eine SPWM auf einem Atmega8 realisiert. Was soll SPWM schon wieder sein? Sinus PWM? > Diese Funktioniert auch >soweit ganz gut (siehe Bild SPWM.jpg). Frequenz der Grundwelle soll 50Hz >betragen. Schaltfrequenz beträgt (der Übersichtlichkeit halber) 2kHz. >Der Atmega8 läuft mit dem internen RC Oszillator bei 2MHz. Warum so langsam? >Nun ist der Code fertig und ich möchte euch gerne um euer Feedback >bitten, was am Code optimiert werden könnte. http://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Prinzipien_der_Optimierung >(1) Ich möchte meine Programmierkenntnisse festigen, verfeinern und >ausbauen Gut. Deine Sinustabelle gehört NICHT in eine Headerdatei sondern eine C-Datei. Auf dem AVR packt man die in den PROGMEN, sonst verschwendet man nur sinnlos RAM. http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29 Deine Funktion void CarrierCalculation(void) hat einen irreführenden Namen, das ist eine Initialisierung, sonst nix. Strukturierte Programmierung auf Mikrocontrollern sei() packt man besser ins main, nicht in spezielle Initfunktionen. Für die Generierung der PWM und des Hochzählen des Tabellenindex kann und sollte man besser einen Timer nutzen, spart Resourcen und ist voll synchron. > i=i+1; > if(i==255) > { > i=0; > } Kann man sich sparen, eine 8 Bit Variable läuft bei 255 allein über, i++; reicht. i muss nicht global und auch nicht volatil sein, eine statische, lokale Variable in der ISR reicht. >Ich bin mir ziemlich sicher, dass die Sinustabelle einen nicht >unerheblichen Faktor dazu beiträgt, da ich 256 uint16 Werte habe. Das sind 512 Byte Flash. Die interessieren heute keinen mehr. >Frage an die erfahrenen Leute wäre jetzt, aus wie vielen Werten der >Sinus bestehen sollte bzw. ob es einen Pi mal Daumen Richtwert gibt, 256 Punkt ist schon OK. > bis >wohin der Sinus noch als sauber anzusehen ist. Das hängt vor allem von deinem Filter nach der PWM ab. http://www.mikrocontroller.net/articles/Pulsweitenmodulation#DA-Wandlung_mit_PWM
Vielen Dank schon mal an alle für eure Antworten. Falk Brunner schrieb: > Was soll SPWM schon wieder sein? Sinus PWM? Genau. Sorry, habe es unter diesem Namen gelernt. > Warum so langsam? Meinst du damit die 2MHz Taktfrequenz vom Atmega? Gute Frage, war mehr oder minder willkürlich festgelegt, um irgendwo zu starten. > Deine Sinustabelle gehört NICHT in eine Headerdatei sondern eine > C-Datei. Auf dem AVR packt man die in den PROGMEN, sonst verschwendet > man nur sinnlos RAM. Okay, ist gemerkt. Werde ich ändern. > Deine Funktion void CarrierCalculation(void) hat einen irreführenden > Namen, das ist eine Initialisierung, sonst nix. Hast recht. Wirklich berechnen tue ich da nichts. Wobei, mit der Initialisierung wird der Timer berechnet. > sei() packt man besser ins main, nicht in spezielle Initfunktionen. Ist geändert. > Für die Generierung der PWM und des Hochzählen des Tabellenindex kann > und sollte man besser einen Timer nutzen, spart Resourcen und ist voll > synchron. Ich bin mir nicht sicher, ob ich dich genau verstehe. Der Timer läuft doch jeden Takt linear nach oben (erhöht sich jeden Takt um 1). Wenn ich jetzt den aktuellen Wert des Timers verwende zum Auslesen der Sinustabelle, muss ich doch den richtigen Prescaler finden, der z.B. zu genau 78.5us das TCNTn Register um 1 nach oben setzt. Wolltest du das damit ausdrücken oder meinst du etwas anderes? > Kann man sich sparen, eine 8 Bit Variable läuft bei 255 allein über, > i++; reicht. Okay, danke. > i muss nicht global und auch nicht volatil sein, eine statische, lokale > Variable in der ISR reicht. Danke. > Das sind 512 Byte Flash. Die interessieren heute keinen mehr. Okay, vielleicht ist der Atmega8 ein wenig oldschool dafür :D Vielen Dank!
@ Michael (Gast) >Meinst du damit die 2MHz Taktfrequenz vom Atmega? Gute Frage, war mehr >oder minder willkürlich festgelegt, um irgendwo zu starten. PWM mach man meisten möglichst hochfrequent, um dann einfacher filtern zu können. >> Für die Generierung der PWM und des Hochzählen des Tabellenindex kann >> und sollte man besser einen Timer nutzen, spart Resourcen und ist voll >> synchron. >Ich bin mir nicht sicher, ob ich dich genau verstehe. Der Timer läuft >doch jeden Takt linear nach oben (erhöht sich jeden Takt um 1). Ja. > Wenn ich >jetzt den aktuellen Wert des Timers verwende zum Auslesen der >Sinustabelle, Nein, in der selben ISR muss dein Programmteil stehen. > muss ich doch den richtigen Prescaler finden, der z.B. zu > genau 78.5us das TCNTn Register um 1 nach oben setzt. >Wolltest du das damit ausdrücken oder meinst du etwas anderes? So halbwegs. Du hast jetzt 2 Timer. Timer 1 macht die phasenkorrekte PWM mit 2 kHz, sprich 500us Pro PWM Durchlauf. Timer2 läuft mit 78us Periodenauer und zählt deinen Index der Sinustabelle hoch. Das ist aber eher Unsinn, weil deine PWM nur alle 500us einen Updat der PWM-Ausgabe machen kann. Hier verschenkst du Zwischenwerte, weil dein Index ca. 6,5 mal schneller läuft als die PWM. Klar, wenn man jetzt eine niedrigere Frequenz generiert, kann man mehr Zwischenwerte ausgeben.
Falk Brunner schrieb: > PWM mach man meisten möglichst hochfrequent, um dann einfacher filtern > zu können. Ergibt Sinn. Die 2kHz habe ich zu Demonstrationszwecken verwendet, weil das Oszibild dann noch "schön" lesbar ist. Angepeilt sind 20kHz am Ende zur Ansteuerung einer H-Brücke. >>Ich bin mir nicht sicher, ob ich dich genau verstehe. Der Timer läuft >>doch jeden Takt linear nach oben (erhöht sich jeden Takt um 1). > > Ja. Okay, immerhin hier sind wir schon auf dem gleichen Nenner ;) >> Wenn ich >>jetzt den aktuellen Wert des Timers verwende zum Auslesen der >>Sinustabelle, > > Nein, in der selben ISR muss dein Programmteil stehen. Hmm, welchen Programmteil meinst du genau? Ich kann dir nicht wirklich folgen, für mich ist das Thema noch Neuland. >> muss ich doch den richtigen Prescaler finden, der z.B. zu >> genau 78.5us das TCNTn Register um 1 nach oben setzt. > >>Wolltest du das damit ausdrücken oder meinst du etwas anderes? > > So halbwegs. > > Du hast jetzt 2 Timer. Richtig. > Timer 1 macht die phasenkorrekte PWM mit 2 kHz, sprich 500us Pro PWM > Durchlauf. Genau > Timer2 läuft mit 78us Periodenauer und zählt deinen Index der > Sinustabelle hoch. Genau. > Das ist aber eher Unsinn, weil deine PWM nur alle > 500us einen Updat der PWM-Ausgabe machen kann. Hier verschenkst du > Zwischenwerte, weil dein Index ca. 6,5 mal schneller läuft als die PWM. > Klar, wenn man jetzt eine niedrigere Frequenz generiert, kann man mehr > Zwischenwerte ausgeben. Hier hast du mich wieder verloren. Meinem Verständnis nach brauche ich einen zweiten, unabhängigen Timer mit 78us Periodendauer. Das resultiert daraus, dass ich meine 256 Sinuswerte in 20ms Periodendauer abklopfen muss. Also muss ich alle 78us meine Sinustabelle auslesen. Dieser Wert wird dann ins OCR1A Register geschrieben und mit der phasenkorrekten PWM verglichen. Wenn ich alles in einem Timer (Timer1) machen würde, hätte mein Sinus doch auch eine hohe Frequenz, weil der Sinus doch nur aus 256 Werten besteht. Ergo müsste ich in den Sinus mehr Zwischenwerte packen, um eine höhere Auflösung desgleichen zu bekommen und die 50Hz beizubehalten. Ich befürchte, dass ich dich noch immer nicht verstanden habe. Wenn es dir nicht zu viel Mühe macht, wäre ich dir dankbar, wenn du mir die ISR mit dem Code zeigen könntest. Vielleicht kann ich dir dann eher folgen.
Da muss ich Falk recht geben, bei einer Periodendauer von 20ms und einer PWM Dauer von 500µs reicht es eigentlich, wenn du z.B. auf einen Timer1_OVL Interrupt oder auch aus dem Timer1_COMP interrupt den Compare Wert aktualisierst, dann benötigst Du eine Tabellengröße von gerade mal 40 Werten, ohne dass Dein Sinus schlechter wird wie jetzt; Wenn Du zudem noch nur eine Viertelwelle Speicherst und nach jeweils 10 Schritten die Zählrichtung des Indexes umkehrst, dann kommst Du sogar mit 10 Werten aus. (ohne Qualitätsverlust)
Nochmal zum Verständniss: Du hast in Deinem Qszilogramm eine Ganze Sinuswelle dargestellt. Die einzelnen PWM Zyklen kannst Du dort von Hand abzählen, und es sind deutlich weniger als Die 256 in der Tabelle, sondern exakt 40 Schritte. Es reicht also aus nach jedem timer1 Durchlauf den index zu aktualisieren, weil alles andere sowieso verloren geht.
nobi schrieb: > Nochmal zum Verständniss: > Du hast in Deinem Qszilogramm eine Ganze Sinuswelle dargestellt. > Die einzelnen PWM Zyklen kannst Du dort von Hand abzählen, und es sind > deutlich weniger als Die 256 in der Tabelle, sondern exakt 40 Schritte. > Es reicht also aus nach jedem timer1 Durchlauf den index zu > aktualisieren, weil alles andere sowieso verloren geht. Jetzt hat es Klick gemacht. Tut mir Leid, Falk, dass ich mich so schwer getan habe. Nun meine ich nachvollziehen zu können, wie es besser zu machen ist. Ich werde mit dem Code ein wenig rumspielen und die Hinweise und Kritik einfügen. Euch allen vielen Dank!
Hallo noch mal, ich habe mal versucht, mich auf den Hinweis mit dem einen Timer (Timer1) zu konzentrieren und das Programm entsprechend zu ändern. Wenn ich euch richtig verstehe, ist das Prinzip das folgende: 1. Timer1 macht phasenkorrekte PWM mit 2kHz. Das heißt, dass TCNT1 alle 500us bei 0 anfängt zu zählen. 2. Jedes mal, wenn TOP erreicht ist (TCNT1 erreicht TOP Wert), entsteht ein Overflow. Das passiert nun alle 250us (dual slope feature bei phasenkorrekte PWM). Da mein Sinus 20ms sein soll und alle 250us ein Interrupt (Overflow) ausgelöst wird, benötige ich 80 Werte in meiner Sinustabelle. Diese Logik habe ich mal implementiert, siehe beigefügten Code. Das Ergebnis ist allerdings alles andere als erhofft :D Tut mir Leid, dass ich mich dämlich anstelle. Aber ich habe ziemliche Verständnisschwierigkeiten in der Umsetzung :( Danke.
Hier noch mal das Bild in einer anderen Zeitskala.
@ Michael (Gast) >Diese Logik habe ich mal implementiert, siehe beigefügten Code. Das >Ergebnis ist allerdings alles andere als erhofft :D Du bist auf dem richtigen Weg, hast das Ziel nur knapp verfehlt! Du hättest deine Sinustabelle bei 256 Einträgen belassen sollen. Denn JETZT, mit nur 80 Einträgen klappt der Trick mit dem Überlauf nicht mehr! Dein Index i geht von 0-255, darf aber nur von 0-79 gehen. Damit greifst du auf undefinierte Daten hinter der Sinustabelle zu. Schlimmer noch, du hast i als int definiert. Das ist eine vorzeichenbehaftete 16 Bit Variable, die erst nach 2^16=65536 Schritten überläuft. Mach also wieder 256 Einträge und nimm einen uint8_t als Index. Die Geschwindigkeit/Frequenz regelt man per variabler Schrittweite, so macht das jede DDS. sei() macht man NACH allen Initialisierungen kurz vor der endlosen Hauptschleife, sonst kann es böse Effekte geben. Und noch was, schreib keine Lyrik in die Kommentare, das bringt nichts. Sowas macht man bestenfalls als Kurzbeschreibeung für Funktionen, aber nicht hinter jeder C-Zeile. >Tut mir Leid, dass ich mich dämlich anstelle. Aber ich habe ziemliche >Verständnisschwierigkeiten in der Umsetzung :( Nana, kein Grund zur Selbstkasteiung ;-) Das ist alles vollkommen normal, es ist noch kein Meister vom Himmel gefallen. Am Ball bleiben ist wichtig.
1 | #include <avr/io.h> |
2 | #include <util/delay.h> |
3 | #include <avr/interrupt.h> |
4 | #include <avr/pgmspace.h> |
5 | #include "SineLookupTable.h" |
6 | |
7 | void CarrierCalculation(void); |
8 | //void SineCalculation(void);
|
9 | |
10 | volatile uint8_t table_inc=6; |
11 | |
12 | int main(void) |
13 | {
|
14 | DDRB |= (1<<PB1); // PB1 (OCA1) as output |
15 | CarrierCalculation(); |
16 | //SineCalculation();
|
17 | sei(); |
18 | |
19 | while(1) |
20 | {
|
21 | |
22 | }
|
23 | }
|
24 | |
25 | void CarrierCalculation(void) |
26 | {
|
27 | OCR1A = pgm_read_word(&sineLookup[0]); // First init |
28 | ICR1 = 500; // PWM max count |
29 | TCCR1A |= (1<<COM1A1) | (1<<WGM11); |
30 | TCCR1B |= (1<<WGM13) | (1<<CS10); // Mode 10, Prescaler 1 |
31 | TIMSK |= (1<<TOIE1); |
32 | }
|
33 | |
34 | ISR(TIMER1_OVF_vect) |
35 | {
|
36 | static uint8_t i = 0; |
37 | |
38 | i += table_inc; |
39 | OCR1A=pgm_read_word(&sineLookup[i]); |
40 | }
|
Vielen Dank für deine Hilfe, Falk. Es komme erst morgen dazu, mich weiter damit auseinander zu setzen. Ich werde dann Rückmeldung geben. Gruß
Noch ein Tip zu Debuggen. Schau dir nicht die PWM direkt an, sondern nach einem passenden RC-Filter. Fürs erste reicht hier vielleicht ein 200 Hz RC-Filter 1. Ordung. Sagen wir 10k und 3,3uF. Dann siehst du deinen Sinus direkt.
Michael schrieb: > Hier noch mal das Bild in einer anderen Zeitskala. Wird das hier zum Volkssport - winzige Bilder? http://www.mikrocontroller.net/attachment/173742/F0000TEK.png
Wieso winzig? 320x240 ist ein 1:1 Bild.
Hallo an alle, hier nun wie versprochen das Update. Zunächst allerdings ein Bild vom Aufbau. Das Filter besteht aus einem 200kOhm Widerstand mit einem 820nF Folienkondensator. Sonderlich viel Auswahl hatten wir leider nicht. Zu deinem Code, Falk: Grundsätzlich sieht das gut aus, siehe F0000TEK. Allerdings beträgt die Periodendauer 21.2ms anstelle der gewünschten 20ms. Ich habe noch mal selbst versucht meinen Fehler von Freitag zu finden und eine SPWM zu implementieren. Und es funktioniert nun, siehe F0001TEK. Die Sinustabelle besteht aus 40 Werten, Periodendauer beträgt 19.60ms. Den Code habe ich mit beifügt für jene, die es interessiert. Eine abschließende Frage hätte ich noch: Zwischen dem PWM Ausgang (Kanal 2) und dem gefilterten Signal (Kanal 1) sieht man eine deutliche Phasenverschiebung. Ich hätten den Spitzenwert des Sinus beim größten Duty Cycle (also in der Mitte bei der größten Pulsbreite) des PWMs erwarten. Ich frage mich, woher die Phasenverschiebung kommt. Ich vergleiche ja nicht Spannung mit Strom, sodass eine Phasenverschiebung durch den kapazitiven Anteil des Filters verursacht wird. Das Filter dient ja lediglich dazu, hochfrequente Oberwellen zu unterdrücken. Man sieht ja noch ein Zappeln auf dem Sinus, das sind die nicht unterdrückten Oberwellen. Der Sinus, den wir hier sehen, müsste ja sowohl von der Frequenz als auch von der Phasenlage mit dem PWM Pattern übereinstimmen. Weiß jemand von euch, warum das gefilterte Signal phasenverschoben ist und lässt mich an dem Wissen teilhaben?
@ Michael (Gast) >Aufbau. Das Filter besteht aus einem 200kOhm Widerstand mit einem 820nF >Folienkondensator. Sonderlich viel Auswahl hatten wir leider nicht. Ist OK. >Grundsätzlich sieht das gut aus, siehe F0000TEK. Allerdings beträgt die >Periodendauer 21.2ms anstelle der gewünschten 20ms. Logisch, weil die 6 gerundet sind, echt müsten es 6,4 sei. Aber eins nach dem anderen ;-) >Den Code habe ich mit beifügt für jene, die es interessiert. Gut. >Ich frage mich, woher die Phasenverschiebung kommt. Vom Filter. > Ich vergleiche ja >nicht Spannung mit Strom, sodass eine Phasenverschiebung durch den >kapazitiven Anteil des Filters verursacht wird. Doch. Denn dein Ausgangs"widerstand" ist ein Kondensator. Jeder Filter hat auch einen Phasengang, auch dein einfacher RC-Filter. Deutlich unterhalb der 3dB Bandbreite ist der nahe Null, bei 3dB hat man 45 Grad Phasenverschiebung, nach oben hin geht es dann auf 90 Grad zu. > Das Filter dient ja >lediglich dazu, hochfrequente Oberwellen zu unterdrücken. Sicher, aber diese Eigenschaft kommt nicht allein. >Oberwellen. Der Sinus, den wir hier sehen, müsste ja sowohl von der >Frequenz als auch von der Phasenlage mit dem PWM Pattern übereinstimmen. Nein.
Damit man die Frequenz feiner einstellen kann, nutzt man einfach Festkommaarithmetik. Dazu nimmt man anstelle eines 8 Bit Index einen 16 Bit Index, wobei die unteren 8 Bit die Nachkommastellen darstellen, welche beim Tabellenzugriff abgeschnitten werden. Siehe unten, wobei hier wieder mit der 256er Sinustabelle gearbeitet wird. Damit kann man die Nachkommastellen mit 1/256 vorgeben.
1 | #include <avr/io.h> |
2 | #include <util/delay.h> |
3 | #include <avr/interrupt.h> |
4 | #include <avr/pgmspace.h> |
5 | #include "SineLookupTable.h" |
6 | |
7 | volatile uint16_t f_inc=6*256 + 102; |
8 | |
9 | int main(void) |
10 | {
|
11 | DDRB |= (1<<PB1); // PB1 (OCA1) as output |
12 | OCR1A = pgm_read_word(&sineLookup[0]); // Value where match occurs. Later to be replaced by the sine wave |
13 | ICR1 = 500; // TOP value for TCNT1 register |
14 | TCCR1A |= (1<<COM1A1); // High at bottom, low on compare match |
15 | TCCR1A |= (1<<WGM11); // Mode 10 |
16 | TCCR1B |= (1<<WGM13); // Mode 10 |
17 | TCCR1B |= (1<<CS10); // Prescaler set to 1 |
18 | TIMSK |= (1<<TOIE1); |
19 | sei(); |
20 | while(1) |
21 | {
|
22 | |
23 | }
|
24 | }
|
25 | |
26 | ISR(TIMER1_OVF_vect) |
27 | {
|
28 | static uint16_t i; |
29 | i+= f_inc; |
30 | OCR1A=pgm_read_word(&sineLookup[i>>8]); |
31 | }
|
Falk Brunner schrieb: > Logisch, weil die 6 gerundet sind, echt müsten es 6,4 sei. Aber eins > nach dem anderen ;-) In seinem angehängten Code gibt's keine Schrittweite von 6. Könnte eher vom ungenauen internen R/C kommen, außerdem ist ICR als Top mit 500 falsch. Schau' die Formel im DB nach, das gibt 501 Schritte bis CT.
Falk Brunner schrieb: > Doch. Denn dein Ausgangs"widerstand" ist ein Kondensator. Jeder Filter > hat auch einen Phasengang, auch dein einfacher RC-Filter. Deutlich > unterhalb der 3dB Bandbreite ist der nahe Null, bei 3dB hat man 45 Grad > Phasenverschiebung, nach oben hin geht es dann auf 90 Grad zu. Ah stimmt, natürlich. Völlig vergessen, dass es ja noch so ein Übertragungsverhalten gibt. Okay, jetzt ist alles glasklar. Vielen Dank für deine Hilfe und deine Geduld. Gruß
Noch was, die Sinustabelle gehört in eine .c Datei, in .h wird nur deklariert (bekannt machen), nicht definiert (Speicher zuweisen). http://www.mikrocontroller.net/articles/FAQ#Header_File.2C_wie_geht_das.3F sinus.h extern const uint16_t sineLookup[] PROGMEM; sinus.c const uint16_t sineLookup[] PROGMEM={ 250, ......
@ MWS (Gast) >> Logisch, weil die 6 gerundet sind, echt müsten es 6,4 sei. Aber eins >> nach dem anderen ;-) >In seinem angehängten Code gibt's keine Schrittweite von 6. Doch, man muss nur den richtigen Anhang betrachten. ;-) Beitrag "Re: SPWM auf Atmega8, bitte um Feedback hinsichtlich Optimierung"
Falk Brunner schrieb: > Noch was, die Sinustabelle gehört in eine .c Datei, in .h wird nur > deklariert (bekannt machen), nicht definiert (Speicher zuweisen). Werde mich damit befassen und den Link durchlesen. Hatte es mal auf die Schnelle versucht zu ändern, aber mit folgender Fehlermeldung: "../SineLookupTable.c:2:16: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'sineLookup' " Muss mich mal schlau machen, was damit gemeint ist. Wenn ich nicht weiterkomme, melde ich mich.
@ Michael (Gast) >Schnelle versucht zu ändern, aber mit folgender Fehlermeldung: >"../SineLookupTable.c:2:16: error: expected '=', ',', ';', 'asm' or >'__attribute__' before 'sineLookup' >" Naja, man braucht in jeder .c Datei die notwendigen inludes #include <avr/pgmspace.h>
Falk Brunner schrieb: > Doch, man muss nur den richtigen Anhang betrachten. ;-) Ich schrieb: "angehängten Code" und das war dieser: Beitrag "Re: SPWM auf Atmega8, bitte um Feedback hinsichtlich Optimierung" MWS schrieb: > In seinem angehängten Code gibt's keine Schrittweite von 6. Darauf bezog sich seine ursprüngliche Nachricht, Deine Antwort, als auch darauf meine Nachricht. Warum sollte ich plötzlich über früheren Code diskutieren wollen ? Da bringst Du was durcheinander.
MWS schrieb: > außerdem ist ICR als Top mit 500 > falsch. Schau' die Formel im DB nach, das gibt 501 Schritte bis CT. Das habe ich noch mal überprüft. Auf Seite 92 im Datenblatt kann die PWM Frequenz im phasenkorrekten PWM berechnet werden:
Umgestellt nach TOP:
Mit
folgt:
Wenn ich das Datenblatt richtig verstehe, hält ICR1 den TOP Wert inne.
Habe ich irgendwo einen Fehler?
Stimmt schon, du machst phase Correct PWM. Das mit 499 wäre bei Fast PWM oder CTC der Fall.
Okay, dann möchte ich das Thema für mich an dieser Stelle gerne abschließen, denn das Problem wurde durch die tolle Unterstützung hier im Forum gelöst. Die SPWM funktioniert nun und noch besser: Ich weiß sogar, wieso :D Damit habe ich mein erstes kleines Projekt in Sachen uC fertiggetsellt und kann nun mit dem Hardwareteil fortfahren. Gruß, Michael
Michael schrieb: > Okay, dann möchte ich das Thema für mich an dieser Stelle gerne > abschließen, denn das Problem wurde durch die tolle Unterstützung hier > im Forum gelöst. Die SPWM funktioniert nun und noch besser: Ich weiß > sogar, wieso :D > > Damit habe ich mein erstes kleines Projekt in Sachen uC fertiggetsellt > und kann nun mit dem Hardwareteil fortfahren. Und natürlich einen großen Dank an alle Beteiligten!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.