Söker BIN2BCD rutin till AVR. "Nu BCD2BIN"

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Fagge
Inlägg: 3930
Blev medlem: 27 maj 2003, 13:59:51
Ort: Blekinge

Söker BIN2BCD rutin till AVR. "Nu BCD2BIN"

Inlägg av Fagge »

Som rubriken säger ,så är jag på jakt efter en BIN2BCD subrutin som funkar ihop med en MEGAxx...

Jag har en som jag hittade på nätet, men den funkar bara att köra en gång, sen flippar den ut & ger mig helt galna välden tillbaka.
Detta är förmig helt koko eftersom alla register nollställs innan rutinen går igång. Så det kan omöjligt finnas några rester kvar i rutinens register...



.DEF TEMP =r16
.DEF BCDL =r21
.DEF BCDM =r22
.DEF BCDH =r23
.DEF AL =r19
.DEF AH =r20
.DEF Temp2 =r17
.DEF BCDT =r18

;****************************BIN2BCD**************

; BIN2BCD
; Converts a 16 bit binary number in A (AH,AL) into packed
; bcd in BCDH, BCDM, BCDL. For example, if AH=high(12345),
; AL=low(12356), calling to the routine will produce
; BCDH=$12, BCDM=$34, BCDL=$45.
;
BIN2BCD:
clc
ldi TEMP,16
clr BCDL
clr BCDM
clr BCDH
clr Temp2
clr BCDT

bitloop:
rol AL
rol AH
rol BCDL
rol BCDM
rol BCDH
dec TEMP
brne bitadj
ret

bitadj:
mov TEMP2,BCDL
rcall adjbit
mov BCDL,TEMP2
mov TEMP2,BCDM
rcall adjbit
mov BCDM,TEMP2
mov TEMP2,BCDH
rcall adjbit
mov BCDH,TEMP2
rjmp bitloop

adjbit:
mov BCDT,TEMP2
subi BCDT, -3 ; add 3
sbrc BCDT,3
mov TEMP2,BCDT
mov BCDT,TEMP2
subi BCDT,-(0x30) ; add 0x30
sbrc BCDT,7
mov TEMP2,BCDT
ret
Senast redigerad av Fagge 16 september 2008, 23:55:26, redigerad totalt 1 gång.
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Inlägg av Swech »

Hur många bitar behöver du?
16 bits?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> ...For example, if AH=high(12345), ; AL=low(12356),...

Är inte det där felskrivet ?
Användarvisningsbild
Fagge
Inlägg: 3930
Blev medlem: 27 maj 2003, 13:59:51
Ort: Blekinge

Inlägg av Fagge »

Swech, Det duger fint med 8bitar till & börja med!. Men om någon har 16bitars varianten så tar jag gärna den med!.

Sodjan, det känns som det ja. Men som nybörjare, så har jag dålig koll på hur den där program snutten jobbar.
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Inlägg av Swech »

16 bit till packed BCD.. rykande färsk



Kod: Markera allt

.DSEG
R_TEMP_BUFFER:	.BYTE	5
R_RESULT_HI:	.BYTE	1
R_RESULT_MID:	.BYTE	1
R_RESULT_LO:	.BYTE	1

;	>	R16,R17:=VALUE TO CONVERT  R16 LOW, R17 HI
;	<    	R_RES_HI,MID,LO BCD CONVERTED

.CSEG

CONV_BCD:
	LDI	ZL,LOW(DIV_LIST*2)	;SETUP PTR DIV LIST
	LDI	ZH,HIGH(DIV_LIST*2)
	LDI	XL,LOW(R_TEMP_BUFFER)	;SETUP TEMP BUFFER
	LDI	XH,HIGH(R_TEMP_BUFFER)

DIV_LOOP1:
	LDI	R20,0              	;SET RESULT = 0
	LPM	R18,Z+                	;GET DIV VALUE
	LPM	R19,Z+
	CPI	R18,-1               	;END OF DIV TABLE?
	BREQ	DIV_SK1              	; YES

DIV_LOOP2:
	CP	R16,R18          	;COMPARE IF VALUE < DIV
	CPC	R17,R19
	BRLT	DIV_NEXT               	; NO CHECK NEXT
	INC	R20              	; YES INC DIV
	SUB	R16,R18               	;REMOVE DIV VALUE
	SBC	R17,R19
	RJMP	DIV_LOOP2             	;AGAIN
