I have my first Assembly program running on an ATmega16 and now I want to convert a decimal number which is saved in a register called speed into a binary form of a hexadecimal number which can be displayed on a 7-seg display. For example speed has saved the decimal 0101 0000 (80) and I want to convert it into the Hex form 0011 0010 (50). How do i do that for any decimal saved in speed?
Thank you for any help you can provide.
Binary and decimal are two different number bases. The normal way1 to have an integer in a register is pure binary, no decimal involved. A decimal or hex representation of that binary number is convenient for humans to look at, but that doesn't change what's actually in the register.
In your case,
0b0101'0000is decimal80, hex0x50; you could write the constant any of those 3 ways in C++ source code. Note that the high 4 bits are0101, binary for5, and the low 4 are0000(0).Base 16 is a power of 2, so 4-bit groups of bits map to hex digits. To get ASCII codes, you could use a lookup table, or add
'0'or'A'depending on whether the nibble value is >= 10 or not. (Or to add an extra7('A' - '0') for numbers above 10, so it's just an if, not if/else). To get 7-segment-display codes, you might use a lookup table indexed by 4-bit integers.In AVR assembly, you can isolate the two 4-bit halves of an 8-bit integer with
andandswapinstructions, like a compiler would make from this source(Godbolt)
The storing is of course optional; if you want to use the values right away, you don't need an array to store them in. That just made it possible to write a C function that produced both outputs so we could look at the compiler-generated asm.
So really it just took
mov+swap+ 2xandiinstructions to isolate the two nibbles which we can then map to hex digits. AVR only has shifts by 1 bit at a time, except forswapwhich rotates by 4. (Thus we have to mask away the high 4 bits to emulate shifting them out.)You never want to have
0011 0010(decimal 50) in a register in the first place: you could get that by multiplying0b0101by ten (0b1010), but the only way you could split it up again into5and0would be dividing by ten (0b1010), which is computationally much more difficult. And it makes no sense, you have hex0x50, not decimal50.Don't do base-conversion by creating a binary integer whose decimal digits are the digits you want for some other base. That won't work for numbers like
0xa5since decimal only allows digits up to 9, and for smaller bases like8or2you can only store at most1111111111in a 32-bit integer, so that's only 10 bits. And it gives you no easy way to get the digits back out when you want to do anything with them.Footnote 1: Computers store everything in bits because they use binary logic, on or off, not 10 or 16 voltage levels. Another way you can use those bits is BCD, Binary Coded Decimal. That's a format where you use 4 bits for every decimal digit, and you have to manually do wrapping and carry-out for digits that become greater than 10 when adding. Or unpacked BCD where you store one decimal digit per byte, saving the unpacking work.