Path: Home => AVR-overview => Binary calculations => Conversions    (Diese Seite in Deutsch: )

# Number format conversion in AVR assembler

Converting numbers is very often used in assembler, because processors prefer calculating in binary, while people on a terminal prefer decimal numbers. If one has to communicate from within an assembler routine with one of the human species, number conversion is a must. This page provides some basic know how on number conversion. Learn a bit more in detail, how conversion between different number systems is done.

For those who prefer going directly to the source code, here is the link to the HTML version and the link to the asm version of the source code.

## Number format basics

The number systems discussed here ar:
• Decimal: Each byte represents a decimal digit, coded in ASCII. Decimal 48 or binary \$30 represents the digit 0, decimal 49 the digit 1, and so on to 57, which represents a 9. Other numbers, from 0 to 47 and from 58 to 255, do not represent correct digits. (Why 0 is 48, and not 0, can only be understood historically, it reaches back to the times of US military teletype machines, but this is another long story).
• BCD-numbers: BCD means Binary Coded Decimal. It's like decimal ASCII, but the decimal digit zero here is indeed 0. BCDs reach from 0 to 9. Numbers greater than 9 (that is 10 to 255) are illegal and not BCD.
• Binary numbers: Here only the digits 0 and 1 are used. Read from the least significant bit, the value of the digits doubles, so the binary 1011 is equal 1*(2 ** 0) + 1*(2 ** 1) + 0*(2 ** 2) + 1*(2 ** 3). Just like decimal 1234 is equal to 4*(10 ** 0) + 3*(10 ** 1) + 2*(10 ** 2) + 1*(10 ** 3). (By the way: each number ** 0 is 1, except 0 ** 0, which is not known exactly). Binary numbers are handled in packages of 4 (called nibble), 8 (called Byte) or 16 (called word), because single bits are very small numbers and e.g. do not allow to buy five apples (needs a package of three bits).
• Hex numbers: Hex numbers are packages of four single bits. These four bits represent 16 different hex digits. The first ten are named like their decimal relatives, but the digits 10 to 15 are named A to F. As string of ASCII-coded hex digits this is rather unlucky, because the ASCII representation of the 9 is 57, of the A is 65. If you prefer using a..f for the additional six digits in hex, the ASCII representation is even 97. This is relevant for number conversions, because these hex digits are distributed over the ASCII character table, complicating conversion.
So far the number format basics.

## General rules of the assembler routines

The AVR assembler software for conversion has to be somehow flexible to apply in different situations. So it is better to spent some thinking before writing it. I have adopted some rules in writing this source code. Here are the rules:
• Binary numbers: All binaries are designed for 16 Bit, with values between 0 and 65,535. They are generally located in the register pair rBin1H (upper 8 bits, MSB) and rBin1L (lower 8 bits, LSB). This binary word is abbreviated as rBin1H:L. Preferred location for this word are the registers R2 and R1, but it doesn't really matter, where and in which order you place it. Some conversions require a second register pair, named rBin2H:L. You can place it in the registers R4 and R3. Generally the values in this register pair are restored after use, so you can use it for other purposes, too, without the risk of a conflict.
• BCD- and ASCII-coded numbers: These numbers are most often located somewhere in the SRAM space of the AVR, e.g. in a buffer of incoming characters from the SIO. So these numbers are generally handled with the pointer register Z (pointer register ZH:ZL or R31:R30). The numbers are assumed to be in the following order: The higher the value of the digit the lower the pointer adress. The number 12345 so would be located in SRAM like this: \$0060: 1, \$0061: 2, \$0062: 3, and so on. You can also place the pointer Z to locations in the register space, e.g. to \$0005. The 12345 would then be located like this: R5: 1, R6: 2, and so on. The conversion software so works as well in the register space, if you place the digits in that order to the registers. No need to write a special conversion routine for the register space. But beware of pointer bugs: the software overwrites registers without asking you. You can even overwrite the pointer registers ZH:ZL. What happens then is rather unknown. Thorough planning of the register space is a must, if you use that routines in register space.
• Packaging: Because not all conversion routines are necessary, I have packed the routines into four packages. The last two packages are only dedicated to hex conversions. The first package converts ASCII- and BCD-numbers to binaries, package II converts binaries to ASCII and BCD. Each package with the called subroutines in it runs separately. If you remove parts of the package content, be sure to keep the appropriated subroutines. The whole four packages compile to 217 words of program space.
• Errors: If a number conversion leads to an error, the T-flag is set to one. The T-flag can be used to react to an error, e.g. by using the branch instructions BRTS and BRTC. If you need the T-flag for other purposes, feel free to exchange the respective lines with the instructions SET, CLT, BRTS and BRTC to use a bit somewhere in a register. If an error is encountered the pointer Z points to the point of error. If the error is caused by an illegal character, it points to that character. If the error is an overflow error, the pointer points to the digit, where the error occurred.
• Other rules: Further details on the different routines are listed in the general part of the source code. There you'll find a overview on all rountines, showing all available functions, their calling conditions and their error cases.

