Zamiana ASCII na HEX - assembler 8051

To forum jest dla wszystkich pasjonatów wiecznie młodych mikrokontrolerów '51. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
Raflles
-
Posty: 77
Rejestracja: 06 sie 2005, 17:15
Lokalizacja: Tychy
Kontakt:

Zamiana ASCII na HEX - assembler 8051

Post autor: Raflles » 12 sie 2006, 17:39

Witam !! Mam pytanko. czy jest jakiś algorytm bądź też sposób na zamianę wartości w ascii na hex ?? Czyli żeby odbierając z portu komputera znaki ascii 3F, czyli 33h 46h procesor odczytał faktyczną wartość, czyli 3Fh. Oczywiście konwersja odbywałaby się po stronie procesorka. Pozdrawiam i proszę o odpowiedź.

Awatar użytkownika
gaweł
Użytkownik
Posty: 651
Rejestracja: 05 kwie 2004, 8:38
Lokalizacja: Białystok
Kontakt:

Re: Zamiana ASCII na HEX - assembler 8051

Post autor: gaweł » 12 sie 2006, 23:28

Raflles pisze:Witam !! Mam pytanko. czy jest jakiś algorytm .....
Oczywiście, że jest. Każdą odebraną cyfrę hex (znakowo ASCII) należy zamienić na wartość binarną, czyli przerobić 33hex (ascii) na 3 (binarnie), 46hex (ascii) na 15 (binarnie). Konwersji dokonujesz 3*16+15=63 (dec) = 3F hex.

tasza
Użytkownik
Posty: 1391
Rejestracja: 21 lut 2005, 15:02

Post autor: tasza » 13 sie 2006, 12:45

Gaweł, a jak przekonwertujesz 'AA'... :?:

Raflles, stanowczo nie mam dziś natchnienia do pisania w asm,
więc tylko opis słowno-muzyczny...

zauważ taką rzecz:
cyfry '0'...'9' mają kody ASCII od 30H do 39H
literki 'A'...'F' mają kody ASCII od 41H do 46H (zauważ - to duże litery, małe mają inne kody)

przyjmijmy że w rejestrze R1 jest literka 'E', w rejestrze R0 jest literka '5'
czyli konwertujemy napis 'E5'

przyjmijmy więc, że starsza połówka bajtu jest w R1,
młodsza w R0 a z tego ma nam wyjśc 0E5H (czyli po C-owemu 0xE5 )

bierzesz R1,
sprawdzasz, czy R1 > 39H
jeżeli nie, to od zawartości R1 odejmujesz 30H czyli #'0'
w ten sposób uzyskasz wartości 0...9
jeżeli jest większe - od wartości R1 odejmujesz 41H czyli #'A'
w ten sposób uzyskasz 0...5 i do tego wyniku nalezy dodać 0AH (czyli dziesięć)
aby uzyskać 0AH...0FH
w taki oto sposób masz przeliczoną starszą połówkę bajtu,
choć wynik jest składowany na czterech młodszych bitach...

to samo robisz dla R0

na koniec należy poskładać wynik w całość, czyli przesunąc bitowo o 4 w lewo wynik z R1
(lub wykonać swap) ustawią się starsze cztery bity, młodsze należy wyzerować.
tę wartość należy dodać do wartości wyliczonej z R0...i gotowe, o!

:)

tasza

PS.
tu masz tabelkę z kodami ASCII
:arrow: http://www.lookuptables.com/

Awatar użytkownika
gaweł
Użytkownik
Posty: 651
Rejestracja: 05 kwie 2004, 8:38
Lokalizacja: Białystok
Kontakt:

Post autor: gaweł » 13 sie 2006, 13:28

tasza pisze:Gaweł, a jak przekonwertujesz 'AA'... :?:
...
No wiesz księżniczko, Raflles pytał o algorytm, to mu z grubsza podałem. Nie określił poziomu szczegółowości, ale skoro jasno określił problem, to uznałem, że tak oczywiste zamiany kodów znaków na wartości liczbowe sam zrobi. Zrobiłaś to w doskonały sposób, więc: nic już nie ma do dodania. :mrgreen:
Jak Raflles będzie chciał, to gdzieś odszukam tekst odpowiedniego programu, ale może sam spróbuje.

Raflles
-
Posty: 77
Rejestracja: 06 sie 2005, 17:15
Lokalizacja: Tychy
Kontakt:

Post autor: Raflles » 13 sie 2006, 13:35

Dzięki wszystkim za pomoc. Narazie sam spróbuję, a jak polegnę to poproszę o gotowca :) Ale jeżeli się uda to wrzucę tutaj kod bo może się komuś jeszcze przyda. Pozdrawiam !!

