Vous êtes sur la page 1sur 8

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

******************************************************** * Number conversion routines, Version 0.1 January 2002 * * (C)2002 by http://www.avr-asm-tutorial.net * ******************************************************** The following rules apply for all conversion routines: - Errors during conversion set the T-bit in the status register. - Z points to either SRAM (Z>=$0060) or to registers ($0001 .. $001D, exclude R0, R16 and R30/31). - ASCII- and BCD-coded numbers with multiple digits are placed with higher significant digits at lower adresses. Z should always point to the most significant digit. - 16-bit-binary values are generally located in the registers rBin1H:rBin1L. These must be defined within the calling program. - Register rmp (range: R16..R29) is used within the routines, its content is changed. - Register pair Z is used within the routines, its content is set depending on the result. - Some routines use register R0 temporarily, its content is restored. - Due to the use of the Z-Register pair the header file for the target processor (xxxxdef.inc) must be included in the calling program or ZH (R31) and ZL (R30) must be defined manually. Otherwise an error message results, or you will get crazy things going on, when you run the program. - Because subroutines and push/pop-operations are used within these routines you must set the stack pointer (SPH:SPL, resp. SPL for devices with equal or less than 256 Byte internal SRAM). ***************** Routines Overview ******************** Routines Input Conditions Out, Errors -------------------------------------------------------AscToBin2 Z points on stops at first non- 16-bit-bin first ASCII non-decimal digit, rBin1H:L, char ignores leading Overflow blanks and zeros Asc5ToBin2 Z points on requires exact 5 16-bit-bin first ASCII valid digits, rBin1H:L, char ignores leading Overflow blanks and zeros and non-dec Bcd5ToBin2 5-digit-BCD requires exact 5 16-bit-bin Z points to valid digits rBin1H:L first digit Overflow and non-BCD Bin2ToBcd5 16-bit-bin Z points to first 5-digit-BCD in rBin1H:L BCD digit Z on first, no errors Bin2ToHex4 16-bit-bin Z points to first 4-digit-hex in rBin1H:L Hex ASCII digit, Z on first hex digits A..F no errors Hex4ToBin2 4-digit-hex Z points to first 16-bit-bin Z points to hex ASCII digit, rBin1H:L, first char requires 4 digits, invalid hex A..F or a..f ok digit ******************* Conversion code ********************

; ; Package I: From ASCII resp. BCD to binary ; ; AscToBin2 ; ========= ; converts an ASCII coded number to a 2-Byte bi; nary ; In: Z points to first digit, conversion stops at first ; digit detected or if overflow of the result occurs, ; end of number must be terminated by a non-decimal ; ASCII-digit! ; Out: Z points to first non-valid digit or to the digit ; where the overflow occurred, if number is valid the ; T-Flag is clear and the number is in registers ; rBin1H:rBin1L ; Used registers: rBin1H:L (result), rBin2H:L (restored ; after use), rmp ; Called subroutines: Bin1Mul10 ; AscToBin2: clr rBin1H ; Clear the result clr rBin1L clt ; Clear error flag bit AscToBin2a: ld rmp,Z+ ; ignore leading blanks and zeros cpi rmp,' ' ; blank? breq AscToBin2a cpi rmp,'0' ; zero? breq AscToBin2a AscToBin2b: subi rmp,'0' ; subtract ASCII zero brcs AscToBin2d ; End of the number cpi rmp,10 ; check invalid digit brcc AscToBin2d ; No-decimal char rcall Bin1Mul10 ; Multiply binary number by 10 brts AscToBin2c ; overflow, return with T-Flag set add rBin1L,rmp ; add the digit to the binary ld rmp,Z+ ; read next char brcc AscToBin2b ; no overflow to binary MSB inc rBin1H ; Overflow to binary MSB brne AscToBin2b ; no overflow of binary MSB set ; Set overflow flag AscToBin2c: sbiw ZL,1 ; Back one char, last char end/invalid AscToBin2d: ret ; ; Asc5ToBin2 ; ========== ; converts a 5-digit ASCII to a 16-bit-binary ; In: Z points to first decimal ASCII-digit, leading ; blanks and zeros are ok. Requires exact 5 digits. ; Result: T-Flag reports result: ; T=0: result in rBin1H:rBin1L, valid, Z points to ; first digit of the hex-ASCII-number ; T=1: error, Z points to the first illegal character ; or to the digit, where the overflow occurred ; Used registers: rBin1H:L (result), R0 (restored after ; use), rBin2H:L (restored after use), rmp ; Called subroutines: Bin1Mul10

