Hallo!
Ich hoffe ihr könnt mir ein wenig auf die Sprünge helfen.
Also, ich lese die die 11 Bit breiten Daten des Digitalen
Temperatursensors TsicXXX in meinen Mega8 ein.
Diese liegen dann verteilt in 2 Registern sozusagen als Hexwert.
Jetzt möchte ich die Temperatur aber mit einer 3-Stelligen
7-Segment-Anzeige
ausgeben. (2 Stellen und eine nach den Komma)
Da zu muss ich aber erst den Wert der in den 2 Registern liegt
umrechnen:
(Wert / 2047 * 200) - 50
Mal und Minus wären ja kein Problem
nur das Dividieren...
das Ergebnis soll dann in 3 Registern stehen:
z.B.:
Register 16 (Wert für 10er)
Register 17 (Wert für 1er)
Register 18 (Wert für Nachkommastelle)
nur wie mache ich das in Assembler?
Ich hoffe Ihr könnt mir da helfen
Grüße, Matze
Tipp, falls es in den Links nicht schon erwähnt wurde: Dividieren und
multiplizieren durch 2er-Potenzen macht man mit einem Shift! Divisonen
durch Konstanten kann man auch als Fixkommamultiplikation mit dem
Kehrwert implementieren!
>Tipp, falls es in den Links nicht schon erwähnt wurde: Dividieren und>multiplizieren durch 2er-Potenzen macht man mit einem Shift! Divisonen>durch Konstanten kann man auch als Fixkommamultiplikation mit dem>Kehrwert implementieren!
Gibt es dafür Beispiele?
Hi nochmal!
Ich versuchs einfach nochmal hier...
ich weis nimmer was ich noch machen soll...
kriegs einfach ned hin...
gibts denn irgendjemanden der mir den fertigen ASM-Code
funktionsfähig geben kann oder jemanden der mir das in ASM Programmieren
kann? Evtl. auch gegen eine kleine Aufwandsentschädigung...
Grüße Matze
Matze0001 schrieb:> umrechnen:> (Wert / 2047 * 200) - 50> das Ergebnis soll dann in 3 Registern stehen:> z.B.:> Register 16 (Wert für 10er)> Register 17 (Wert für 1er)> Register 18 (Wert für Nachkommastelle)
Die einfachste Möglichkeit: bastle in Excel o.ä. eine Lookup-Tabelle und
binde sie ins Programm ein.
In der Tabelle stehen für jeden der möglichen Werte (ich nehme an:
0...2047) die zugehörigen Zehntel, Einer und Zehner. Mit etwas
Nachdenken reicht für die Tabelle ein Byte je Eintrag (Zehntel und
Einer), für Zehner und Vorzeichen musst Du dann eine zweite spendieren.
Oder Du nimmst zwei Byte je Eintrag, dann ist es ganz einfach.
Die zweiteinfachste Möglichkeit: Du probierst einfach alle Werte für die
Anzeige vom kleinsten zum größten durch, so viele sind es ja nicht (2000
Stück, wenn ich mich nicht irre). Sobald der Anzeigewert größer ist als
der gemessene, hast Du den richtigen Wert gefunden. Anders formuliert
(Pseudocode):
var zehner, einer, zehntel
zehner = -5; einer = 0; zehntel = 0;
loop:
wenn (200 * messwert - 50 < 20470*zehner + 2047*einer + 205*zehntel)
dann breche Schleife ab, Wert gefunden
zehntel = zehntel + 1
einer = einer + 1
zehner = zehner + 1
end loop
(Du musst natürlich drei Schleifen verschachteln und noch ein bisschen
Aufwand für die negativen Zahlen treiben).
Die Rechnerei dauert ein paar Millisekunden, aber das ist ja egal, so
schnell kannst Du das Display eh nicht ablesen.
Die komplizierteste Möglichkeit: vorwärts rechnen, wie von Dir
vorgeschlagen.
(Wert / 2047) zu rechnen ist diffizil, einfach ist: (Wert / 2048) =
(Wert >> 11). >> ist der Rechtsshiftoperator, guck mal in Deinem
C-Handbuch nach. In Assembler geht das natürlich auch.
Bitte erst multiplizieren, dann den Rechtsshift machen, vorher
überlegen, welche Wortbreite Du brauchst. Mit ((Wert * 25) >> 8) - 50
geht es übrigens auch. Wenn Du es andersherum machst, verlierst Du
Genauigkeit.
Anschließend musst Du das Ergebnis noch in Zehner, Einer und Zehntel
zerlegen, das ist tendenziell die schwierigere Aufgabe.
Jürgen W. schrieb:> ;t=TSic_Wert*200 /2048-50 (die 2047 um 1 erhöht um besser rechnen zu können)
Je nachdem, welcher Temperaturbereich gemessen werden soll, kann man
auch 'TSic_Wert' noch um eins erhöhen, dann ist der max. Fehler (~0.1K)
bei -50°C.
Danke für die ganzen Vorschläge! Echt super! Aber ich denke ich werde
das mal mit der Tabelle ausprobieren...
is halt ein "wenig" Schreibarbeit... :(
Wie mache ich dann eine 3 Byte breite Tabelle? :)
geht das überhaupt?
Grüße Matze
Na dann mal viel Spass ;-)
Bei 3 Bytes pro Tabelleneintrag sind das 6144 Bytes (6kb), Hoffentlich
hast du dann noch genügend Platz für den Code.
Was gefällt dir an meinem Code nicht ? Sind gerade mal 14 Befehle.
Matze0001 schrieb:> hab den code schon mal ausprobiert... nur was kommt da genau raus? Was> sind das dann für Werte?
In temp3 das Highbyte des Ergebnisses, in temp2 das Lowbyte.
Wobei der Wert das 10-fache der Temperatur ist.
Bei 22 Grad kriegst du also 220 als Ergebnis, bei 38.7 Grad
dementsprechend 387. Auf die Art hat man 1 'Kommastelle', obwohl man gar
nicht mit Kommazahlen rechnet. Einfach während der Ausgabe auf einem LCD
vor die letzte Stelle ein Komma 'einschmuggeln' und schon sieht es so
aus als ob. Bei deinen 7-Segment LED-Anzeigen steht das Komma ja schon
dort (auf der Frontplatte), da brauchst du also gar nichts tun :_)
@Matze0001
und wenn du jetzt 3 Werte einzel brauchst, dann musst du das Ergebnis
noch mal durch 10 teilen, der Rest ist dann die Komma-Stelle. Das
ganzzahlige Ergebnis teilst du wieder durch 10, womit der Rest dann die
Einer-Stelle und das ganzzahlige Ergebnis die Zehner-Stelle ergibt.
Sascha
ahh, jetzt klickts langsam! Vielen lieben dank euch!
Wie kann ich euch ein Bier ausgeben? :)
Ok und wenn ichs jetzt sozusagen durch 2047 teilen will damits genauer
wird, dann wirds wieder zu kompliziert oder? (wär aber jetzt auch ned so
wichtig bin froh das es jetzt so funktioniert)
Und wie teil ich das jetzt noch durch 10? Und dann nochmal?
damit ich die Zehner, Einer und die Nachkommastelle in einzelnen
Registern hab?
Wenn ihr mir da noch helfen könntet wärs perfekt
Wär echt super
sorry das ich mich da so anstelle..
Grüße Matze
Matze0001 schrieb:> ahh, jetzt klickts langsam! Vielen lieben dank euch!>> Wie kann ich euch ein Bier ausgeben? :)>> Ok und wenn ichs jetzt sozusagen durch 2047 teilen will damits genauer> wird, dann wirds wieder zu kompliziert oder? (wär aber jetzt auch ned so> wichtig bin froh das es jetzt so funktioniert)
Ja wird es.
Allerdings solltest du dir mal ausrechnen, wieviel denn dieses 'genauer'
überhaupt ist.
> Und wie teil ich das jetzt noch durch 10? Und dann nochmal?> damit ich die Zehner, Einer und die Nachkommastelle in einzelnen> Registern hab?
zb indem man in einer Schleife 10 abzieht, solange bis die Zahl negativ
wird. Gleichzeitig zählt man mit wie oft man abgezogen hat.
Bei dir sind das natürlich erst mal die Hunderter. Du ziehst also in
einer Schleife jeweils 100 ab und zählst mit oft das gut ging. Die
Anzahl ist die Anzahl der Hunderter in der Zahl oder eben vulgo: das
Ergebnis von Zahl dividiert durch 100.
Zum Ergebnis (das ja jetzt negativ ist, schnell wieder 100 dazu, und das
ganze Spielchen mit 10. Wie oft kann man 10 abziehen, ehe die Zahl
negativ wird. Damit hast du die Zehner. Und das was übrig bleibt (10
dazu zählen um wieder positiv zu werden), sind dann die Einer.
387
+++
0
387 - 100 = 287 1
287 - 100 = 187 2
187 - 100 = 87 3
87 - 100 = -13 Ooops |
+------> 3 Hunderter
-13 + 100 = 87
0
87 - 10 = 77 1
77 - 10 = 67 2
67 - 10 = 57 3
57 - 10 = 47 4
47 - 10 = 37 5
37 - 10 = 27 6
27 - 10 = 17 7
17 - 10 = 7 8
7 - 10 = -3 Oops |
+------> 8 Zehner
-3 + 10 = 7 -------> und 7 Einer
das geht bei Zahlen in dieser Größenordnung schneller als richtige
Divisionen. Und ist auch leichter implementiert.
ok, das bekomm ich hin! Vielen dank!
Jetzt musst ich dann nur noch eins wissen... Wie kann ich jetzt die
beiden Register mit 100 subtrahieren
also 16bit - 8bit? :)
Matze0001 schrieb:> ok, das bekomm ich hin! Vielen dank!> Jetzt musst ich dann nur noch eins wissen... Wie kann ich jetzt die> beiden Register mit 100 subtrahieren> also 16bit - 8bit? :)
Falsch
16 Bit - 16 Bit
und das hast du im Code von Jürgen schon gesehen.
Ich zitiere
1
subi temp2,low(500) ;500 (50.0) abziehen
2
sbci temp3,high(500)
:-) Code studieren! In jedem Code verbergen sich Schätze. Und nirgends
ist das extensive Codestudium so wertvoll wie in Assembler. Bis man die
Feinheiten von 5 oder 6 Anweisungen komplett in allen Details verstanden
hat, das kann auch schon mal Stunden dauern. Aber dann lehnt man sich
zurück und sagt: "Genial! Das hat was."
Jetzt hab ich doch noch was :/
ich subtrahiere und subtrahiere usw.
und wie kann ich dann auswerten das die letzte Subtraktion nicht mehr in
Ordnung war?
Grüße Matze
Hi
>es gibt ein Bit im Statusregister für negative Ergebnisse oder man>vergleicht ob 87 größer als 100 ist.
Da würde ich vorsichtig sein. Das N-Flag representiert nur Bit 7 vom
Ergebnis.
$01-$02 -> $FF -> N=1 negativ
$01-$A0 -> $61 -> N=0 positiv
MfG Spess
Hi
>dann sorry für die Fehlinformation, musst es dann eben doch über einen>vergleich lösen.
Nein. Bei einem 'negativen Überlauf' wird das Carry-Flag gesetzt. Nur
die Auswertung des N-Flags ist allgemein dafür nicht sinnvoll.
MfG Spess
ja genau so wars, wusste noch das ich das mal über die Statusbits nach
dem Abziehen gemacht habe.
Matze001: Ansonsten einfach mal in der Befehlsübersicht nachschauen was
nach dem subtrahieren passiert.
Ah ich habs!
mit "brmi"
am Ende der Subtraktion
Wenn Temp3 ins Minus geht dann weiterspringen und zu temp2 100 dazu
Danke euch allen nochmal Vielmals!
Grüße Matze
nur da ist doch das Problem, das eben das Carry-Flag bei der Subtraktion
öffters mal gesetzt bzw. gelöscht ist bis die Berechnung fertig ist...
und mit "brmi"
wird nur weitergesprungen wenn das Ergebnis am Ende der Subtraktion
negativ ist
Hi
>nur da ist doch das Problem, das eben das Carry-Flag bei der Subtraktion>öffters mal gesetzt bzw. gelöscht ist bis die Berechnung fertig ist...
Aber am Ende einer Rechnung stimmt es. Durch 'sbc'/'sbci' wird der
Übertrag der vorherigen Rechnung einbezogen.
MfG Spess
Hi
>jetzt wenn se aber ins minus geht stimmts nicht mehr... :(
Wieso? Ist halt eine negative Zahl. Um den Wert richtig darzustellen
musst du das 2er-Komplement bilden. Bei einem Byte geht da mit 'neg'.
Bei grösseren Zahlen so:
ja, aber ich rechne ja mit den Code von Jürgen W.
mit deinen Code komm ich ned so richtig klar, weils immer nur
Ausschnitte sind und nicht der ganze
da ist dann wieder ein rcall irgendwo anders hin drin usw.
kann ja ned hellsehen wo des dann hin geht...
da komm ich ned mit klar... :(
Sorry ned böse gmeint
Hi
>ja, aber ich rechne ja mit den Code von Jürgen W.
Na und. Da bekommst das Ergebnis in 2 Registern und von denen musst du
bei negativen Ergebnis das 2er-Komplement bilden. Die Routine 'neg16'
zeigt dir wie man das bei zwei Registern macht. Wenn du nicht mal in der
Lage bist, das auf deine Register umzusetzen tut es mir ehrlich leid.
MfG Spess
ok, jetzt komm ich klar damit :) vielen lieben Dank!
sorry, programmier ja noch nicht so lange..
jetzt hab ich aber noch was... :)
wie stell ich jetzt am besten fest das ich im Minusbereich bin damit ich
dann den Sprung zum 2er-Komplement bilden machen kann?
Hi
>wie stell ich jetzt am besten fest das ich im Minusbereich bin damit ich>dann den Sprung zum 2er-Komplement bilden machen kann?
Bei einer negativen Zahl ist das höchstwertigste Bit gesetzt. Bei
Operationen, die die Flags beeinflussen wird in diesem Fall das N-Flag
(negative) gesetzt. Also hast du verschiedene Möglichkeiten:
subi temp2,low(500) ;500 (50.0) abziehen
sbci temp3,high(500)
brmi/brpl ....
tst temp3
brmi/brpl ....
sbrc/sbrs temp3,7
rjmp ....
MfG Spess