.

INCLUDES RFID interfacing with avr GPS interfacing with avr RF Module interfacing with avr Stepper Motor With AVR

Tuesday, December 20, 2011

CONVERSIONS

Converting Int to ASCII Coded Decimal
Converting integers to ASCII coded decimal is pretty simple. To understand how it is done, you first have to think about how the numbers we're using in written documents are built up:
Let's take the number 233 and rip it apart:
Multiply number with
100
10
1
decimal
2
3
3
result
200
30
3
These add up to 233. The number consists of single digits which specifiy the number of hundreds, tens, and ones we add together.
To get these results, we need to divide the number; first by 100, then by 10 and then by 1. As the AVR doesn't have a divide instruction, this has to be done manually:
Divide by 100:
- copy the number into a temporary register
- compare the number with 100
- if greater or equal, increase the hundreds count and subtract 100 from the temporary register
- go to the compare again
When this is done, the number in the temporary register is lower than 100. Now we can proceed with 10s and 1s. Instead of dividing it by 1 we can just copy the remaining number to the register that holds the ones.
Unfortunately, this is not enough to convert a number to decimal coded ASCII. In an ASCII table we can see that '0' is 0x30. So we add 0x30 to the single digits (hundreds, tens, ones) and can now print it on the screen (via UART, USB, LCD interface, whatever).
It's now also possible to reformat the number, delete characters we don't need (print a space instead of 0 hundreds if the number was lower than 100) or add additional characters in between.
Here's a flow chart of how the conversion can be done:

It should be pretty easy for you to write the code for this yourself.
Doing this with a 16-bit number is just the same, but with 5 digits and 16-bit compares. The code space needed (as well as cpu time) is 40% bigger. If you have a lot of free program space, you can build up a case-like structure to do the conversion: If the number is greater than 200, the hundreds counter is loaded with 2 and 200 is subtracted from the original number. This is faster but requires more space. It's up to you.

Converting Int to ASCII Coded Hex
This conversion is a bit more difficult than int to ASCII coded decimal, as you don't only have to display numbers, but characters as well. In the ASCII table, these are not found directly after the numbers.
However, the first task is to load the two nibbles that make up to an 8 bit integer into separate registers:

The reason why you have to swap the nibbles in reg A is that the register holding the high nibble should have a value between 0x00 and 0x0F (15). If we didn't swap the nibbles, their value would be 0x00..0xF0 which we can't convert to ASCII.
Now we have two nibbles, each in a separate register, which are between 0x00 (0) and 0x0F (15). These must now be converted into their ASCII representative: For 0 it's '0', for 10 it's 'A' and for 15 it's 'F'. This can be done with a lookup table or by using a case structure.
A lookup table for this would have the ASCII values of the possible nibble values at the nibble positions:
Table Position:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Nibble value:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ASCII:
'0'
'1'
'2'
'3'
'4'
'5'
'6'
'7'
'8'
'9'
'A'
'B'
'C'
'D'
'E'
'F'
The conversion only consists of replacing the register value by a corresponding table value (which is the overall concept of a lookup table).
When this is done and the number we had was 128, we now have reg A holding '8' and reg B holding '0' because 128 is 0x80.
Converting 16-bit numbers from int to ASCII coded hex is not much harder. The result needs 4 registers and we need to convert two ints without having to use any 16-bit instructions:
1024 (hex 0x0400) converts to '0' and '4' for the high byte and '0' and '0' for the low byte.


Converting ASCII Coded Decimal to INT
Ascii Coded Decimal strings are, for example, used in the Ymodem protocol for sending file size information. To use that string as a file size it has to be converted to an integer in order to be processed fast and code-efficient.
The conversion is not as straight-forward as others, as the string length has to be taken into account:
'512' has a length of 3 characters, and therefore the '5' means 500, and not 50 or 5. As the most significant digits are usually sent first, the string is not too hard to be converted. If the least significant digit is sent first the string has to be stored first and can't be processed byte for byte.
Given that the most significant digit is sent first, the following steps are necessary for each character received:

For the '512' string, this happens:
'5' is converted to 5 by subtracting ASCII '0' from '5'. Then the result (which is still zero) is multiplied by 10. The result is zero.
Now 5 is added. Result = 5
Now the '1' is received and converted to 1. The result (which is 5) is multiplied by 10, so we now have 50.
1 is added which equals 51.
The '2', being the last character of the string, is again converted, the result is pultiplied by 10 (=510) and 2 is added. The result is 512. Easy huh?
The only thing I didn't mention until now is how to determine when the string ends. This depends on the transmitter or source of the string. If it is a null-terminated string, we can use the following program flow:



Converting ASCII Coded Hex to Int
For the conversion from ASCII coded hex to int we first need some code that converts one ASCII character (which represents one hex nibble) to its decimal value. 'A' -> 10. This can't (or shouldn't) be done with a lookup table, because the ASCII value of 'A' is bigger than the size of efficient code doing the same thing. Therefore, the lookup table would also be quite big. So, it's better to choose the case structure.
Then the second nibble is converted in the same way and the two nibbles are combined to form one int.

This conversion is done for the two nibble characters. These are then combined in one byte:

Maybe the nibbles have to be swapped again, depending on how the two nibbles were sent: If the high nibble was sent first, the received byte can left as it is: The high nibble was added, the nibbles were swapped and then the low nibble was added.
Consequently, if the low nibble is sent first, the nibbles have to be swapped again.

No comments:

Post a Comment