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
@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
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
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
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"
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:
1 | ldi tmp,100 |
2 | mul A,tmp |
3 | subi r0,lo8(-(128)) |
4 | sbci r1,hi8(-(128)) |
Das Ergebnis steht in r1. Damit kommen tatsächlich Werte in [0..100] heraus.
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!
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.
@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
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.
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.
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
Ach so! Das ist also auch so gedacht, dass man niemals volle Referenzspannung messen wird. Jetzt verstehe ich, vielen Dank!
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.
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.
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: 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...
@Johannes M. wir beide meinen das Gleiche, du im technischen ich im mathematischen Sinne. Gruß Hagen
>Bloß finde ich sie gerade nicht mehr... Ich auch, und ich habe sie wiedergefunden: Beitrag "Re: Wie Berechnung in AVR Assembler möglichst schnell?"
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.