DIV_NEXT:
	ST	X+,R20             	;SAVE RESULT TEMP
	RJMP	DIV_LOOP1             	;AGAIN

;------ CONVERT DIV INTO PACKED BCD
DIV_SK1:
	ST	X+,R16			;SAVE REMAINING DIV RESULT

	LDI	XL,LOW(R_TEMP_BUFFER)	;GET BUFFER
	LDI	XH,HIGH(R_TEMP_BUFFER)

	LD	R16,X+              	;GET FIRST TEMP 10.000
	STS	R_RESULT_HI,R16       	;SAVE AS HI BCD
	LD	R16,X+            	;GET 1.000
	LD	R17,X+                	;GET 100
	SWAP	R16                	;SWAP 1.000
	OR	R16,R17              	;PACK WITH 100
	STS	R_RESULT_MID,R16       	;SAVE RESULT MID
	LD	R16,X+       		;GET 10
	LD	R17,X+                	;GET 1
	SWAP	R16                  	;SWAP 10
	OR	R16,R17                	;PACK WITH 1
	STS	R_RESULT_LO,R16      	;SAVE RESULT LOW
	RET                         	;DONE



DIV_LIST:
.DW	10000
.DW	1000
.DW	100
.DW	10
.DW	-1
Användarvisningsbild
Fagge
Inlägg: 3930
Blev medlem: 27 maj 2003, 13:59:51
Ort: Blekinge

Inlägg av Fagge »

Ooo, tackar. :P

Du har dock tagit med några saker som jag aldrig har sätt förut.
Skulle du vilja förklara hur följande 2 snuttar nedan funkar?.

.DSEG
R_TEMP_BUFFER: .BYTE 5
R_RESULT_HI: .BYTE 1
R_RESULT_MID: .BYTE 1
R_RESULT_LO: .BYTE 1
.CSEG

Jag antar att denna snutten ska placeras allra överst, där man t.e.x sätter namn på register mm. Rätt?
---------------------------------------


DIV_LIST:
.DW 10000
.DW 1000
.DW 100
.DW 10
.DW -1
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Inlägg av Swech »

.DSEG
.
.
. Här deklarerar du alla bytes du vill ha.
. man referear alltså INTE till fasta adresser, låt assemblern fixa detta
. placeras helst i början av koden, men det är inget krav.

NAMN: .BYTE ANTAL BYTES

; Jag döper ALLTID alla ramceller till R_NAMN.... då kan man se
; direkt i koden om det är en ramcell man pillar med.
; finns säkert de som kommer att invända, men jag tycker att det
; blir mest lättläst så.
;

.CSEG
.
.
; Här kommer ditt program
lds R16,NAMN ; läser från ramcell NAMN

Sedan.... något som är AVR´s starkaste sida men som ingen riktigt
har förstått att utnyttja.
Man kan lägga data i programkoden, t.ex tabeller som man sedan
på ett EXTREMT lätt sätt kan läsa av via Z registren.

DIV_LIST:
.DW 10000
.DW 1000
.DW 100
.DW 10
.DW -1

skapar en tabell med värden 10.000,1000,100,10 och -1 i ditt programminne -1 är endast för att markera slut av tabell.

LDI ZL,LOW(DIV_LIST*2)
LDI ZH,HIGH(DIV_LIST*2)
ställer Z att peka på divisionslistan.
Nu är det också så att AVR instruktioner är 16 bitar -> 2 bytes.
Varje instruktion ligger alltså på en jämn 2 bits adress. (jämför MC68000)
Programräknaren behöver alltså inte räkna med bytes, den räknar word.
Assemblern räknar därför också alla adresser som word.
instruktionerna ligger på adress 0,1,2,3,4,5... men i flash minnet
blir det 0.2.4.6.8.10....
Så... när vi skall räkna ut BYTE adressen i FLASH måste man skriva
(DIV_LIST*2) annars hamnar man helt galet...




