Konverze z hexadecimální soustavy do ASCII

GNU general public licence  Obsah  model procesorů řady x51 (8051, 8052, ...)
Článek popisuje konverzí z hexadecimální soustavy do ASCII, přičemž se snaží najít optimální optimální algoritmus podle podmínek řešení.

Programujete-li jednočipové počítače, tak dříve nebo později narazíte na jeden ze základních problémů a tou je komunikace s uživatelem. Pominu-li takové problémy, jakými je nutnost řešení naprogramování, či hardwarové ošetření této komunikace na úrovni čtení dat z klávesnice, výpis znaků na displej, dostáváme se k problémům převodů znaků mezi jednotlivými soustavami desítková/hexadecimální,...

Varianta 1 - převod tabulkou

I přes zdánlivou primitivnost je následující varianta převodu často používána, a to nejen pro její jednoduchost. Po jednoduché optimalizaci totiž umožň;uje dosáhnout slušnou rychlost převodu, nezávislou navíc na tom jaké převádíme číslo. Druhou výhodou tohoto řešení je možnost převodu i do trochu jiného číselného vyjádření než je obligátní 0123456789ABCDEF, např. do číselného vyjádření zavedeného v měřicí technice firmou Hewlett Packard pro měření metodami příznakové analýzy, kdy je pro vyjádření použita řada 0123456789ACFHPU, lépe čitelná na sedmisegmentových dislejích.

Varianta převodu tabulkou zhruba odpovídá následujícímu algoritmu zapsanému v "C" like jazyku:

const code char   HEXstring[16] = "0123456789ABCDEF";