; Asc5ToBin2: push R0 ; R0 is used as counter, save it first ldi rmp,6 ; five chars, one too much mov R0,rmp clr rBin1H ; Clear result clr rBin1L clt ; Clear T-Bit Asc5ToBin2a: dec R0 ; all chars read? breq Asc5ToBin2d ; last char ld rmp,Z+ ; read a char cpi rmp,' ' ; ignore blanks breq Asc5ToBin2a ; next char cpi rmp,'0' ; ignore leading zeros breq Asc5ToBin2a ; next char Asc5ToBin2b: subi rmp,'0' ; treat digit brcs Asc5ToBin2e ; Last char was invalid cpi rmp,10 ; digit > 9 brcc Asc5ToBin2e ; Last char invalid rcall Bin1Mul10 ; Multiply result by 10 brts Asc5ToBin2e ; Overflow occurred add rBin1L,rmp ; add the digit ld rmp,z+ brcc Asc5ToBin2c ; no overflow to MSB inc rBin1H ; Overflow to MSB breq Asc5ToBin2e ; Overflow of MSB Asc5ToBin2c: dec R0 ; downcount number of digits brne Asc5ToBin2b ; convert more chars Asc5ToBin2d: ; End of ASCII number reached ok sbiw ZL,5 ; Restore start position of ASCII number pop R0 ; Restore register R0 ret Asc5ToBin2e: ; Last char was invalid sbiw ZL,1 ; Point to invalid char pop R0 ; Restore register R0 set ; Set T-Flag for error ret ; and return with error condition set ; ; Bcd5ToBin2 ; ========== ; converts a 5-bit-BCD to a 16-bit-binary ; In: Z points to the most signifant digit of the BCD ; Out: T-flag shows general result: ; T=0: Binary in rBin1H:L is valid, Z points to the ; first digit of the BCD converted ; T=1: Error during conversion. Either the BCD was too ; big (must be 0..65535, Z points to BCD where the ; overflow occurred) or an illegal BCD was detected ; (Z points to the first non-BCD digit). ; Used registers: rBin1H:L (result), R0 (restored after ; use), rBin2H:L (restored after use), rmp ; Called subroutines: Bin1Mul10 ; Bcd5ToBin2: push R0 ; Save register clr rBin1H ; Empty result clr rBin1L

ldi rmp,5 ; Set counter to 5 mov R0,rmp clt ; Clear error flag Bcd5ToBin2a: ld rmp,Z+ ; Read BCD digit cpi rmp,10 ; is it valid? brcc Bcd5ToBin2c ; invalid BCD rcall Bin1Mul10 ; Multiply result by 10 brts Bcd5ToBin2c ; Overflow occurred add rBin1L,rmp ; add digit brcc Bcd5ToBin2b ; No overflow to MSB inc rBin1H ; Overflow to MSB breq Bcd5ToBin2c ; Overflow of MSB Bcd5ToBin2b: dec R0 ; another digit? brne Bcd5ToBin2a ; Yes pop R0 ; Restore register sbiw ZL,5 ; Set to first BCD digit ret ; Return Bcd5ToBin2c: sbiw ZL,1 ; back one digit pop R0 ; Restore register set ; Set T-flag, error ret ; and return ; ; Bin1Mul10 ; ========= ; multiplies a 16-bit-binary by 10 ; Sub used by: AscToBin2, Asc5ToBin2, Bcd5ToBin2 ; In: 16-bit-binary in rBin1H:L ; Out: T-flag shows general result: ; T=0: Valid result, 16-bit-binary in rBin1H:L ok ; T=1: Overflow occurred, number too big ; Bin1Mul10: push rBin2H ; Save the register of 16-bit-binary 2 push rBin2L mov rBin2H,rBin1H ; Copy the number mov rBin2L,rBin1L add rBin1L,rBin1L ; Multiply by 2 adc rBin1H,rBin1H brcs Bin1Mul10b ; overflow, get out of here Bin1Mul10a: add rBin1L,rbin1L ; again multiply by 2 (4*number reached) adc rBin1H,rBin1H brcs Bin1Mul10b ; overflow, get out of here add rBin1L,rBin2L ; add the copied number (5*number reached) adc rBin1H,rBin2H brcs Bin1Mul10b ;overflow, get out of here add rBin1L,rBin1L ; again multiply by 2 (10*number reached) adc rBin1H,rBin1H brcc Bin1Mul10c ; no overflow occurred, don't set T-flag Bin1Mul10b: set ; an overflow occurred during multplication Bin1Mul10c: pop rBin2L ; Restore the registers of 16-bit-binary 2 pop rBin2H ret ; ; *************************************************

