Forum: Mikrocontroller und Digitale Elektronik Sinuswerte in Array speichern


von Jan S. (spongebob)


Lesenswert?

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:
1
#include <math.h>
2
3
uint8_t sin_arr[512];
4
5
void init_sin(void)
6
{
7
  uint8_t i;
8
  
9
for (i=0; i<512; i++)
10
{
11
  sin_arr[i] = (uint8_t)(255*sin(2*3.141*((double)i/1024.0)));
12
}
13
  
14
}
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

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

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?

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Grad hier im sehr nützlichen Mikrocontroller-Wiki gefunden: [[Sinus 
Tabelle]] (schreibt man eigentlich zusammen oder mit Bindestrich) ;-)

von jochen (Gast)


Lesenswert?

uint8 ist immer kleiner 512.. du hast eine Endlos Schlaufe.. must uint32 
oder grösser nehmen.

von J.-u. G. (juwe)


Lesenswert?

jochen schrieb:
> must uint32
> oder grösser nehmen.

Um Himmels willen....

Für 512 reicht uint16_t.

von Jan S. (spongebob)


Lesenswert?

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

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Diese nützliche Website erzeugt dir die gewünschte Sinus Tabelle:
http://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml

von Schast (Gast) (Gast)


Lesenswert?

J.-u. G. schrieb:
> Für 512 reicht uint16_t.

Für 512 Werte reicht ein Oktett + Extrabit!

von Falk B. (falk)


Lesenswert?

@  Schast (Gast) (Gast)

>> Für 512 reicht uint16_t.

>Für 512 Werte reicht ein Oktett + Extrabit!

Viel Spass bei der Adressierung und Handhabung.

von Schast (Gast) (Gast)


Lesenswert?

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

von Bernd S. (bernds1)


Lesenswert?

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.

von Ingo (Gast)


Lesenswert?

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.

von Bernd S. (bernds1)


Lesenswert?

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

von Schast (Gast) (Gast)


Lesenswert?

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.

von Thomas E. (thomase)


Lesenswert?

Schast (Gast) schrieb:
> Scheiße, ich komm' grade nicht drauf, welche Architektur das war, die
> eine Bytesize von 13 Bits hatte.
Gemini-Boardcomputer.

mfg.

von J.-u. G. (juwe)


Lesenswert?

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.

von Bernie (Gast)


Lesenswert?

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!

von Thomas E. (thomase)


Lesenswert?

Bernie schrieb:
> Mach lieber eine Tabelle von -90° bis +90°.
0-90° reicht auch. Die negative Amplitude bekommt einfach ein Offset.

mfg.

von Jan S. (spongebob)


Lesenswert?

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

von Bernd S. (bernds1)


Lesenswert?

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.

von al3ko (Gast)


Lesenswert?

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

von Bernie (Gast)


Lesenswert?

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

von al3ko (Gast)


Lesenswert?

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?

von Spess53 (Gast)


Lesenswert?

Hi

> Salopp gesagt so wie hier:
>http://www.tgipmt.com/resource%20images/articles/m...

Das beschreibt aber eine analoge PWM. Also Vergleich eines 
Eingangssignal mit einem Dreieckssignal.

MfG Spess

von al3ko (Gast)


Lesenswert?

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

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.