print_hex (BYTE num)
{
   put_nibble (num >> 4);
   put_nibble (num);


put_nibble (BYTE nibble)
{
   char_from_Acc (HEXstring[nibble & 0x0F]);
}

V ASM51 je možno tento algoritmus převést na následující kód:

print_hex1:
   PUSH   ACC           ;uloz hodnotu pro tisk LSB (nizsi) casti cisla
   SWAP   A             ;presun MSB (vyssi) cast cisla z pozice bitu 7..4 do pozice 3..0
   ACALL  put_nibble1   ;vytiskni MSB cast cisla
   POP    ACC           ;obnov hodnotu
   ACALL  put_nibble1   ;vytiskni LSB cast cisla
   RET
;
put_nibble1:
   ANL    A,#0FH        ;ber v uvahu jen LSB cast cisla
   ADD    A,#HEXstring1-mvcoff1 ;pricti offset zacatku tabulky
   MOVC   A,@A+PC       ;a pouzij jej jako index k vybrani hodnoty v ASCII
mvcoff1:
   ACALL  char_from_Acc ;vytiskni hodnotu z tabulky
   RET
HEXstring1:
   DB    '0123456789ABCDEF'
;
; delka prikladu 34 byte, doba vykonavani 31 µs pri 12 MHz
;

Předchozí variantu převodu je možno, eliminací nadbytečných dvojic instrukcí CALL - RETURN  a jejich nahrazením instrukcemi JMP přepsat do následujícího tvaru:

print_hex2:
   PUSH   ACC
   SWAP   A
   ACALL  put_nibble2
   POP    ACC
;
put_nibble2:
   ANL    A,#0FH
   ADD    A,#HEXstring2-mvcoff2
   MOVC   A,@A+PC
mvcoff2:
   AJMP   char_from_Acc
HEXstring2:
   DB     '0123456789ABCDEF' ;'standart' hex string
;  DB     '0123456789ACFHPU' ;signature analysis

;
; delka prikladu 30 byte, doba vykonavani 23 µs pri 12 MHz
;

Jak je vidět, už pouhá eliminace nadbytečných volání procedur zrychlí proceduru z 31 na 23 us, při současném zkrácení kódu o 4 byte. Potřebujeme-li zvýšit rychlost o dalších pár us, nezbývá už nic jiného než eliminovat volání put_nibble, přepsáním (rozvinutím) této procedury přímo do kódu na místa, kde byla volána (v překladačích vyšších jazyků je takovéto rozvinutí nazýváno termínem "inline macro").

print_hex3:
   PUSH   ACC
   SWAP   A
   ANL    A,#0FH
   ADD    A,#HEXstring3-mvcoff3a
   MOVC   A,@A+PC
mvcoff3a:
   ACALL  char_from_Acc
   POP    ACC
   ANL    A,#0FH
   ADD    A,#HEXstring3-mvcoff3b
   MOVC   A,@A+PC
mvcoff3b:
   AJMP   char_from_Acc
HEXstring3:
   DB     '0123456789ABCDEF' ;'standart' hex string
;  DB     '0123456789ACFHPU' ;signature analysis

;
; delka prikladu 35 byte, doba vykonavani 21 µs pri 12 MHz
;

Rozvinutí vnořených procedur, jak je vidět přineslo zrychlení o další 2 us, za cenu prodloužení výsledného kódu o 5 byte.

Varianta 2 - převod pomocí porovnání

Tato varianta bývá často používána a patří k poměrně přehledným a pochopitelným.

Varianta převodu pomocí porovnání zhruba odpovídá následujícímu algoritmu zapsanému v "C" like jazyku:

print_hex (BYTE num)
{
   put_nibble (num >> 4);
   put_nibble (num);


put_nibble (BYTE nibble)
{
   nibble = nibble & 0x0F;        //Cckar by jiste napsal nibble &= 0x0F
   if (nibble > 10) nibble = nibble + 'A' - ('9' + 1);
   char_from_Acc (nibble + '0');
}

V ASM51 je možno tento algoritmus převést na následující kód:

print_hex4:
   PUSH   ACC
   SWAP   A
   ACALL  put_nibble4
   POP    ACC
put_nibble4:
   ANL    A, #0Fh
   ADD    A, #-10     ;procesor neumi prime porovnani s konstantou
                      ;proto pouzijeme pomocne odecteni
   JNC    phex_n
   ADD    A, #7
phex_n:
   ADD    A, #'0'+10  ;zde je pricitano +10, protoze by bylo neefektivni
                      ;uschovavat puvodni hodnotu pred porovnanim >10
                      ;a vracet ji zpet
   AJMP   char_from_Acc

;
; delka prikladu 19 byte, doba vykonavani 25,75 µs pri 12 MHz
;
   I tento algoritmus by bylo možno dále vylepšovat, např. nahrazením
   ADD   A,#7
dvojicí
   ADD   A,#'A'+10
   AJMP  char_from_Acc

Varianta 3 - převod pomocí instrukcí DAA

Tato varianta je jednoduchá, stručná a elegantní, nicméně nepatří k jednoduše pochopitelným.

print_hex5:
   PUSH   ACC
   SWAP   A
   ACALL  put_nibble5
   POP    ACC
put_nibble5:
   ANL    A,#0Fh
   ADD    A,#90h  ;prevede cislo z rozsahu 00h..0Fh na 90h..9Fh
   DA     A       ;pro cisla 90h..99h neudela nic
                  ;pro cisla 9Ah..9Fh 
                  ; 1) pricte 06h cimz je prevede na A0h..A5h
                  ; 2) k vysledku pricte 60h cimz je prevede na 00h..05h a nastavi Carry
   ADDC   A,#40h  ;prevede cislo z rozsahu 90h..99h na D0h..D9h + Carry
                  ;prevede cislo z rozsahu 00..05h(+Carry) na 41h..45h
   DA     A       ;pro cisla D0h..D9h(+Carry)pricte 60h cimz je prevede na 30h..39h
                  ;pro cisla 41h..45h neudela nic
   AJMP   char_from_Acc
;
; delka prikladu 17 byte, doba vykonavani 25 µs pri 12 MHz
;
char_from_Acc:
   RET   ;dummy procedure

;

Shrnutí

Každá z variant má své pro i proti, jak je vidět i z následující tabulky:
  délka kódu
(byte)
doba vykonávání
(µs při 12 MHz)
Poznámka
převod tabulkou verze 1 34 31  
převod tabulkou verze 2 30 23 Univerzální
převod tabulkou verze 3 35 21 Nejrychlejší
převod pomocí porovnání 19 25,75  
převod pomocí DAA 17 25 Nejmenší
Poznámka: Doba vykonávání je průměrem pro všech 256 možných hodnot.




Sponzored by LPhard Ltd. Graphics by GIMP Created by EasyPad

(c)Copyright 2000, 2001, HW server & Radek Benedikt
Web51@HW.cz, Web51.HW.cz

Final applications of the Web51 : www.HWgroup.cz
GNU general public licence  Obsah  model procesorů řady x51 (8051, 8052, ...)