logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Jak podzielić szesnastkowe 16-bitowe liczby na 8051 i zamienić na dziesiętne?

Telside 17 Maj 2005 16:36 7891 18
REKLAMA
  • #1 1500923
    Telside
    Poziom 10  
    Posty: 56
    Ocena: 4
    Witam wszystkich. Mam do napisania pod 8051 program ktory bedzie zamienial szesnastkowa 16 bitowa liczbe na pieciocyfrowa dziesietna (wiec szesnastkowe bierzemy z takiego przedzialu aby najmniejsza dziesietna wyniosla 10000 a najwieksza 65535). Wymyslilem sobie cos takiego, ze dziele liczbe startowa przez 10000 bez reszty i zapisuje wynik, ktory nastepnie mnoze przez 10000 i odejmuje od liczby startowej. Nastepnie wynik odejmowania dziele przez 1000 znowu bez reszty i otrzymuje kolejna cyferke dziesietna. Znowu to co mam mnoze przez 1000 i odejmuje, itd. Na koncu dziele przez 1 (czyli juz nic nie robie) i dopisuje ta reszte na ostatniej pozycji liczby pieciocyfrowej. I teraz mam problem natury podstawowej: jak wykonac operacje dzielenia np. liczby FFFF/2710. Bo nie mam pojecia nawet jakby to wykonac recznie (jak pomnozyc wiem). Przejrzalem co nieco archiwum ale jakos nic nie trafilo do mnie z tego. Moze ktos bylby laskaw napisac dosc lopatologicznie jak taka operacje wykonac. Z gory serdecznie dzieki.
  • REKLAMA
  • #2 1501191
    Robot_
    Poziom 18  
    Posty: 277
    Pomógł: 22
    Wróżka ma dzisiaj wolne więc powiedz w jakim języku chcesz to zrobić
  • #3 1501387
    Telside
    Poziom 10  
    Posty: 56
    Ocena: 4
    W asemblerze
  • REKLAMA
  • #5 1501802
    Telside
    Poziom 10  
    Posty: 56
    Ocena: 4
    hmm... niestety to do mnie nie przemawia, moze gdyby bylo jeszcze po polsku.... moze jakas translacja na bardziej lopatologiczny zapis...? to co sam napisalem nie jest zapewne sposobem prawidlowym z punktu widzenia optymalizacji, poprawnosci informatycznej itd. ale to byl pierwszy pomysl jaki mi sie nawinal - no i na papierze z kalkulatorem w dloni on dziala. jakkolwiek, w jaki sposob dzieli sie liczby szesnastkowe? przeciez musi byc tego jakis algorytm.
  • #6 1502086
    McRancor
    VIP Zasłużony dla elektroda
    Posty: 5326
    Pomógł: 479
    Ocena: 124
    Daj sobie spokuj z dzieleniem liczb 16bitowych w 8 bitowym procesorze, bo jeśli nie chce Ci się zrozumieć tego banalnego algorytmu zamiany na BCD to na pewno nie będzie Ci się chciało przekopać przez algorytm dzielenia liczb dwa razy dłuższych niż procesor ;)

    Algorytm jest bardzo prosty, przesuwasz w lewo a to co odpada wrzucasz do jednostek, robisz tak aż przesuniesz ostatnią wartość do jednostek, czyli osiem razy, jeżeli w którymkolwiek liczniku pojedyńczej cyfry jest wartość większa niż 4 (czyli po przesunięciu bitów wyrośnie nam liczba większa niż 9, to zamiast przesuwać wszystko w lewo dodajemy do tej liczby 3 i dopiero przesuwamy wszystko.

    Algorytm jest dość prosty i skuteczny, dla liczb 16bitowych używamy 5 4bitowych liczników cyfr i przesówamy 16razy, czasem trzeba dodawać trójki do dwóch liczników na raz.
  • #7 1502207
    Telside
    Poziom 10  
    Posty: 56
    Ocena: 4
    Nie sadzilem ze algorytm dzielenia dwoch liczb 16bitowych jest tak bardzo skomplikowany, ze nie ma sensu go wykonywac na procesorze 8 bitowym a mi sie nie bedzie chcialo go przekopac. Duzo rzeczy nie ma sensu. Teoretycznie powinienem napisac program dzielenia 16 bitow / 16 bitow przy czym dzielna < dzielnika, co daje przeciez liczby ulamkowe, a to chyba jest jeszcze gorsze, niz dzielenie tak naprawde czastkowe o ktore mi chodzi (dzielenie bez reszty).
  • REKLAMA
  • #9 1503585
    shg
    Poziom 35  
    Posty: 2289
    Pomógł: 339
    Ocena: 135
    W oparciu o to:
    https://www.elektroda.pl/rtvforum/topic262306.html

    Napisałem to, co w załączniku. Tylko, że tam jest zamiana 3 bajtowej liczby na system dziesiętny (w każdej komórce pamięci liczba od 0 do 9).
    W zasadzie chodzi o to, żeby dodawać, albo nie (w zależności od ustawionego bitu w liczbie wejściowej) w systemie dziesiętnym wagi cyfr odpowiadających kolejnym cyfrom w systemie binarnym.
    Tą procedurkę można łatwo "zhackować", żeby wykonywała konwersję dla liczb wejściowych o dowolnej długości.

    Konketniej to chodzi o procedurę bin3_to_BCD, bo w pliku jest jeszcze kilka innych.
    Załączniki:
    • zegar_synt_pll_saa.asm.txt (9.16 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #10 1508413
    opac
    Poziom 2  
    Posty: 2
    Witam

    Mam do zrobienia konwersje dwubajtowej liczby dziesietnej na szesnastkową. Robimy to w asemblerze `51.
    Zalecono zastosowanie jakiegos odejmowania wag (1,10,100,1000) i zliczanie...nie za bardzo rozumiem o co w tym biega. Jesli ktos moglby to wytlumaczyc byłbym wdzieczny
  • REKLAMA
  • #12 1508989
    shg
    Poziom 35  
    Posty: 2289
    Pomógł: 339
    Ocena: 135
    A ja bym zamianę z dziesiętnej na szesnastkową zrobił dodając wagi... ;)
    A dokładniej to tak:
    Konwesja w dwóch etapach - najsampierw na binarną, a dopiero potem na szesnastkową - będzie prościej.

    Zamiana z dziesiętnej na binarną - dodajesz wagi (1, 10, 100, ...) tyle razy ile wynosi wartość odpowiadającej danej wadze cyfry. To jest paskudnie proste ;)

    A potem zamiana z binarnej na szesnastkową, to już istna bajka - po kolei z jiczby po 4 bity bierzesz i zamieniasz je na odpowiednie cyfry szesnastkowe.

    Przykład: zamienić 12345 na postać szesnastkową:
    dodajemy po kolei wartości cyfr przemnożone przez jej wagę (czyli najprościej będzie dodawać wagę odpowiedinią ilość razy). Nie ważne, od której strony zaczynamy, tu zakładam, że od prawej i tak:
    0. wyjście = 0
    1. waga = 1
    2. jeżeli nie ma już cyfr do przetworzenia, to skocz do 10
    3. cyfra = pobierz kolejną cyfrę
    4. jeżeli cyfra = 0, to skocz do 8
    5. wyjście = wyjście + waga
    6. cyfra = cyfra - 1
    7. skocz do 4
    8. waga = waga * 10, albo waga = następna waga z tablicy
    9. skocz do 2
    10. koniec

    I w ten oto sposób zmienna wynik zawera odczytaną wartość liczby dziesiętnej, zamiany na szesnastkowy nie opiszę, bo nie :P

    Kolejne wagi można pobierać z tabeli, będzie szybciej, niż mnożenie ich przez 10, szczególnie przy większych liczbach.
  • #13 1511547
    simonel
    Poziom 12  
    Posty: 52
    Pomógł: 3
    Ocena: 1
    Zamiana 16 bitow na 5 cyferek lopatologicznie w asemblerze
    Załączniki:
    • cyfra.txt (3.38 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #14 1607755
    Konto nie istnieje
    Konto nie istnieje  
  • #15 1608039
    Konto nie istnieje
    Konto nie istnieje  
  • #16 1608335
    GienekS
    Poziom 32  
    Posty: 1971
    Pomógł: 139
    Ocena: 15
    W załączeniu moje biblioteki na '51 mnozenia, dzielenia, BCD na BIN, BIN na BCD. wszystko jest realizowane na tylu bajtach ile się zadeklaruje w zmiennej LCZYN.
    ;
    ;	Procedury biblioteczne dla procesora 8031
    ;
    ;--------------------------------------
    ;przyklad zastosowania ponizszych procedur
    ;--------------------------------------
    	org	0	;
    ;			;
    start:	acall	BBCD	;
    	acall	BCDB	;
    	acall	MUL	;
    	acall	DZIEL	;
    	ajmp	start	;
    ;-----------------------
    LCZYN	equ	4	;dlugosc czynnikow w bajtach
    BCD	equ	20h
    CZYNIK1	equ	BCD+LCZYN+1
    CZYNIK2	equ	CZYNIK1+LCZYN
    AKU1	equ	CZYNIK2+LCZYN
    AKU2	equ	AKU1+LCZYN*2
    WYNIK	equ	AKU2+LCZYN*2
    RAKU1	equ	WYNIK+LCZYN*2
    RAKU2	equ	RAKU1+1
    ;---------------------------------------------------------
    ;Program mnozenia liczb binarnych urzywa rejestry R0 do R7
    ;Organizacja pamieci dla procedur
    ;      xxxxx	BCD	
    ;	xxxx	CZYNIK1 oraz BIN
    ;	xxxx	CZYNIK2
    ;   xxxxxxxx	AKU1	oraz	WYNIKD
    ;   xxxxxxxx	AKU2	oraz	DZIELNIK
    ;   xxxxxxxx	WYNIK	oraz	DZIELNA
    ;	   x	RAKU1
    ;	   x	RAKU2
    ;
    MUL:	mov	r0,#AKU1
    	mov	r2,#WYNIK-AKU1+LCZYN*2
    	acall	ZERO
    	mov	RAKU1,#AKU1+LCZYN*2-1
    	mov	RAKU2,#AKU2+LCZYN*2-2
    	mov	r6,#CZYNIK1+LCZYN-1
    	mov	r3,#LCZYN	;ilosc czynnikow 2
    LOOP:	mov	r7,#CZYNIK2+LCZYN-1
    	mov	r5,RAKU1
    	mov	r4,RAKU2
    	acall	ZER_AKU
    	acall	MUL1
    	acall	D_ABW
    	dec	r6	;nastepny czynnik 2
    	dec	RAKU1
    	dec	RAKU2
    	djnz	r3,LOOP
    	ret
    ;
    ;Procedura dadawania
    ;R0 i R1 => R1 w R2 dlugosc
    DODAJ1:	clr	c
    DL:	mov	a,@r0
    	addc	a,@r1
    	mov	@r1,a
    	dec	r0
    	dec	r1
    	djnz	r2,DL
    	ret
    ;Procedura dadwania czesciowego
    D_ABW:	mov	r0,#AKU1+LCZYN*2-1	;7
    	mov	r1,#WYNIK+LCZYN*2-1	;7
    	mov	r2,#LCZYN*2		;8
    	acall	DODAJ1
    	mov	r0,#AKU2+LCZYN*2-1	;7
    	mov	r1,#WYNIK+LCZYN*2-1	;7
    	mov	r2,#LCZYN*2		;8
    	ajmp	DODAJ1
    ;Procedura zerowania akumulatorow
    ZER_AKU:
    	mov	r0,#AKU1
    	mov	r2,#LCZYN*4		;16, AKU1+AKU2
    ;Procedura zerowania
    ZERO:	mov	@r0,#0
    	inc	r0
    	djnz	r2,ZERO
    	ret
    ;Procedura mnozenia
    ;w R6 czynnik 1
    ;w R7 czynnik 2
    ;w R5 AKU1 adres A, w R4 AKU2 adres B
    ;w R2 dlugosc
    MUL1:	mov	r2,#LCZYN	;4
    MLOOP:	mov	r0,6
    	mov	r1,7
    	mov	a,@r0
    	mov	b,@r1
    	mul	ab
    	mov	r0,5
    	mov	r1,4
    	mov	@r0,a
    	mov	@r1,b
    	dec	r4
    	dec	r5
    	dec	r7
    	djnz	r2,MLOOP
    	ret
    ;--------------------------------------------------
    ;	Procedura dzielenia
    ;
    ;	xxxxxxxx	DZIELNA	w WYNIKu z mnozenia
    ;	xxxxxxxx	DZIELNIK w AKU2
    ;	xxxxxxxx	WYNIKD	w AKU1
    ;
    DZIELNA	equ	WYNIK
    LDA	equ	LCZYN*2	
    LDK	equ	LDA
    DZIELNIK	equ	AKU2	;DZIELNA+LDA
    WYNIKD	equ	AKU1
    LWY	equ	LDA
    ;
    DZIEL:	acall	ZERWYN	;if DZIELNIK=0 then C=1 else C=0
    	acall	CZY_0
    	jc	KONIEC
    	mov	r1,#DZIELNIK+LDK-1
    	mov	r0,#DZIELNA+LDA-1
    	mov	r2,#LDA
    	acall	POROW
    	jc	NEGAT
    	acall	SZUKAJ
    DA_DK:	acall	ODJAC8
    	mov	r0,#WYNIKD+LWY-1
    	mov	r2,#LWY
    	acall	MNOZ2	;wynik*2
    	inc	WYNIKD+LWY-1	;+1
    DAL:	djnz	r3,DALEJ
    	clr	c
    	ajmp	KONIEC
    DALEJ:	acall	DZIEL8	;dzielnik/2
    	acall	PODZIELNE	;czy jest podzielne
    	jc	DA_DK
    	mov	r0,#WYNIKD+LWY-1
    	mov	r2,#LWY
    	acall	MNOZ2	;wynik*2
    	ajmp	DAL
    NEGAT:	clr	c
    KONIEC:	ret
    ;Procedura odejmowania od R1, R0 wynik umieszcza w R1
    ;w R2 dlugosc bufora w bajtach
    ODJAC8:	acall	USTAW8
    ODJAC:	clr	c
    LOOPO:	mov	a,@r1
    	subb	a,@r0
    	mov	@r1,a
    	dec	r0
    	dec	r1
    	djnz	r2,LOOPO
    	ret
    ;Procedura dodawania do R0, R1 wynik umieszcza w R0
    ;w R2 dlugosc bufora w bajtach
    DODAJ8:	acall	USTAW8
    DODAJ:	clr	c
    LOOP1:	mov	a,@r0
    	addc	a,@r1
    	mov	@r0,a
    	dec	r0
    	dec	r1
    	djnz	r2,LOOP1
    	ret
    ;Sprawdzenie if Dzielnik = 0 then C=1 else C=0
    CZY_0:	mov	r0,#DZIELNIK
    	mov	r2,#LDK
    	setb	c
    CZY:	mov	a,@r0
    	jnz	ZERO_C
    	inc	r0
    	djnz	r2,CZY
    	ret
    ZERO_C:	clr	c
    	ret
    ;Sprawdzenie rownosci if R0 = R1 then C=1 else C=0
    ;w R2 dlugosc bufora w bajtach
    PODZIELNE:
    	acall	USTAW8
    CZYR:	mov	a,@r0
    	mov	b,@r1
    	cjne	a,b,ROZNE
    	dec	r0
    	dec	r1
    	djnz	r2,CZYR
    	setb	c
    	ret
    ROZNE:	acall	POROW8
    	ret
    ;Porownanie R0 z R1 wynik umieszczany jest w C
    ;w R2 dlugosc bufora w bajtach
    POROW8:	acall	USTAW8
    POROW:	clr	c
    LOOP2:	mov	a,@r0
    	subb	a,@r1
    	dec	r0
    	dec	r1
    	djnz	r2,LOOP2
    	ret
    ;Mnozenie razy 2 bufora R0 o dlugosci w R2
    MNOZ8:	mov	r0,#DZIELNIK+LDK-1
    	mov	r2,#LDK
    MNOZ2:	clr	c
    LOOP3:	mov	a,@r0
    	rlc	a
    	mov	@r0,a
    	dec	r0
    	djnz	r2,LOOP3
    	ret
    ;Dzielenie przez 2 bufora R0 o dlugosci w R2
    DZIEL8:	mov	r0,#DZIELNIK
    	mov	r2,#LDK
    DZIEL2:	clr	c
    LOOP4:	mov	a,@r0
    	rrc	a
    	mov	@r0,a
    	inc	r0
    	djnz	r2,LOOP4
    	ret
    ;Ustawia rejestry dla procedur
    USTAW8:	mov	r0,#DZIELNIK+LDK-1
    	mov	r1,#DZIELNA+LDA-1
    	mov	r2,#LDA	;podstawic dluzszy bufor
    	ret
    ;Szukanie pozycji dzielnika w stosunku do dzielnej
    SZUKAJ:	mov	r3,#0	;wskaznik ilosci przesuniec
    LOOP5:	mov	r0,#DZIELNA+LDA-1
    	mov	r1,#DZIELNIK+LDK-1
    	mov	r2,#LDA
    	acall	POROW
    	jc	WROC
    	inc	r3
    	acall	MNOZ8
    	ajmp	LOOP5
    WROC:	acall	DZIEL8
    PRZEZ0:	ret
    ;
    ZERWYN:	mov	r0,#WYNIKD
    	mov	r2,#LWY
    ZER:	mov	@r0,#0
    	inc	r0
    	djnz	r2,ZER
    	ret
    ;----------------------------------------------------------
    ;	Procedury przeliczeniowe Bin na BCD oraz BCD na Bin
    ;			dla komputera 8031
    ;/***** ***** ***** ***** *****/***** ***** ***** *****/
    ;/	       BCD	       /	  BIN	       /
    ;BCD	equ	20h	;adres bazowy bufora
    LBCD	equ	LCZYN+1
    BIN	equ	BCD+LBCD
    LBIN	equ	LCZYN
    ;
    ;	Procedura zamiany liczby BIN na BCD
    ;	Wywolanie przez ACALL BBCD niszczy A,R1,R2,R3
    ;
    BBCD:	mov	r3,#8*LBIN
    	acall	ZER_BCD
    S1:	acall	KOR
    	acall	ROL
    	djnz	r3,S1
    	ret
    ;
    KOR:	mov	r0,#BCD+LBCD-1
    	mov	r1,#LBCD
    KOR1:	mov	a,@r0
    	cjne	a,#50h,KOR2
    KOR2:	jc	NIEKOR
    	add	a,#30h
    	mov	@r0,a
    NIEKOR:	anl	a,#0fh
    	cjne	a,#5,KOR3
    KOR3:	jc	NIEKO
    	add	a,#3
    	mov	r7,a
    	mov	a,@r0
    	anl	a,#0f0h
    	orl	a,r7
    	mov	@r0,a
    NIEKO:	dec	r0
    	djnz	r1,KOR1
    	ret
    ;
    ROL:	clr	c
    	mov	r2,#LBCD+LBIN
    	mov	r0,#BIN+LBIN-1
    ROL1:	mov	a,@r0
    	rlc	a
    	mov	@r0,a
    	dec	r0
    	djnz	r2,ROL1
    	ret
    ;
    ZER_BCD:
    	mov	r0,#BCD
    	mov	r1,#LBCD
    ZER1:	mov	@r0,#0
    	inc	r0
    	djnz	r1,ZER1
    	ret
    ;---------------------------------------------------
    ;      Procedura zamiany liczby z kodu BCD na B
    ;      Wywolanie przez ACALL BCDB niszczy A,R1,R2,R3
    ;
    BCDB:	MOV	R1,#BCD+LBCD
    	MOV	R2,#LCZYN
    PBCDB1:	MOV	@R1,#0
    	INC	R1
    	DJNZ	R2,PBCDB1
    	CLR	C
    	MOV	R2,#LBIN*8	;ilosc bitow do przesuniecia w B
    PP2:	MOV	R3,#LBCD+LBIN	; -"-  bajtow do dzielenia w BCDB
    	MOV	R1,#BCD
    PLOP2:	MOV	A,@R1    ;petla dzielaca BUFBCD/2
    	RRC	A
    	MOV	@R1,A
    	INC	R1
    	DJNZ	R3,PLOP2
    	DJNZ	R2,DAL1
    	RET		;koniec przeliczenia
    DAL1:	MOV	R3,#LBCD	;ilosc bajtow do korekcji w BCD
    	MOV	R1,#BCD
    PLOP5:	MOV	A,@R1	;korekcja biezacego bajtu
    	ANL	A,#80H
    	JZ	POMIT1
    	MOV	A,@R1
    	ANL	A,#7FH
    	ADD	A,#50H	;korekcja nibla H
    	MOV	@R1,A
    POMIT1:	MOV	A,@R1
    	ANL	A,#8
    	JZ	POMIT2
    	MOV	A,#0F7H
    	ANL	A,@R1
    	ADD	A,#5	;korekcja nibla L
    	MOV	@R1,A
    POMIT2:	INC	R1
    	DJNZ	R3,PLOP5	;do korekcji nastepnego bajtu
    	AJMP	PP2	;nastepne dzielenie BUFBCD/2
    	end
    
  • #17 1611083
    Konto nie istnieje
    Konto nie istnieje  
  • #18 1611150
    GienekS
    Poziom 32  
    Posty: 1971
    Pomógł: 139
    Ocena: 15
    Moim celem było napisanie procedur elastycznych do różnych celów i dowolnej długości. I myślę że się mi udało.
  • #19 1611256
    Konto nie istnieje
    Konto nie istnieje  

Podsumowanie tematu

✨ Dyskusja dotyczy problemu konwersji 16-bitowej liczby szesnastkowej na pięciocyfrową liczbę dziesiętną w asemblerze dla mikrokontrolera 8051. Autor planuje dzielenie liczby przez 10000 i kolejne potęgi 10 w celu wyodrębnienia poszczególnych cyfr dziesiętnych, jednak napotyka trudności z implementacją dzielenia 16-bitowego przez 16-bitowe liczby na 8-bitowym procesorze. W odpowiedziach zaproponowano alternatywne metody, m.in. algorytm konwersji binarnej na BCD oparty na przesunięciach bitowych i dodawaniu wartości 3 do liczników, co jest efektywnym sposobem na uniknięcie skomplikowanego dzielenia. Podano również linki do istniejących procedur i bibliotek asemblerowych realizujących mnożenie, dzielenie oraz konwersję BCD-BIN i BIN-BCD dla 8051. Wskazano, że dzielenie można realizować przez wielokrotne odejmowanie lub przesunięcia bitowe z korektą, a także zaprezentowano przykładowe procedury dzielenia 16-bitowego przez 16-bitowe liczby wraz z kodem asemblerowym. Omówiono kompromis między rozmiarem kodu a szybkością wykonania oraz znaczenie uniwersalności i optymalizacji pamięci RAM w programach dla 8051.
Wygenerowane przez model językowy.
REKLAMA