[ Dodano: 2006-08-15, 18:42 ]
takie małe pytanko. Czy jest jakaś instrukcja w assemblerze, która porównuje, albo sprawdza relacje ??

tasza
Użytkownik
Posty: 1391
Rejestracja: 21 lut 2005, 15:02

Post autor: tasza » 16 sie 2006, 12:49

Raflles pisze:Czy jest jakaś instrukcja w assemblerze, która porównuje, albo sprawdza relacje
a kto to wie, tyle ich tam jest :roll: .... no sam zobacz:
:arrow: http://www.win.tue.nl/~aeb/comp/8051/set8051.html
a szczególnie:
:arrow: http://www.win.tue.nl/~aeb/comp/8051/se ... tml#51subb ( SUBB )
:arrow: http://www.win.tue.nl/~aeb/comp/8051/set8051.html#51jnc ( JNC )

aha, i może taki kawalątek kodu (pod assembler uC/51 jakby coś.... )

Kod: Zaznacz cały

	.segment start, org $0  
	;
	; jakis_znaczek = '0' ; mniej_lub_rowne_9
	; jakis_znaczek = '8' ; mniej_lub_rowne_9
	; jakis_znaczek = '9' ; mniej_lub_rowne_9
	jakis_znaczek = 'A' ; wiecej_niz_9
	; jakis_znaczek = 'F' ; wiecej_niz_9
	;
	mov A, #jakis_znaczek
	;
	subb A,#3Ah	; '9' + 1 = 3AH
	jnc wiecej_niz_9
	;	
mniej_lub_rowne_9:
	; to sie wykona dla <= '9'
	ljmp mniej_lub_rowne_9
	;
wiecej_niz_9:
	; tu skoczy jak > '9'
	ljmp wiecej_niz_9
no i polecam zadymiastą zabawkę do testowania kodu:
:arrow: https://forum.elportal.pl/viewtopic.php?p=18818#18818 (ESM8051) :idea:

:mrgreen:

tasza

Raflles
-
Posty: 77
Rejestracja: 06 sie 2005, 17:15
Lokalizacja: Tychy
Kontakt:

Post autor: Raflles » 20 sie 2006, 17:44

Witam !!!!

Podaje obiecany kod zamiany ASCII na wartość znaku w HEX. Proszę o krytykę, jeżeli coś dało się zrobić łatwiej i szybciej i żeby zajmowało mniej miejsca. Pozdrawiam !!!!

Kod: Zaznacz cały


;Zamiana ASCII na HEX.

mov A,#38h                      ;wpisujemy do akumulatora znak odebrany przez RS232
setb RS1
mov R0,A
clr RS1  

setb RS1
mov A,R0
clr RS1



zamiana:

sprawdzenie1:                   ;sprawdza, czy liczba hex jest z zakresu 30 - 4F
          
anl A,#0F0h                     ;zerujemy mlodszy polbajt akumulatora
cjne A,#30h,czy40               ;sprawdzamy, czy rozne od 30h, jesli rozny to skok do "dalej"
ljmp rowne30                    ;skok do "dalej"
czy40:
cjne A,#40h,zla_wartosc         ;sprawdzamy czy rozne od 40h,
ljmp rowne40

rowne30:

setb RS1
mov A,R0
clr RS1
subb A,#30h
cjne A,#0Ah,czy0Bh
ljmp zla_wartosc
czy0Bh:
cjne A,#0Bh,czy0Ch
ljmp zla_wartosc
czy0Ch:
cjne A,#0Ch,czy0Dh
ljmp zla_wartosc
czy0Dh:
cjne A,#0Dh,czy0Eh
ljmp zla_wartosc
czy0Eh:
cjne A,#0Eh,czy0Fh
ljmp zla_wartosc
czy0Fh:
cjne A,#0Fh,ile
ljmp zla_wartosc

rowne40:

setb RS1
mov A,R0
clr RS1
subb A,#37h
anl A,#0Fh
cjne A,#00h,czy01h
ljmp zla_wartosc
czy01h:
cjne A,#01h,czy02h
ljmp zla_wartosc
czy02h:
cjne A,#02h,czy03h
ljmp zla_wartosc
czy03h:
cjne A,#03h,czy04h
ljmp zla_wartosc
czy04h:
cjne A,#04h,czy05h
ljmp zla_wartosc
czy05h:
cjne A,#05h,czy06h
ljmp zla_wartosc
czy06h:
cjne A,#06h,czy07h
ljmp zla_wartosc
czy07h:
cjne A,#07h,czy08h
ljmp zla_wartosc
czy08h:
cjne A,#08h,czy09h
ljmp zla_wartosc
czy09h:
cjne A,#09h,ile
ljmp zla_wartosc