; ; Package II: From binary to ASCII resp. BCD ; ; Bin2ToAsc5 ; ========== ; converts a 16-bit-binary to a 5 digit ASCII-coded decimal ; In: 16-bit-binary in rBin1H:L, Z points to the highest ; of 5 ASCII digits, where the result goes to ; Out: Z points to the beginning of the ASCII string, lea; ding zeros are filled with blanks ; Used registers: rBin1H:L (content is not changed), ; rBin2H:L (content is changed), rmp ; Called subroutines: Bin2ToBcd5 ; Bin2ToAsc5: rcall Bin2ToBcd5 ; convert binary to BCD ldi rmp,4 ; Counter is 4 leading digits mov rBin2L,rmp Bin2ToAsc5a: ld rmp,z ; read a BCD digit tst rmp ; check if leading zero brne Bin2ToAsc5b ; No, found digit >0 ldi rmp,' ' ; overwrite with blank st z+,rmp ; store and set to next position dec rBin2L ; decrement counter brne Bin2ToAsc5a ; further leading blanks ld rmp,z ; Read the last BCD Bin2ToAsc5b: inc rBin2L ; one more char Bin2ToAsc5c: subi rmp,-'0' ; Add ASCII-0 st z+,rmp ; store and inc pointer ld rmp,z ; read next char dec rBin2L ; more chars? brne Bin2ToAsc5c ; yes, go on sbiw ZL,5 ; Pointer to beginning of the BCD ret ; done ; ; Bin2ToAsc ; ========= ; converts a 16-bit-binary to a 5-digit ASCII coded decimal, ; the pointer points to the first significant digit of the ; decimal, returns the number of digits ; In: 16-bit-binary in rBin1H:L, Z points to first digit of ; the ASCII decimal (requires 5 digits buffer space, even ; if the number is smaller!) ; Out: Z points to the first significant digit of the ASCII ; decimal, rBin2L has the number of characters (1..5) ; Used registers: rBin1H:L (unchanged), rBin2H (changed), ; rBin2L (result, length of number), rmp ; Called subroutines: Bin2ToBcd5, Bin2ToAsc5 ; Bin2ToAsc: rcall Bin2ToAsc5 ; Convert binary to ASCII ldi rmp,6 ; Counter is 6 mov rBin2L,rmp Bin2ToAsca: dec rBin2L ; decrement counter ld rmp,z+ ; read char and inc pointer cpi rmp,' ' ; was a blank?

breq Bin2ToAsca ; Yes, was a blank sbiw ZL,1 ; one char backwards ret ; done ; ; Bin2ToBcd5 ; ========== ; converts a 16-bit-binary to a 5-digit-BCD ; In: 16-bit-binary in rBin1H:L, Z points to first digit ; where the result goes to ; Out: 5-digit-BCD, Z points to first BCD-digit ; Used registers: rBin1H:L (unchanged), rBin2H:L (changed), ; rmp ; Called subroutines: Bin2ToDigit ; Bin2ToBcd5: push rBin1H ; Save number push rBin1L ldi rmp,HIGH(10000) ; Start with tenthousands mov rBin2H,rmp ldi rmp,LOW(10000) mov rBin2L,rmp rcall Bin2ToDigit ; Calculate digit ldi rmp,HIGH(1000) ; Next with thousands mov rBin2H,rmp ldi rmp,LOW(1000) mov rBin2L,rmp rcall Bin2ToDigit ; Calculate digit ldi rmp,HIGH(100) ; Next with hundreds mov rBin2H,rmp ldi rmp,LOW(100) mov rBin2L,rmp rcall Bin2ToDigit ; Calculate digit ldi rmp,HIGH(10) ; Next with tens mov rBin2H,rmp ldi rmp,LOW(10) mov rBin2L,rmp rcall Bin2ToDigit ; Calculate digit st z,rBin1L ; Remainder are ones sbiw ZL,4 ; Put pointer to first BCD pop rBin1L ; Restore original binary pop rBin1H ret ; and return ; ; Bin2ToDigit ; =========== ; converts one decimal digit by continued subraction of a ; binary coded decimal ; Used by: Bin2ToBcd5, Bin2ToAsc5, Bin2ToAsc ; In: 16-bit-binary in rBin1H:L, binary coded decimal in ; rBin2H:L, Z points to current BCD digit ; Out: Result in Z, Z incremented ; Used registers: rBin1H:L (holds remainder of the binary), ; rBin2H:L (unchanged), rmp ; Called subroutines: ; Bin2ToDigit: clr rmp ; digit count is zero Bin2ToDigita: cp rBin1H,rBin2H ; Number bigger than decimal? brcs Bin2ToDigitc ; MSB smaller than decimal