## From ASCII to binary

The routine AscToBin2 is suitable for converting ASCII-coded numbers in buffers. It reads over leading blanks and zeros and stops conversion on the first non-decimal digit read. The length of the number is limited to the 16-bit long result registers. Numbers that exceed 65,535 cause an error with the T-flag set and Z placed on the first digit that exceeds the 16-bit limit.

If the length of the ASCII number is exactly five digits, you can use the routine Asc5ToBin2. Every illegal character causes an error, except leading blanks and zeros.

Conversion is done from the left to the right of the number. Each additional digit causes a multiplication of the result by 10, followed by adding the digit to the result. The routine is somewhat slow due to the multiplication by 10. There sure are quicker methods to do the conversion job. But this one is easy to understand.

## From BCD to binary

Conversion of BCDs to binary is similiar to ASCII conversion, so we do not discuss this routine in detail. See the source code of this routine for additional comments.

## Binary multiplication by 10

This routine Bin1Mul10 multiplies a 16-bit-binary in rBin1H:L by 10. To do that, the binary is copied to another location, added two times with itself, then the copy is added, and another addition with itself yields the tenfold. As during each step of adding an overflow of the 16-bit-binary can occur, the detection of the overflow and the following reaction cause the most time and code of that routine. If you are fine without that level of error detection and if you don't care if your result is ok or if you prefer error detection a different way, you can skip the parts of the routine that branch around. The code will be much shorter and faster then.

## From binary to ASCII

Conversion from binary to ASCII is done in the routine Bin2ToAsc5. The result is generally five digits long. The conversion is done by a call to the subroutine Bin2ToBcd5. This is discussed more in detail below.

If you use the routine Bin2ToAsc instead, the routine returns with the pointer Z on the first non-zero digit and the number of remaining digits in rBin2L. This is convenient if you have to send the result via SIO to the man behind the terminal without boring him with leading blanks.

## From binary to BCD

Bin2ToBcd5 converts the binary in rBin1H:L to decimal BCD. This conversion is a bit long in code and required time, but sure easier to understand than others. The conversion is done by repeated subtraction of binary representations of the decimal numbers 10,000, 1,000, 100 and 10. Only the remaining one's are treated different!

## From binary to Hex

The routine Bin2ToHex4 produces a four digit Hex-ASCII number from a 16-bit binary in rBin1H:L. Such hex numbers are somewhat easier to read and remember than the binary original. How would you spell 1011011001011110? Hex B65E is a little bit more convenient to remember, nearly like the decimal equivalent 46686.

The routine converts the hex digits A to F in capital letters. If you more like a to f, change the source code accordingly.

## From hex to binary

With Hex4ToBin2 the conversion goes the other way round. Because illegal (non-hex) digits can occur, some code is necessary to detect those errors and signal them in the T-flag.

Zum Seitenanfang