Konverze z hexadecimální soustavy do ASCII |
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í,...
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.
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
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
;
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.
POPIS Web51 | NOVINKY | FAQ | OBJEDNÁVKA | DOWNLOAD |
(c)Copyright 2000, 2001, HW server & Radek Benedikt
Web51@HW.cz, Web51.HW.cz Final applications of the Web51 : www.HWgroup.cz |