Moin.
Ich versuche einen Sinus per PWM zu erzeugen. Bin noch ganz am Anfang.
Ich habe mir gestern mal ausgerechnet, welche Sinusfrequenz ich
höchstens (ohne Wert überspringen oder so) erzeugen kann.
Ich würde einen 8-Bit Timer nehmen und eine Taktfrequenz von 16MHz.
Daraus resultiert bei einer EEPROM größe von 512 (ATMega8) ca. 60Hz.
Kann das hinkommen?
Naja, mein eigentliches Problem ist, das ich erstmal, bevor ich das
EEPROM beschreibe, ein 512-Werte breites Array hernehmen wollte um zu
sehen ob die Werte richtig berechnet werden.
Der Datentyp ist uint8_t, da ich nur die Positive Halbwelle speichern
will und die EEPROM-Werte ja 8 bit breit sein sollen.
Die Berechnung gestaltet sich wie folgt:
Ich finde im Moment absolut nicht herraus, warum mein Debugger das nicht
mitmachen will.
Der zeigt an "Running" und macht dann nix mehr...
Denke das muss ein ganz dummer Fehler sein.
Hoffe Ihr könnt mir helfen
Grüße
Jan
Hallo Jan, ich geb zu, ich hab mir deinen Code gar nicht angeschaut,
aber ist es nicht sinnvoller, die Sinuswerte nicht im Mikrocontroller
zu berechnen, sondern sie schon während der Erstellung des Programms zu
ermitteln und sie dann in eine Tabelle in den Flashspeicher zu
schreiben?
Ich hab mir das mit dem Wiki angesehen. Scheint mir echt ne gut
Möglichkeit zu sein die Werte zu erzeugen. Naja, EEPROM hatte ich mir
nur gedacht, um damit mal ein bisschen rum zuexperimentieren, aber ich
glaub ich werde ne bessere Anwendung dafür finden ;-)
Ich greif dann wohl doch auf den Flash-Speicher zurück. Davon is beim
Mega8 ja auch genug vorhanden.
Danke für die Hilfreichen Kommentare.
Gruß
Jan
Lieber Brunner-Ossi,
wer damit Probleme hat, zwei Oktette zu adressieren und auszulesen, für
den ist die Programmierung von Microcontrollern eventuell nicht das
passende Hobby. Soweit ich in diesem Forum gelesen habe bist Du doch der
Schlaumeier, der immer sagt "Wenn Du schon die Basics nicht beherrschst,
wie willst Du dann erst $_Irgendwas machen?"
xxx
Schast (Gast) schrieb:> J.-u. G. schrieb:>> Für 512 reicht uint16_t.>> Für 512 Werte reicht ein Oktett + Extrabit!
Also insgesamt neun Bit? Ein Oktett sind acht Bit, plus eins sind neun.
Und du willst allen ernstes 512 Werte zu jeweils 16 Bit in 9 Bit
unterbringen? Das will ich sehen!
Da fällt mir folgendes ein: Mittlerweile ist die Programmierung von
Kompressions-Algorithmen schon so weit fortgeschritten, daß schon der
Inhalt aller Bücher einer Bibliothek auf 1 Bit reduziert werden kann.
Am Dekompressions-Algorithmus wird allerdings noch eine Weile
gearbeitet.
Wenn du einen 8Bit Timer hast, dann rechnest du dir einen Sinus mit 100
Werten mit Excel aus. y1 = 255 * sin (3,6 / 360) das ganze in 3,6er
Schritten hochgezählt. Diese Tabelle speicherst du dann ins RAM. Wenn du
nun die Werte über eine PWM ausgibst, z.B. mit 5kHz kommt hinten ein
Sinus mit 50Hz raus. Ggf kann man die Stützstellen reduzieren, damit man
die Frequenz steigern kann. Ein Sinus mit 30 Stützstellen sieht
immernoch gut.
@Schast:
Übrigens, auch wenn du die Zählvariable "i" aus dem Progamm mit deiner
Aussage meinst, hat trotzdem Falk recht. Die nächstgrößere Variable nach
uint8_t ist nun mal uint16_t und nicht uint9_t! Oder hast du schonmal
eine 9-Bit-Variable gesehen?
Bernd S. schrieb:> Übrigens, auch wenn du die Zählvariable "i" aus dem Progamm mit deiner> Aussage meinst, hat trotzdem Falk recht.
"i" und "Programm" interessiert mich nicht sonderlich. Es ging doch
darum, daß sich 512 Werte mit 9 Bits repräsentieren lassen.
> Die nächstgrößere Variable nach uint8_t ist nun mal uint16_t> und nicht uint9_t!
Was interessiert irgendein C-Konstrukt uint_irgendwas? Der Punkt war,
daß sich 512 Werte mit 9 Bit abbilden lassen. Definieren wir ein Byte
als ein Oktett, und nehmen wir an, daß 8 Variablen mit 512
Wertemöglichkeiten verarbeitet werden müssen. Dann gibt es 2
Möglichkeiten:
1.) Ich nehme 2 Bytes je Variable, macht 16 Byte (Gesamt: 128 Bit)
2.) Ich nehme je 1 Byte + 1 Bit und definiere eine Bitmask (Gesamt: 72
Bit)
=> Ersparnis bei Fall 2: Mehr als die Hälfte des Speichers.
Ist immer ein Trade-Off zwischen Speicher, Speed und Codesize.
> Oder hast du schonmal eine 9-Bit-Variable gesehen?
Scheiße, ich komm' grade nicht drauf, welche Architektur das war, die
eine Bytesize von 13 Bits hatte.
Schast (Gast) schrieb:> Scheiße, ich komm' grade nicht drauf, welche Architektur das war, die> eine Bytesize von 13 Bits hatte.
Gemini-Boardcomputer.
mfg.
Schast (Gast) schrieb:> Was interessiert irgendein C-Konstrukt uint_irgendwas? Der Punkt war,> daß sich 512 Werte mit 9 Bit abbilden lassen.
Nein. Es ging darum auf einem ATMega8, den passenden Typ für einen
Schleifenzähler, der bis 512 zählen soll, zu verwenden.
Mal abgesehen vom der Bitzahl deiner Variablen,
frag ich mich was die Beschränkung auf die positive
Halbwelle bringen soll. ???
Willst du die Daten bei jedem PWM-Zyklus aus dem EEPROM
lesen? - Das dauert E-W-I-G!
Wenn man sie zum µC-Start vom EEPROM ins RAM kopiert,
spart man immerhin Flash-Speicher.
Mach lieber eine Tabelle von -90° bis +90°.
Und nutze nicht den gesamten Zahlenraum aus:
Du kannst dem Zähler nicht sagen "warte auf NULL", wenn
er schon auf 3 gezählt hat!
Oh man, da hab ich ja wieder eine Diskussion ausgelöst...
Naja, bei mir funktionierts jetzt jedenfalls.
Ich habe den Code aus dem Wiki ein bisschen umgestrickt so das ich die
Werte mit sin(...) berechne. Jeden berechneten Wert multipliziere ich
mit 255 und speichere ihn im Headerfile ab. Ich habe statt einer
while... eine for... genommen.
Also der Code in der for sieht so aus:
1
for(i=0;i<512;i++)
2
{
3
sine=sin(2*PI*((double)i/1024));
4
sine_uint8_t=(char)(255*sine);
5
sprintf(buffer," %d\n",sine_uint8_t);
6
fputs(buffer,fp);
7
}
Das erzeugte array muss dann natürlich noch uint8_t als typ bekommen.
Ich denke so kann man auch mit dem 8-Bit-PWM dingens gemütlich arbeiten
ohne im nachhinein noch irgendwas umrechnen zu müssen. Soweit jedenfalls
meine Hoffnung. Mal sehen was draus wird ;-)
Ich Bastel mir jetzt mal den PWM-Scheiß zurecht und dann mal sehen was
passiert.
Trotzdem danke für die vielen hilfreichen Tipps. Achja, für irgendwelche
Anmerkungen bin ich natürlich immer offen.
Grüße Jan
Schast (Gast) schrieb:> "i" und "Programm" interessiert mich nicht sonderlich. Es ging doch> darum, daß sich 512 Werte mit 9 Bits repräsentieren lassen.
Damit läßt sich ein Wert von 0..511 darstellen
Übrigens ging es genau um das Programm und eine Lösung für die
Sinustabelle.
> Was interessiert irgendein C-Konstrukt uint_irgendwas?
Das interessiert schon, weil der Fragesteller mit C programmiert.
> Ist immer ein Trade-Off zwischen Speicher, Speed und Codesize.
Eben, und hier geht es um eine möglichst schnelle Sinus-Erzeugung per
PWM. Da kommt es eben auf die Geschwindigkeit an, da kann man sich keine
Bit-Schiebereien leisten. Ich weiß, wie du das meinst, aber sowas kann
man machen, wenn man viel Zeit hat. Hier eben nicht.
> Scheiße, ich komm' grade nicht drauf, welche Architektur das war, die> eine Bytesize von 13 Bits hatte.
Daß es andere Architekturen gibt, weiß ich, aber hier geht es um einen
ATmega und um C.
Es tut mir sehr Leid, dass ich mich hier einklinke und damit ggf. die
Übersicht ein wenig zerstöre. Allerdings bin ich ebenfalls gerade dabei,
eine Sinus PWM auf einem Atmega zu realisieren und befinde mich auch bei
der Sinustabelle.
Der Timer auf dem uC zählt von Bottom (0x00) bis zum TOP Wert (sagen wir
mal z.B. 0xFF oder einen Wert im OCR1x/ICR1 Register). Also ist der
Wertebereich im Timer >=0, d.h. keine negativen Zahlen.
Der Sinus hingegen hat eine negative Halbwelle. Wie genau löst man das
elegant?
Meinen Recherchen im Internet nach baut man sich eine Lookup Tabelle vom
Sinus, der mit einem Offset nach oben versehen ist. Das heißt, dass die
positive Amplitude irgendwo nahe dem TOP Wert ist und die negative
Amplitude irgendwo nahe am Bottom (Je nach Modulationsindex). Der
"Nulldurchgang" des Sinus ist also irgendwo über 0 im positiven Bereich.
So macht es z.B. die Lookup Tabelle auf dieser Seite:
http://www.daycounter.com/Calculators/Sine-Generator-Calculator2.phtml
Sehe ich das richtig, dass das eine Variante zur Sinus PWM ist? Oder ist
das zu umständlich und es geht auch wesentlich einfacher (wie hier
bereits angedeutet mit lediglich einer Halbperiode, da sich die Werte
wiederholen aber mit negativem Vorzeichen). Allerdings frage ich mich
dann, wie die zweite/negative Halbwelle berücksichtigt wird.
Es wäre nett, wenn jemand zu meinem Anliegen Bezug nehmen könnte.
Gruß,
al3ko
@ al3ko
Na logisch! Was aus der PWM herauskommt, wenn der µC mit
positiver Versorgungsspannung betrieben wird, kann nur
positiv sein.
- Auch der unterste Punkt der negativen Halbwelle.
Das ist keine Variante, sondern das wahre Leben.
Willst du ein nullsymmetrisches elektrisches Signal haben,
musst du entweder mit einem Kondensator die Gleichspannung
abtrennen, oder einen Operationsverstärker mit passendem
Offset versehen.
Bernie schrieb:> @ al3ko>> Na logisch! Was aus der PWM herauskommt, wenn der µC mit> positiver Versorgungsspannung betrieben wird, kann nur> positiv sein.
Richtig. Allerdings geht es mir eher um das Pulse Pattern für die
Ansteuerung der FETs. Salopp gesagt so wie hier:
http://www.tgipmt.com/resource%20images/articles/motor%20speed%20control/mf32.gif
Dass der Ausgang am uC allerdings 0 bzw. VCC ist, stört mich weniger,
denn das Signal kommt eh in einen Gatetreiber und dann an eine H-Brücke
(wo dann am Ende +-V_DClink entsteht). Wie gesagt, das Pulse Pattern ist
für mich wichtig und genau da sehe ich den Timer als Carriersignal und
den Sinus als Referenzsignal ausschlaggebend. Um das Pulse Pattern aus
dem oben verlinkten Bild zu bekommen, hätte ich jetzt den Timer von 0
bis TOP zählen lassen sowie den Sinus mit einem Offset versetzt.
Sollte so richtig sein, oder?
Spess53 schrieb:> Das beschreibt aber eine analoge PWM. Also Vergleich eines> Eingangssignal mit einem Dreieckssignal.
Da muss ich noch mal nachhaken. Ich hätte jetzt den Timer im Phase
correct modus laufen lassen, um das Dreiecksignal mit dual slope zu
bekommen (na klar diskretisiert). Somit habe ich doch schon mal das
hochfrequente Carriersignal.
Den Sinus als Referenzsignal würde ich über die Lookup Tabelle
realisieren und den Wert zum jeweiligen Zeitpunkt in das OCR1A bzw. ICR1
Register laden. Somit hätten wir doch die digitale Version von der
analogen PWM, oder habe ich einen gravierenden Gedankenfehler?
Falls ja, wäre ich dir/euch sehr dankbar, wenn ihr mir auf die Sprünge
helfen könntet, es richtig zu verstehen, denn scheinbar sehe ich den
Wald vor lauter Bäumen nicht :)