mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Wie Berechnung in AVR Assembler möglichst schnell?


Autor: HHe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Tag,

ich möchte folgende Berechnung mit einem AVR ATmega48 in Assembler 
möglichst rechenzeitunintensiv programmieren:
Der als unsigned angenommene Wert eines Registers MessReg enthält die 
oberen 8 Bit einer ADC Messung. Es soll nun das 2er Komplement gebildet 
werden (neg MessReg) und dann folgende Rechnung ausgeführt werden:
(A/255)*100 = (A*100)/255 (auf ganze Stellen genau, das Ergebnis soll 
ein unsigned Byte sein)
wobei A der Wert von MessReg ist.
Dies wäre mit (kleinem) Fehler leicht durch:
ldi temp, 100
mul MessReg, temp (r1: High Byte des Ergebnisses, r0: Low)
zu erledigen (r1 enthielte das Ergebnis von (A*100)/256).

Hat jemand eine Idee, wie es anders ginge, oder man den nach obiger 
Methode entstehenden Fehler eliminieren könnte? (Die Genauigkeit ist mir 
eh relativ egal, es geht mehr darum, dass man mit meiner Methode nie auf 
100% käme.)


Gruß
HHe

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@HHe (Gast)

>ich möchte folgende Berechnung mit einem AVR ATmega48 in Assembler
>möglichst rechenzeitunintensiv programmieren:

Schönes Wort "rechenzeitunintensiv" ;-)

>(A/255)*100 = (A*100)/255

Das ist keine Rechung, sondern ein Gleichung.

>Hat jemand eine Idee, wie es anders ginge, oder man den nach obiger
>Methode entstehenden Fehler eliminieren könnte?

Wo kommt denn dein /255 her? Da es um einen ADC geht und um 8 Bit, 
behaupte ich mal, dass die Rechnung /256 lauten muss, und nicht /255.

Siehe Festkommaarithmetik.

MFg
Falk