ile:

mov P1,A

ljmp ile

zla_wartosc:


ljmp zla_wartosc


PS: Program reaguje tylko na znaki z klawiatury od 0-9 i od A-F. Narazie wersja półbajtowa.

Awatar użytkownika
gaweł
Użytkownik
Posty: 651
Rejestracja: 05 kwie 2004, 8:38
Lokalizacja: Białystok
Kontakt:

Post autor: gaweł » 20 sie 2006, 21:32

Raflles pisze:Witam !!!!
Podaje obiecany kod zamiany ASCII na wartość znaku w HEX. Proszę o krytykę, jeżeli coś dało się zrobić łatwiej i szybciej i żeby zajmowało mniej miejsca. Pozdrawiam !!!!
Widzisz, jak się chce, to da się zrobić. W kwestii krytyki, to jest tak: kryterium jest takie: działa lub nie działa. Jeżeli twój program działa, to jest OK, koniec krytyki.
Natomiast można zastanowić się, czy można to zrobić inaczej. Owszem, można: rozwiązań będzie tyle ilu autorów. Jeżeli każde z nich będzie działać, to jest OK.

Podobnie jak u ciebie: program reaguje tylko na znaki od 0-9 i od A-F i wersja jest bajtowa.
Moja propozycja rozwiązania ma algorytmem znacząco innym od tego jaki zaproponowała ci Tasza:

Kod: Zaznacz cały

$mod51
;
$NODEBUG
$LIST
$OBJECT
;
        CSEG
        org     0
        ljmp    reset
;
;-----------------------------------------------------------------------------
HexTable:db     '0123456789ABCDEF',0
CnvCh:                          ;funkcja CnvCh: parametr wywolania: rej. B-znak
;*****                          ;wynik:  A + wskaznik C ;
        mov     r0,#0           ;
        mov     dptr,#HexTable  ;
CnvCh2: mov     a,r0            ;
        movc    a,@a+dptr       ;
        jz      CnvCh0          ;
        cjne    a,b,CnvCh1      ;
        mov     a,r0            ;
        setb    c               ;
        ret                     ;
CnvCh0: clr     c               ;
        ret                     ;
CnvCh1: inc     r0              ;
        ljmp    CnvCh2          ;
;-----------------------------------------------------------------------------
ConvHex:                        ;funkcja ConvHex: parametr wywolania: rej. r6 i r7 - znaki
;*******                        ;wynik w A + wskaznik C
        mov     b,r6            ;
        lcall   CnvCh           ;
        jnc     CnvHx0          ;
        swap    a               ;
        push    acc             ;
        mov     b,r7            ;
        lcall   CnvCh           ;
        pop     b               ;
        jnc     CnvHx0          ;
        orl     a,b             ;
        setb    c               ;
CnvHx0: ret                     ;
;-----------------------------------------------------------------------------
reset:  nop                     ;
                                ;przyklad uzycia:
        mov     r6,#'A'         ;
        mov     r7,#'B'         ;
        lcall   ConvHex         ;rej A=ConvHex('AB');
                                ;w wyniku w rej A jest AB hex oraz wsk C=1 ===> OK
        jnc     blad            ;
        mov     p1,a            ;
        mov     r6,#'7'         ;
        mov     r7,#'X'         ;
        lcall   ConvHex         ;rej A=ConvHex('7X');
                                ;w wyniku wsk C=0 ===> error
        jnc     blad            ;
        mov     p1,a            ;
        ljmp    $               ;
blad:   nop                     ;
        ljmp    $               ;
;-----------------------------------------------------------------------------
        END

tasza
Użytkownik
Posty: 1391
Rejestracja: 21 lut 2005, 15:02

Post autor: tasza » 21 sie 2006, 10:18

Witam,
Raflles pisze:Proszę o krytykę, jeżeli coś dało się zrobić łatwiej i szybciej i żeby zajmowało mniej miejsca
jakość programisty jest odwrotnie proporcjonalna do ilości wstawionych w kod skoków bezwarunkowych

