Forum: Mikrocontroller und Digitale Elektronik Exponetialfunktion ohne Tabelle?


von Chris O. (lupin_iii)


Angehängte Dateien:

Lesenswert?

Ich hoffe es traut sich jemand

Ich habe an einem ATmega8 an Port B und D 16 LEDs hängen, die je nach
Effekt in irgendeinem Muster (alle an, alle gleichzeitig blinken,
zufälliges linken, Lauflicht u.a.) leuchten.

Da die Effekte mit verschiedenen Geschwindigkeiten laufen sollen, gibt
es an Port C 2 Taster für schneller/langsamer. Intern wird dann eine
Variable zwischen 0 und 255 verändert. Wenn ich den Wert direkt ins
OCR2 füttere (Timer2 läuft im CTC-Mode), dann ist das Verhalten nicht
gerade toll (z. B. von 20 auf 10 => Effekt doppelt so schnell, von 220
auf 210 => fast keine Änderung bemerkbar; beides sind aber zehn
Einstellungsschritte).

Kleine Anmerkung: ich verwende nachher 256, obwohl nur 255 in die
Register passt. Das ist aber zum Rechnen bequemer.

Wünschenswert ist ein Verhalten, bei dem sich die Geschwindigkeit
exponetiell ändert:

s(speed) = wert_für_ocr2
s(0)     = 256
s(128)   =  16
s(256)   =   1

Das lässt sich ganz leicht berechnen: 256 >> (speed >> 5). Das Problem
dabei ist: so kommen insgesamt nur 8 unterschiedliche Schritte heraus,
wobei sich jedesmal die Geschwindigkeit verdoppelt.

Deswegen ist meine nächste Lösung, das 256 vor dem Shiften durch einen
anderen Wert zu ersetzen, je nachdem was in Bits 3 und 4 von speed
steht. In Assembler sieht das dann so aus:

###################
Oh grade gelesen, dass man den anhängen soll. Also siehe Anhang...
###################

Das sind schon einige Schritte mehr, aber dafür schon ein ganze Menge
Code. Ich habe noch nicht so viel in Assembler gemacht. Gibt es da eine
Möglichkeit den selben Effekt übersichtlicher und schneller zu
erreichen, ohne gleich eine Tabelle im EEPROM zu verwenden?

von Thomas K. (thkais)


Lesenswert?

Du musst die Tabelle ja nicht ins EEPROM schreiben, sondern kannst auch
den Flash verwenden...
In so einem Fall ist eine Tabelle wirklich das allereinfachste.
Eigentlich brauchst Du eine 1/x - Funktion, wenn ich das richtig
durchblicke.

von Profi (Gast)


Lesenswert?

Die Exponentialfunktion ensteht, wenn man die Frequenz von Stufe zu
Stufe mit einem konstanten Faktor multipliziert, d.h. den Timerwert
durch einen konstanten Wert dividiert.

Das kann man mit einer Tabelle machen ,aber auch einfach on-the-fly
berechnen:
Damit man genug Auflösung hat, bietet sich hier eine 16x16
Fixedpoint-Arithmetik an. Vom 32-Bit-Ergebnis verwendest Du die 8
höchsten Bits für den Timer.
Z.B. für 12 Schritte für ein Frequenzverhältnis 10:1 ist die Konstante
1,21153 (wie in der E12-Reihe für Widerstände):
für die eine Richtung addierst Du das 0,21153-fache, indem Du mit
0,21153*65536=13863 multiplizierst und zum Grundwert addierst.

für die andere Richtung multiplizierst Du mit dem Kehrwert
0,8254*65536=54094

Schritt F  8bitTeiler
  0   1,00   255
  1   1,21   210
  2   1,47   174
  3   1,78   143
  4   2,15   118
  5   2,61    98
  6   3,16    81
  7   3,83    67
  8   4,64    55
  9   5,62    45
 10   6,81    37
 11   8,25    31
 12  10,00    25

Eine ganz andere Methode wäre die Erzeugung des Tabellenindexes wie bei
der DDS (direkte digitale Synthese) durch regelmäßige (mit z.B. 10kHz)
Addition mit einer Konstanten, welche proportional zur gewünschten
Frequenz ist.

von Chris O. (lupin_iii)


Lesenswert?

Danke für die Antworten!

Ich habe mir die Lösungen angesehen. Die Fixed-Point-Lösung braucht mir
zu viele Register und auch Rechenzeit, obwohl sie eigentlich am
sichersten (vor Programmierfehlern) und sehr leicht an andere Raten pro
Schritt anpassbar ist. Aber da der speed-Wert auch immer wiedermal
direkt gesetzt werden kann und nicht nur um eins nach oben oder unten
geht, könnte das im Extremfall 255 Multiplikationen hintereinander
bedeuten.

Die DDS braucht ja auch eine Tabelle. Wenn ich keine verwende nicht
ergibt sich durch Addieren keine a^x sondern nur eine a*x Funktion, was
das inverse der 1/x Funktion ist. Und bei beiden ergibt sich nicht das
gewünschte Verhalten, dass sich bei gleicher Schrittanzahl (z. B. 5mal
+ drücken) die Geschwindigkeit immer um den gleichen Faktor ändert.

Im Endeffekt werde ich doch eine Tabelle mit 64 Werten, allerdings im
Flash, nehmen. Das scheint in dem Fall tatsächlich die beste Lösung zu
sein und ist ein guter Kompromiss zwischen Auflösung, Speicherverbrauch
und Rechenaufwand zu sein. Außerdem habe ich gemerkt, dass ein OCR2 Wert
von 1 sowieso viel zu wenig ist, da dann nur noch alles flackert. Mit
einer Tabelle kann ich die speed-to-OCR2-Werte leichter von z. B. 10
bis 255 exponteial verteilen.

Aber ich merke mir die Vorschläge, falls eine Vorberechnung mal nicht
möglich ist!

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.