Hallo,
ich möchte über ein Display einige, im MC gespeicherte, Zahlen
ausgeben.
Diese sind aber im 2-stelligen Hex-Format (also 8bit).
Weiß jemand, wie ich diese Hex-Zahlen in jeweils 3 ASCII-Zeichen
umwandeln kann?
Gibt eis da einen Trick, oder brauche ich da eine Tabelle?
Das Thema war hundertmal da.
Es gibt fertigen Code für wohl jede Programmiersprache auf der Welt (Du
verrätst ja nicht, welche Sprache auf welchem Gerät Du einsetzt).
Im aller-allerschlimmsten Fall mußt Du Dein Gehirn benutzen.
Denkansatz: beginne mit dem ASCII-Zeichen für null ($30). Solange Du
von der Zahl hundert abziehen kannst, tu es und erhöhe jedesmal den
ASCII-Wert. Wenn Deine Zahl dann unter hundert ist, kannst Du den
ersten Wert rausschreiben und beginnst wieder mit $30, diesmal mit den
Zehnern. Usw.
Geht evtl. auch noch einfacher, aber ich habe es in C mal so gemacht:
die Variable enthält die Zahl 145.
1. 145%10=5 -> einer
2. 145/10=14
3. 14%10=4 -> zehner
4: 14/10=1 -> hundetrter
Die Ergebnisse mit einem Offset beaufschlagen, der sich nach dem
Character-ROM des Displays richtet.
MW
Die Variante mit der Division klingt eigentlich recht einfach.
Allerdings programmiere ich mit dem AVR-Assembler.
Ich muss mal schauchen, obs da die Möglichkeit zur Modulo-Division
gibt...
gibt auch noch andere Varianten, z.B. für jedes gesetzte Bit des
Quellregisters den entspr. dezimalen Wert (1,2,4,8,16,usw.) auf
Zielregister addieren und nach jeder Addition eine Dezimalkorrektur
("DAA" oder so) ausführen.
Das ergibt gepacktes BCD, muss man noch entpacken und jeweils 30h
dazuzählen, dann ists ASCII.
Dieter
Hier ein kleines Progrämmchen!
void itohexa(unsigned int n, unsigned char * s) // wandelt eine long
Zahl in einen 4 Byte grossen HEX-String
{
unsigned int help,z;
help = n;
for (z=3;z>0;z--)
{
if ((help & 0x000F) > 9) s[z] = (help & 0x000F) + 55;
else s[z] = (help & 0x000F) + '0';
help = help >> 4;
}
s[4] = 0;
}
Gruß
Mike
@Michael: Schön in Hochsprachen, wenn man viel Zeit hat. Aber Division
und Modulo gibt es auf einem AVR nicht geschenkt.
@Jens: Hast Du den Eindruck, daß Bernd das hinbekommt, wenn ihm schon
subtrahieren zu schwierig ist?
@dds5: Wetten, daß das langsamer ist und mehr Takte braucht?
@Mike: Schön, war aber nicht verlangt.
@Bernd: Gerade wenn Du Assembler schreibst, vertraue mir: das
beschriebene Verfahren ist das einfachste. Ehrlich.
Aus dem Stegreif; die Zahl stehe in r16:
ldi r17, $30 - 1 ; ein inc kommt immer!
Hunderterschleife:
inc r17
subi r16, 100
brpl Hunderterschleife
subi r16, -100 ; weil einmal zuviel abgezogen
ldi r18, $30 - 1 ; ein inc kommt immer!
Zehnerschleife:
inc r18
subi r16, 10
brpl Zehnerschleife
ldi r18, $30 + 10 ; weil 10 zuviel von r16 abgezogen
add r18, r16
Ich hoffe, das stimmt alles; das Ergebnis steht dann in r17,r18,r19. 11
Befehle. Ich bezweifle, daß man das mit Modulo oder anderen Methoden
hinbekommt. Und schneller sollte es auch sein.
Im übrigen meine Bewunderung für ein Mega128-Projekt in Assembler!
@Philipp
Ich hab sowas für 16Bit auf PIC18F in Assembler realisiert.
Ergibt knapp doppelt so viel Code wie die Subtraktion in Schleifen, ist
aber worst case (65535) rund doppelt so schnell.
Dieter
Hm. Worst case für meine Schleife sollte bei 16 Bit übrigens 59999 sein.
Und dann ist noch die Frage, ob Durchschnitt (für max. Durchsatz) oder
Maximum (für real time scheduler!) wichtiger sind.
Ich kann es mir immer noch nicht richtig vorstellen, immerhin muß nach
jeder von bis zu 15 Additionen auf bis zu 5 Stellen auf Dezimalüberlauf
getestet werden.
Kannst Du auch AVR-Assembler? Dann steht meine Wette, daß Dein
Verfahren nicht mithält, selbst mit doppelt soviel Code. Auch nicht bei
16 Bit! Schlägst Du ein?
Gruß, Philipp.
@Philipp
AVR-Asm kenn ich leider nicht, hab bisher nur mit (in dieser
Reihenfolge) Z80, µPD75108 (4Bit!), 8051, PIC16C und jetzt PIC18F
gearbeitet. Vieles kann man trotzdem erkennen und teilweise auch
verstehen, aber ist schon blöd dass jeder andere Mnemonics benutzt weil
fast alle Markenschutz haben.
Wette verlier ich wahrscheinlich, weil
1. Ergebnis liegt nicht in ASCII sondern 3 Byte gepackt BCD vor.
2. Es ist nur mit den Standard AppNote Routinen verglichen.
@Peter
Interessante Technik, alternierendes addieren / subtrahieren.
Das sieht wirklich nicht mehr unterbietbar aus.
Den Tippfehler in Zeile 22 bügelt der Profi selbst aus und verliert
kein Wort darüber (bin halt kein Profi), aber welchen numerischen Wert
hat der Ausdruck in Z 45 "-'0'" oder ist da nur das "-" zu viel?
Dieter
Stimmt, mit dem abwechselnden Addieren spart man sich noch jeweils das
zurücknehmen der überschüssigen Subtraktion: noch drei Befehle gespart.
Clever!
Das -'0' ist richtig, entspricht dem -100 in meinem Code, ist aber
nur verständlich, wenn man AVR-Assembler kennt: es gibt kein 'ADDI',
also 1-Byte-Konstantenaddition, sondern nur SUBI. Um '0' zu addieren,
muß man also -'0' subtrahieren. (Verstehen tue ich das Fehlen von ADDI
übrigens nicht, schließlich braucht man keinen eigenen Befehl im µC,
sondern nur eine Übersetzung durch den Assembler.)