jakoś tak to było....to z MIK02 S.Gardynika ( https://elportal.pl/index.php?module=Co ... y&ceid=133 )

może zerknijcie na to....sama funkcja hex2bin:

Kod: Zaznacz cały

        ;-----------------------------------------
        ; we: R1,R0 - 2 x ascii do konwersji
        ; wy: ACC - wersja binarna
hex2bin:
        mov A, R1 	; starsza literka
        lcall h2b	; f.pomocnicza
        swap A 		; bity 0...3 --> 4...7
        mov R1,A	; wynik z powrotem do R1
        mov A, R0	; tera młodsza literka
        lcall h2b	; f.pomocnicza
        orl A, R1	; A = A | R1
        ret		; wyjście
        ; procedurka pomocnicza, 
        ; konwertuje zawartość ACC podaną w ascii na bin
h2b:
        jb ACC.4, h2b_conv_digit
        ; tu literka
        subb A, #37h
        ; w Acc jest A...F		
        ret	
        ; tu cyfra
h2b_conv_digit:	
        subb A, #30h
        ; w Acc jest 0...9			
        ret
        ;
        ;
w takim otoczeniu ją testowałam:

Kod: Zaznacz cały

        .include <../include/reg51.def>
        .segment start, org $0  
        ;
        mov SP,#20h	; stos
        ;	
        ; R1,R0 = '9A'
        mov R1, #'9'
        mov R0, #'A'
        lcall hex2bin
        ;
        ; wynik pokaż na porcie P2 
        mov P2, A
        ;
petelka_na_koniec:
        ljmp petelka_na_koniec
        ;
        ;
najpoważniejszą wadą mojej hex2bin jest brak jakiejkolwiek weryfikacji sensu podawanych
do R1,R0 danych wejściowych i w tym kontekście Wasze funkcje są lepiej napisane.

a w kwestii weryfikacji, chyba najfajniej byłoby napisać taką funkcję,
która dostanie znak do zbadania i wskaźnik na tabelkę w segmencie CODE,
w której są aktualnie przez nas dopuszczalne do użycia znaczki....
zresztą, różnie to można...

tasza

[ Dodano: 2006-08-21, 12:51 ]
jakoś nie mam natchnienia na nic lepszego, ale macie też funkcyjkę do prostej weryfikacji....
gdy znaczek jest w zbiorze podanym via DPTR i zakończonym 0h
funkcja zwraca C = 1, a gdy go tam nie ma daje C = 0....

Kod: Zaznacz cały

        .include <../include/reg51.def>
        .segment start, org $0  
        ;
        mov SP,#20h	; stos
        ;	
        mov DPTR, #hex_digits
        mov A, #'5'
        lcall ascii_in_set
        jnc err_nie_hex
        ;
petelka_na_koniec:
        ljmp petelka_na_koniec
        ;
err_nie_hex:
        ljmp err_nie_hex
        ;
        ;
        ;
        ;---------------------------------------
        ; we: ACC - badany znak
        ;     DPTR - adres tabelki z akceptowalnymi
        ;            znaczkami ascii, koniec tabelki to 00h
        ; wy: C = 1 - znaczek w zbiorze
        ;     C = 0 - znaczek poza zbiorem
        ; funkcja zamazuje zawartość R0 !
ascii_in_set:
        mov R0, A	; zabezpiecz A
        clr A
        movc A, @A+DPTR
        ; w A jest jeden z elementów tabelki
        cjne A, #00, ascii_in_set_not_finish	; czy koniec? ( 00h ? )
        ; juz koniec a tu nie ma takiego...skasuj C i sio!
        clr C
        ret	
        ;
ascii_in_set_not_finish:	
        ; więc teraz porównaj wybrany znak z zadanym
        subb A, R0	
        jz ascii_in_set_found ;jest taki znaczek, koniec szukania
        inc DPTR	; DPTR = DPTR + 1
        mov A, R0	; odtwórz A z kopii trzymanej w R0	
        ; powtórz cykl	
        sjmp ascii_in_set 	
        ;
ascii_in_set_found:
        ; jest taki znaczek, ustaw C i wyjdź
        setb C
        ret
        ;
        ;
        ; dopuszczalne znaczki
hex_digits:
        .dc.b "0123456789ABCDEF", 0h
        ;
        ;
tasza

Raflles
-
Posty: 77
Rejestracja: 06 sie 2005, 17:15
Lokalizacja: Tychy
Kontakt:

Post autor: Raflles » 24 sie 2006, 17:19

Witam ponownie !! Żeby nie zaczynać kolejnego tematu, chciałem poprosić o pomoc z następującym problemem. A więc do wyjścia mikrokontrolera podłączone są trzy szeregowo połączone rejestry z wejściem szeregowym i wyjściem równoległym typu 74LS164. Problem polega na tym, że wysyłając znaki szeregowo z mikrokontrolera na wyjściach rejestrów powstają błędy. Każdy ze scalaka jest odsprzęgnięty zaraz przy nóżce z zasilania kondensatorem 100uF/16V. Dane wychodzące z procesora są napewno poprawne, a i w powolnej prędkości wysuwu tych danych widać, że błędy popełniają rejestry. każdy z pinów równoległych rejestrów jest obciążony diodą i rezystorem podłączoną do masy. Czy dioda była podciągnięta do plusa, czy do masy takie same błędy wyskakują. Poniżej zrobiony na szybko schemat urządzenia. albo i nie :) Nie mam nigdzie na sieci możliwości załadowania obrazka. Pozdrawiam i proszę o pomoc !! A cha. Kolejny rejestr jest wejściem podłączonym do wyjścia równoległego najstarszego bitu poprzedniego rejestru. jedno z wejść szeregowych jest podłączone do plusa zasilania a drugie do wyjścia mikrokontrolera. reset i clock każdego z rejestrów też jest bezpośrednio podłączony do pinów procesora.