Autor: Reinhard R. (reirawb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was hältst du von (A * 201)/512?
Ist immer noch 8 Bit Multiplikation aber der Fehler ist viel geringer.
Außerdem ist der Fehler positiv, d.h. du kannst auf einen Wert von 100% 
kommen.
Kommt allerdings noch ein Schiebebefehl dazu.

Gruß Reinhard

Autor: Michael Appelt (micha54)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

vermutlich willst du denWert als Prozentzahl von 0 bis 100 ausgeben.

Einfach eine Tabelle mit 256 Werten anlegen und den umgerechneten Wert 
dort auslesen.

unsigned char tabelle [256] = {0, 1, 1, 1, 2, 2....100};
unsigned int wert = tabelle[A];

Evtl. gleich in Ascii eintragen, dann spart das reichclich Rechenzeit.

struct {char [4] wert} tabelle [256] = {"  0%", "  1%"......

Gruss,
Michael

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist zwar für 10Bit beschrieben, aber geht auch für 8Bit.
Da ist Skalierung und Umrechnung in ASCII gleich drin
Beitrag "Re: Problem mit ADC an mega128"

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da der ADC 256 Schitte auflöst, willst du wahrscheinlich

  x = round(A*100/256)
    = int(A*100/256 + 1/2)
    = int(A*100/256 + 128/256)
    = int((A*100 + 128)/256)

berechnen (round rundet zur nächsten ganzen Zahl, int rundet ab, die
Divisionen sind exakt). Der letzte Ausdruck geht in Assembler so:
  ldi  tmp,100
  mul  A,tmp
  subi r0,lo8(-(128))
  sbci r1,hi8(-(128))

Das Ergebnis steht in r1. Damit kommen tatsächlich Werte in [0..100]
heraus.

Autor: HHe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,


vielen Dank für die vielen Antworten. Als ich selbst noch einmal darüber 
nachdachte kam ich auch (fast ;) ) auf die Methode von yalu, die mir 
sehr gelegen erscheint.
Die Methode von Michael Appelt (micha54) ist natürlich das Optimum in 
Sachen Geschwindigkeit (da ich die den Wert tatsächlich als ASCII 
ausgeben will), aber ich fürchte für so eine Tabelle reicht der 
Flash-Speicher schon nicht mehr aus.



Vielen Dank!

Autor: HHe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach noch ein Nachtrag: Wieso eigentlich durch 256 teilen? Ja, man hat 
256 mögliche diskrete Messwerte, die wir aber als Zahlen 0-255 
interpretieren. Also gilt immer Messwert/256 < 1.
Oder anders: wir rechnen ja sozusagen im Ring Z/256Z, also 256=0.
Das verstehe ich noch nicht.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@HHe (Gast)

>Sachen Geschwindigkeit (da ich die den Wert tatsächlich als ASCII
>ausgeben will),

Und deswegen so ein Aufstand? Wieviel Millionen Messwerte willst du denn 
umrechnen? Selbst die schlechteste Variante schafft locker 1000 
Zeichen/s, mehr als jeder Mensch lesen kann.

>aber ich fürchte für so eine Tabelle reicht der
>Flash-Speicher schon nicht mehr aus.

Vollkommen unnötig. Viel Wind um nichts.

MFG
Falk

Autor: HHe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja schon klar, dass der AVR sehr viele Zeichen / s schafft, aber 
vielleicht hat er ja auch noch andere zeitkritische sachen zu tun......

Viel interessanter wäre es, wenn du mir meine letzte Frage bezüglich des 
durch 256 teilens beantworten könntest.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
HHe wrote:
> Ach noch ein Nachtrag: Wieso eigentlich durch 256 teilen?
Weil ein 8-Bit-Analog-Digital-Wandler die Referenzspannung in 256 (und 
nicht 255) gleiche Teile unterteilt. Bedingt durch das Prinzip können 
nur Werte von 0 bis "100% VREF - 1 LSB" ausgegeben werden, also Werte 
von 0 bis 255. Dividieren muss man trotzdem durch 256, weil das der 
eigentliche 100%-Wert ist, der allerdings nicht darstellbar ist. Warum 
das so ist, wird klar, wenn man sich Aufbau und Funktionsweise eines ADC 
mal genauer ansieht.

Im Prinzip gibt der ADC ja nicht Zahlenwerte für konkrete Spannungswerte 
aus, sondern für Spannungsintervalle . Die ADC-Ausgabe 0 bedeutet 
lediglich, dass der Spannungswert am Eingang kleiner ist als die 
kleinste auflösbare Einheit (die bei einem 8-Bit-ADC eben VREF/256 ist). 
Ein Wert von 255 bedeutet, dass die Spannung größer (*) als 255 * 1 
LSB ist. Ein Wert von 122 sagt aus, dass die Spannung größer als 122 * 
1 LSB, jedoch kleiner als 123 * 1 LSB ist.

(*) Bei exakter Gleichheit ist das Ergebnis nicht definiert, es wird 
dann entweder der höhere oder der niedrigere Wert ausgegeben. Das liegt 
daran, dass ein Komparator (wie er am Eingang des ADC vorliegt) nur 
größer/kleiner unterscheiden kann, während der Zustand seines Ausgangs 
bei Gleichheit der Eingänge undefiniert ist.

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wieviele Zahlen kannst du abzählen im Bereich 0 bis 255 ?
Damit's einfacher wird: wieviele Zahlen kannst du abzählen im Bereich 0 
bis 9 ?

Übrigens benötigt die Tabellen Methode nicht viel weiniger an Rechenzeit 
wie die Methode von Yalu, besonders wenn man das Runden weg lässt.

Gruß Hagen

Autor: HHe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach so! Das ist also auch so gedacht, dass man niemals volle 
Referenzspannung messen wird. Jetzt verstehe ich, vielen Dank!

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hagen Re wrote:
> wieviele Zahlen kannst du abzählen im Bereich 0 bis 255 ?
> Damit's einfacher wird: wieviele Zahlen kannst du abzählen im Bereich 0
> bis 9 ?
Hat damit aber nichts zu tun. Das mit den 256 Zuständen (0...255) hat er 
ja selbst schon geschrieben.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
HHe wrote:
> Ach so! Das ist also auch so gedacht, dass man niemals volle
> Referenzspannung messen wird. Jetzt verstehe ich, vielen Dank!
Ich hab es noch ein bisschen ergänzt, damit es klarer wird. Siehe oben.

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, wenn es aber 256 Zustände, also machbare Meßwerte gibt, warum dann 
durch 255 teilen ? Es hat schon was mit der Abzählbarkeit zu tun, das 
ist nämlich identisch zur Quantisierung des ADCs, und ein ADC 
quantisiert einen analogen Wert in digitale, abzählbare Mengen. Eine 
Menge aus den Elementen 0 bis 255 hat Cardinalität 256.

Gruß Hagen

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Autor: Reinhard Richter (reirawb)
*201/512

ja, so würde ich es auch machen,
 - ein mul
 - ein shift des High-Bytes


max-Wert: 255*201/512=100,107421875

evtl. noch beser mit Auf-Runden:
(ADC*201 + 256)/512, also
 - mul ADC,201
 - inc High-Byte
 - shr High-Byte
 - Ausgabe High-Byte


Matthias Tabelle hat aber auch einen gewissen Reiz der Einfachheit. 
Zuerst störte mich das 256-malige Mitspeichern des %, aber: dadurch ist 
die Berechnung des Index leichter wg. Länge=4 (2 shifts)


Ich habe mal eine Routine entwickelt und hier im Forum gepostet, die die 
Umrechnung einer beliebigen Spannung/Wertes (u.a. auch 100%) UND die 
Ausgabe in ASCII in einem Rutsch durchgeführt wurde. Bloß finde ich sie 
gerade nicht mehr...

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Johannes M.

wir beide meinen das Gleiche, du im technischen ich im mathematischen 
Sinne.

Gruß Hagen

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Bloß finde ich sie gerade nicht mehr...

Ich auch, und ich habe sie wiedergefunden:
Beitrag "Re: Wie Berechnung in AVR Assembler möglichst schnell?"

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.