brne Bin2ToDigitb ; MSB bigger than decimal cp rBin1L,rBin2L ; LSB bigger or equal decimal brcs Bin2ToDigitc ; LSB smaller than decimal Bin2ToDigitb: sub rBin1L,rBin2L ; Subtract LSB decimal sbc rBin1H,rBin2H ; Subtract MSB decimal inc rmp ; Increment digit count rjmp Bin2ToDigita ; Next loop Bin2ToDigitc: st z+,rmp ; Save digit and increment ret ; done ; ; ************************************************** ; ; Package III: From binary to Hex-ASCII ; ; Bin2ToHex4 ; ========== ; converts a 16-bit-binary to uppercase Hex-ASCII ; In: 16-bit-binary in rBin1H:L, Z points to first ; position of the four-character Hex-ASCII ; Out: Z points to the first digit of the four-character ; Hex-ASCII, ASCII digits A..F in capital letters ; Used registers: rBin1H:L (unchanged), rmp ; Called subroutines: Bin1ToHex2, Bin1ToHex1 ; Bin2ToHex4: mov rmp,rBin1H ; load MSB rcall Bin1ToHex2 ; convert byte mov rmp,rBin1L rcall Bin1ToHex2 sbiw ZL,4 ; Set Z to start ret ; ; Bin1ToHex2 converts an 8-bit-binary to uppercase hex ; Called by: Bin2ToHex4 ; Bin1ToHex2: push rmp ; Save byte swap rmp ; upper to lower nibble rcall Bin1ToHex1 pop rmp ; Restore byte Bin1ToHex1: andi rmp,$0F ; mask upper nibble subi rmp,-'0' ; add 0 to convert to ASCII cpi rmp,'9'+1 ; A..F? brcs Bin1ToHex1a subi rmp,-7 ; add 7 for A..F Bin1ToHex1a: st z+,rmp ; store in target ret ; and return ; ; ******************************************* ; ; Package IV: From Hex-ASCII to binary ; ; Hex4ToBin2 ; converts a 4-digit-hex-ascii to a 16-bit-binary ; In: Z points to first digit of a Hex-ASCII-coded number ; Out: T-flag has general result:

; T=0: rBin1H:L has the 16-bit-binary result, Z points ; to the first digit of the Hex-ASCII number ; T=1: illegal character encountered, Z points to the ; first non-hex-ASCII character ; Used registers: rBin1H:L (result), R0 (restored after ; use), rmp ; Called subroutines: Hex2ToBin1, Hex1ToBin1 ; Hex4ToBin2: clt ; Clear error flag rcall Hex2ToBin1 ; convert two digits hex to Byte brts Hex4ToBin2a ; Error, go back mov rBin1H,rmp ; Byte to result MSB rcall Hex2ToBin1 ; next two chars brts Hex4ToBin2a ; Error, go back mov rBin1L,rmp ; Byte to result LSB sbiw ZL,4 ; result ok, go back to start Hex4ToBin2a: ret ; ; Hex2ToBin1 converts 2-digit-hex-ASCII to 8-bit-binary ; Called By: Hex4ToBin2 ; Hex2ToBin1: push R0 ; Save register rcall Hex1ToBin1 ; Read next char brts Hex2ToBin1a ; Error swap rmp; To upper nibble mov R0,rmp ; interim storage rcall Hex1ToBin1 ; Read another char brts Hex2ToBin1a ; Error or rmp,R0 ; pack the two nibbles together Hex2ToBin1a: pop R0 ; Restore R0 ret ; and return ; ; Hex1ToBin1 reads one char and converts to binary ; Hex1ToBin1: ld rmp,z+ ; read the char subi rmp,'0' ; ASCII to binary brcs Hex1ToBin1b ; Error in char cpi rmp,10 ; A..F brcs Hex1ToBin1c ; not A..F cpi rmp,$30 ; small letters? brcs Hex1ToBin1a ; No subi rmp,$20 ; small to capital letters Hex1ToBin1a: subi rmp,7 ; A..F cpi rmp,10 ; A..F? brcs Hex1ToBin1b ; Error, is smaller than A cpi rmp,16 ; bigger than F? brcs Hex1ToBin1c ; No, digit ok Hex1ToBin1b: ; Error sbiw ZL,1 ; one back set ; Set flag Hex1ToBin1c: ret ; Return

Vous aimerez peut-être aussi