Forum: Mikrocontroller und Digitale Elektronik SPWM auf Atmega8, bitte um Feedback hinsichtlich Optimierung


von Michael (Gast)


Angehängte Dateien:

Lesenswert?

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

von Thomas (Gast)


Lesenswert?

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 ;-)

von J. T. (chaoskind)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@  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

von Michael (Gast)


Lesenswert?

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!

von Falk B. (falk)


Lesenswert?

@  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.

von Michael (Gast)


Lesenswert?

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.

von nobi (Gast)


Lesenswert?

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)

von nobi (Gast)


Lesenswert?

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.

von Michael (Gast)


Lesenswert?

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!

von Michael (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Michael (Gast)


Angehängte Dateien:

Lesenswert?

Hier noch mal das Bild in einer anderen Zeitskala.

von Falk B. (falk)


Lesenswert?

@  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
}

von Michael (Gast)


Lesenswert?

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ß

von Falk B. (falk)


Lesenswert?

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.

von Bludon (Gast)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

Wieso winzig? 320x240 ist ein 1:1 Bild.

von Michael (Gast)


Angehängte Dateien:

Lesenswert?

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?

von Falk B. (falk)


Lesenswert?

@  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.

von Falk B. (falk)


Lesenswert?

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
}

von MWS (Gast)


Lesenswert?

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.

von Michael (Gast)


Lesenswert?

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ß

von Falk B. (falk)


Lesenswert?

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, ......

von Falk B. (falk)


Lesenswert?

@  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"

von Michael (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@  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>

von MWS (Gast)


Lesenswert?

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.

von Michael (Gast)


Lesenswert?

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?

von Falk B. (falk)


Lesenswert?

Stimmt schon, du machst phase Correct PWM. Das mit 499 wäre bei Fast PWM 
oder CTC der Fall.

von Michael (Gast)


Lesenswert?

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

von Michael (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.