tasza
Użytkownik
Posty: 1391
Rejestracja: 21 lut 2005, 15:02

Post autor: tasza » 25 sie 2006, 8:58

Raflles pisze:Każdy ze scalaka jest odsprzęgnięty zaraz przy nóżce z zasilania kondensatorem 100uF/16V.
oj,oj,oj....kłania się zagadnienie odsprzęgania zasilania w układach impulsowych (cyfrowych)....
opracowań jest wiele, pierwsze z brzegu, które znalazłam:
:arrow: http://www94.web.cern.ch/HSI/s-link/dev ... couple.pdf
chodzi o to, że do odsprzęgania zasilania używa się kondensatorów o małej indukcyjności własnej
a elektrolityczne (a już takie 100uF) mają ją dość dużą,
Indukcyjność dla sygnałów szybkozmiennych (a taki charakter mają zakócenia w cyfrówce)
stanowi duży opór (reaktancję indukcyjną) i taki kondensator jest wtedy zwykłą atrapą...
na sztuki jest i nic nie wnosi.

Należy zastosować np. ceramiczne kondensatorki o małej wartości....47-100 nF :idea:

No, ale to taka uwaga na boku, ponieważ nie sądzę, że to jest przyczyna....

Schemat na bazie Twojego opisu - w załączniku...

I jeżeli spinasz wyjście QH (n) z wejściem A(n+1) czyli tworzysz łańcuch/kaskadę rejestrów
to sygnały /RESET i CLOCK muszą być wspólne :idea:
inaczej układ, choć elektrycznie poprawny, jest po prostu bez sensu....

czy masz tak jak narysowałam?

Powiedz proszę co oznacza:
Raflles pisze:Problem polega na tym, że wysyłając znaki szeregowo
z mikrokontrolera na wyjściach rejestrów powstają błędy.
Jakiego rodzaju?
dostajesz losowe kombinacje bitów? czy podobne do tych co niby wgrywasz
do rejestrów, ale regularnie poprzestawiane?

No i przydałby się choć kawalątek kodu, który odpowiada za wpisywanie danych,
może po prostu masz gdzieś błąd...

Aha, tak mi przyszło do głowy....
Do którego portu MCU masz podpięte sygnały sterujące liniami rejestru?
Jeżeli do portu P0, to poczytaj proszę to co było przerabiane u radzia:
:arrow: http://forum.mikrokontrolery.net/viewto ... =2224#2224
brak rezystorów podciągajacych na końcówkach P0 też może być przyczyną
takich dziwnych zachowań....jak coś, profilaktycznie daj R o wartości 5.1K..10K

tasza
Załączniki
kaskada_74164.gif
(12.31 KiB) Pobrany 685 razy

Raflles
-
Posty: 77
Rejestracja: 06 sie 2005, 17:15
Lokalizacja: Tychy
Kontakt:

Post autor: Raflles » 25 sie 2006, 15:26

Dzięki Tasza !! Jak zwykle jesteś niezastąpiona !!!! Rejestry były podłączone dokładnie jak na twoim schemacie, ale faktycznie były podłączone do portu P0 i zapomniałem o podciągnięciu przez rezystory do plusa. Ale zastanawia mnie fakt, że rejestr podłączony bezpośrednio do portu P0 wskazywał zawsze prawidłową wartość, a źle pokazywały te dwa kolejne. Ciekawe czemu ?? A do pierwszego rejestru zawsze wchodziła prawidłowa wartość, a błędy powstawały dopiero podczas przesuwu. Pozdrawiam !!!!

ODPOWIEDZ