mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Exponetialfunktion ohne Tabelle?


Autor: Chris O. (lupin_iii)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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?

Autor: Thomas K. (thkais)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Profi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Chris O. (lupin_iii)
Datum:

Bewertung
0 lesenswert
nicht 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!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.