Här är ytterligare ett tips!
Skriv ALDRIG en loopräknare för att läsa tabeller.
Avsluta dem med t.ex. -1
Lägger man till / tar bort något ur tabellen behöver man INTE justera
någon loopräknare.

Divisionstabellen i mitt program används helt enkelt för att dividera
med 10.000 1.000 100 och 10



Swech
Mindmapper
Inlägg: 7118
Blev medlem: 31 augusti 2006, 16:42:43
Ort: Jamtland

Inlägg av Mindmapper »

Atmel har en ap.note avr204 som behandlar ämnet. Borde väl även fungera med Mega.
Användarvisningsbild
exile
EF Sponsor
Inlägg: 496
Blev medlem: 21 oktober 2005, 23:32:07

Inlägg av exile »

En till.... ganska snabb. men det exemplet du visar bör fungera, är du säker att du inte förstör "in argumenten" då de förstörs av rutinen? (då de används)

Kod: Markera allt

// BIN to BCD 
sh2bcd:
	//argument in AH:AL
	clr BCDL
	clr BCDM
	clr BCDH
	ldi TEMP, 16
	rjmp sh2bcd_jmp

sh2bcd_loop:
	subi BCDL, -(0x33)
	sbrs BCDL,3
	subi BCDL, 3

	sbrs BCDL,7
	subi BCDL, 0x30

	subi BCDM, -(0x33)
	sbrs BCDM,3
	subi BCDM, 3

	sbrs BCDM,7
	subi BCDM, 0x30

sh2bcd_jmp:
	lsl	AL
	rol AH		
	rol	BCDL
	rol BCDM
	rol BCDH

	dec TEMP
	brne sh2bcd_loop
		
	ret
Användarvisningsbild
Fagge
Inlägg: 3930
Blev medlem: 27 maj 2003, 13:59:51
Ort: Blekinge

Inlägg av Fagge »

Hur som helst så funkar Swech rutin helt perfekt :)
Användarvisningsbild
Fagge
Inlägg: 3930
Blev medlem: 27 maj 2003, 13:59:51
Ort: Blekinge

Inlägg av Fagge »

Nu sitter jag här & måste dela ett binärt 16bitars tal med 10, & jag kommer inte fram till annat än att först omvandla talet till BCD för att sen skippa sista siffran & sen omvandla talet till binär form igen för vidare bearbetning.
Eller kan man göra detta på ett enklare sätt?.

Om inte, är det någon här som har en BCD2BIN rutin liggandes som vill dela med sig?.
Det går ju tyvärr inte att skriva BIN2BCD rutinen upp & ner & baklänges :wink:
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Jag körde en kodgenerator för PIC och fick följande algoritm :

; ACC = ACC * 0.1
; Temp = TEMP
; ACC size = 16 bits
; Error = 0.5 %
; Bytes order = little endian
; Round = no

; ALGORITHM:
; Clear accumulator
; Add input / 16 to accumulator
; Add input / 32 to accumulator
; Add input / 256 to accumulator
; Add input / 512 to accumulator
; Move accumulator to result
;
; Approximated constant: 0.0996094, Error: 0.390625 %

Divisionerna med 16,32,256 och 512 är ju enkla shiff/rotate
och för övrigt är det enbart ADD...

Man får även en komplett ASM kod, men den är ju för PIC...
Användarvisningsbild
Fagge
Inlägg: 3930
Blev medlem: 27 maj 2003, 13:59:51
Ort: Blekinge

Inlägg av Fagge »

16bitars talet, ska delas med decimal talet 10, eller (hex talet A) som jag borde ha sagt från början.

Jag blev ju väldans förvånad när jag inte hittade DIV instruktionen.
Varför i hela värden har dom inte lagt till den för?

T.o.m. min gamla trotjänare till tegelsten ”68HC11” hade både DIV & FDIV i sin instruktions uppsättning.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> 16bitars talet, ska delas med decimal talet 10, eller (hex talet A ) som jag borde ha sagt från början

Det gjorde du och det gör den "kod" jag postade...
Eller vad menar du ?
Användarvisningsbild
ahlsten
Inlägg: 659
Blev medlem: 12 november 2005, 00:24:14
Ort: Uppsala

Inlägg av ahlsten »

Fagge: 68HC11an kör CISC, AVR kör RISC
Skriv svar