Path: Home => AVR-Overview => Binary calculations => Fixed decimal => 8-bit-conversion    (Diese Seite in Deutsch: )

8-bit binary conversion to 3-digit fixed decimal in AVR Assembler

``````
; Demonstrates floating point conversion
; in Assembler, (C)2003 www.avr-asm-tutorial.net
;
;    analogue-digital-converter, number is in the
;    range from hex 00 to FF.
;    You need to convert this into a floating point
;    number in the range from 0.00 to 5.00 Volt
;
; The program scheme:
;    1. Multiplication by 502 (hex 01F6).
;       That step multiplies by 500, 256 and
;       divides by 255 in one step!
;    2. Round the result and cut the last byte
;       of the result.
;       This step divides by 256 by ignoring the
;       last byte of the result. Before doing
;       that, bit 7 is used to round the result.
;    3. Convert the resulting word to ASCII and set
;       the correct decimal sign
;       The resulting word in the range from 0 to
;       500 is displayed in ASCII-characters as
;       0.00 to 5.00.
;
; The registers used:
;    The routines use the registers R8..R1 without
;    saving these before. Also required is a multi-
;    purpose register called rmp, located in the
;    upper half of the registers. Please take care
;    that these registers don't conflict with the
;    register use in the rest of your program.
;
;    When entering the routine the 8-bit number is
;    expected in the register R1.
;    The multiplication uses R4:R3:R2 to hold
;    the multiplicator 502 (is shifted left
;    max. eight times during multiplication).
;    The result of the multiplication is calculated
;    in the registers R7:R6:R5.
;    The result of the so called division by 256
;    by just ignoring R5 in the result, is in
;    R7:R6. R7:R6 is rounded, depending on the
;    highest bit of R5, and the result is copied to
;    R2:R1.
;    Conversion to an ASCII-string uses the input
;    in R2:R1, the register pair R4:R3 as a divisor
;    for conversion, and places the ASCII result
;    string to R5:R6:R7:R8 (R6 is the decimal char).
;
; Other conventions:
;   The conversion uses subroutines and the stack.
;   The stack must work fine for the use of three
;   levels (six bytes SRAM).
;
; Conversion times:
;   The whole routine requires 228 clock cycles
;   maximum (converting \$FF), and 79 clock cycles
;   minimum (converting \$00). At 4 MHz the times
;   are 56.75 microseconds resp. 17.75 microseconds.
;
; Definitions:
;   Registers
.DEF rmp = R16 ; used as multi-purpose register
;
;   AVR type
;   Tested for type AT90S8515, only required for
;   stack setting, routines work fine with other
;   AT90S-types also
.NOLIST
.INCLUDE "8515def.inc"
.LIST
;
; Start of test program
;
; Just writes a number to R1 and starts the
; conversion routine, for test purposes only
;
.CSEG
.ORG \$0000
rjmp main
;
main:
ldi rmp,HIGH(RAMEND) ; Set the stack
out SPH,rmp
ldi rmp,LOW(RAMEND)
out SPL,rmp
ldi rmp,\$FF ; Convert \$FF
mov R1,rmp
rcall fpconv8 ; call the conversion routine
no_end:   ; unlimited loop, when done
rjmp no_end
;
; Conversion routine wrapper, calls the different conversion steps
;
fpconv8:
rcall fpconv8m ; multiplicate by 502
rcall fpconv8r ; round and divide by 256
rcall fpconv8a ; convert to ASCII string
ldi rmp,'.' ; set decimal char
mov R6,rmp
ret ; all done
;
; Subroutine multiplication by 502
;
; Starting conditions:
; +--+
; |R1|  Input number, example is \$FF
; |FF|
; +--+
; +--+--+--+
; |R4|R3|R2| Multiplicant 502 = \$00 01 F6
; |00|01|F6|
; +--+--+--+
; +--+--+--+
; |R7|R6|R5| Result, as example 128,010
; |01|F4|0A|
; +--+--+--+
;
fpconv8m:
clr R4 ; set the multiplicant to 502
ldi rmp,\$01
mov R3,rmp
ldi rmp,\$F6
mov R2,rmp
clr R7 ; clear the result
clr R6
clr R5
fpconv8m1:
or R1,R1 ; check if the number is all zeros
brne fpconv8m2 ; still one's, go on convert
fpconv8m2:
lsr R1 ; shift number to the right (div by 2)
brcc fpconv8m3 ; if the lowest bit was 0, then skip adding
fpconv8m3:
lsl R2 ; multiply R4:R3:R2 by 2
rol R3
rol R4
rjmp fpconv8m1 ; repeat for next bit
;
; Round the value in R7:R6 with the value in bit 7 of R5
;
fpconv8r:
clr rmp ; put zero to rmp
lsl R5 ; rotate bit 7 to carry
mov R2,R7 ; copy the value to R2:R1 (divide by 256)
mov R1,R6
ret
;
; Convert the word in R2:R1 to an ASCII string in R5:R6:R7:R8
;
; +--+--+
; +R2|R1| Input value 0..500
; +--+--+
; +--+--+
; |R4|R3| Decimal divider value
; +--+--+
; +---+---+---+---+
; | R5| R6| R7| R8| Resulting ASCII string (for input value 5,00)
; |'5'|'.'|'0'|'0'|
; +---+---+---+---+
;
fpconv8a:
clr R4 ; Set the decimal divider value to 100
ldi rmp,100
mov R3,rmp
rcall fpconv8d ; get ASCII digit by repeated subtraction
mov R5,rmp ; set hundreds string char
ldi rmp,10 ; Set the decimal divider value to 10
mov R3,rmp
rcall fpconv8d ; get the next ASCII digit
mov R7,rmp ; set tens string char
ldi rmp,'0' ; convert the rest to an ASCII char
mov R8,rmp ; set ones string char
ret
;
; Convert binary word in R2:R1 to a decimal digit by substracting
; the decimal divider value in R4:R3 (100, 10)
;
fpconv8d:
fpconv8d1:
cp R1,R3 ; Compare word with decimal divider value
cpc R2,R4
brcc fpconv8d2 ; Carry clear, subtract divider value
ret ; done subtraction
fpconv8d2:
sub R1,R3 ; subtract divider value
sbc R2,R4
inc rmp ; up one digit
rjmp fpconv8d1 ; once again
;
; End of floating point conversion routines
;
;
; End of conversion test routine
;
``````