Author Topic: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle  (Read 3336 times)

0 Members and 1 Guest are viewing this topic.

Offline rollingstoneTopic starter

  • Contributor
  • Posts: 19
Hello everyone.
I'm kind of newbie in MCU programming, and recently I was doing something with 8 bit PIC18 micro, and wanted to do a MCU runtime counter.

When it is powered on, every second interrupt is fired and 1st register counts seconds from 0 to 3Ch (60d). 2'nd register counts minutes (0 to 3Ch). 3'rd register count hours 0 to 18h (24d). and 4'th register counts days 0 - FFh.

MCU runtime is saved to EEPROM every minute. Also I wanted to send this information to USART by typing some command. But instead of hex numbers I wanted to see decimal numbers in terminal. So I made a look-up table where values from all 5 registers was converted to ASCII coded decimal numbers.

Table was for numbers 0d - 255d (this is kind of bulky I think). For ex minutes in hex 37h was decoded in table and sent to USART as ASCII number "055" ("\x30\x35\x35\r\n").

I wanted to get rid of that bulky table. So next step was to make some kind of HEX to DEC converter. And Now my ASCII look-up table shrinked to ten entries (for numbers 0 to 9) and it could decode numbers from 0h to FFh. I know there are ready HEC to DEC converters in C language, but as i am still learning many things, I wanted to get some practice in assembly and made my own converter (which I did).

And it works by taking hex number in WREG, converting it to decimal equivalent and putting out to three registers. Then it is possible to use ASCII look up table and to send it to USART. For ex number 0Eh is converted to 0, 1, 4 or number FFh to 2, 5, 5. I attach algorithm of this converter in PDF file. And if someone thinks it's not that useless and may be needs something like this in assembly language for PIC18 I will post code here.

And finally my question. This converter is usable only in range of numbers 0h - FFh (which is good for converting minutes or hours (max value 60d)). But I thought it would be nice to make (or just to understand how it works) another one for numbers in range of FFh to FF FFh or even to FF FF FFh. For example if I want to send 4 byte data from sensor to USART and display it in decimal format.

I know one can use 32 bit MCU and C for this task and something like that and some ready available solutions and don't bother. But I don't need it for anything right now. This is like interesting puzzle to me and I'm just curious and want to understand how this can be accomplished (I am trying to do it in assembly for 8 bit MCU). Does anyone know some sort of algorithm or equation? is it possible to do it using standard math functions like add, subtract, multiply which are available in PIC18. I tried to think of it myself but for now nothing simple and elegant comes to my mind and my algorithm is too complex. Also I done a lot of searching and nothing. And yes I know how to do it easily using calculator or (sometimes) my brain which is decimal (most of the time) :)
« Last Edit: July 18, 2016, 06:58:13 pm by rollingstone »
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle
« Reply #1 on: July 18, 2016, 07:25:29 pm »
That's an odd way of approaching the problem.

Here is what I would do.

Declare a 32bit type, and increment it every second. When you want to communicate it's value via uart, convert that to a string type of your choosing.
================================
https://dannyelectronics.wordpress.com/
 
The following users thanked this post: rollingstone

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle
« Reply #2 on: July 18, 2016, 07:55:28 pm »
Don't you want the seconds and minutes to go from 0 to 59? (00h to 3Bh)

And this might be quicker than using division, if your MCU doesn't have fast division.

Code: [Select]
#include <stdio.h>

/* Byte to ASCII */
void btoa(unsigned char i) {
   char out[4];
   out[0] = '0';
   out[1] = '0';
   out[2] = '0';
   out[3] = '\0';   

   /* Hundreds */
   while(i > 99) {
      out[0]++;
      i -= 100;
   }

   /* tens */
   while(i > 9) {
      out[1]++;
      i -= 10;
   }

   /* units */
   while(i != 0) {
      out[2]++;
      i--;
   }
   printf("Value was %s",out);
}
int main(int argc, char *argv[]) {
   int i;
   if(argc > 1)
     i = atoi(argv[1]);
   btoa((unsigned char)i);
}
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 
The following users thanked this post: rollingstone

Offline picandmix

  • Frequent Contributor
  • **
  • Posts: 395
  • Country: gb
Re: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle
« Reply #3 on: July 18, 2016, 08:00:37 pm »
Its always good to write your own subroutines.

There are many ways to create Ascii from Hex  but this site has lots of such examples including various math solutions.
http://www.piclist.com/tecHREF/microchip/math/radix/index.htm

Also a simple but quick  method for doing fixed delays, but remove the $ instruction and replace with labels as those dealys are made for the 16F series, whereas the 18F different in respect of the $  - let you find that one out yourself.
http://www.golovchenko.org/cgi-bin/delay

Attached is a typical delay and 2 / 3 character acscii converters, though you will find 4 + digit ones in piclist.

Forgot to add this screenshot from the Pic18F4520 datasheet which shows how to create a RTC using a 32khz crystal, if you want its accuaracy.

Congrats on using  a flow chart, an invaluable tool imho, wish more folk would use them rather than just jumping in.
By the same token, always add lots of comments to your code, it may seem like simple code now , but in a few months or years time, when looking back you may wonder how it works.
« Last Edit: July 18, 2016, 08:08:34 pm by picandmix »
 
The following users thanked this post: rollingstone

Offline Maxlor

  • Frequent Contributor
  • **
  • Posts: 565
  • Country: ch
Re: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle
« Reply #4 on: July 18, 2016, 09:00:09 pm »
A small detail: you don't need to use use a lookup table to get the ascii values for decimal digits, instead use ascii_value = 48 + digit_value , which is faster and uses less memory.
 
The following users thanked this post: rollingstone, Kilrah

Offline rollingstoneTopic starter

  • Contributor
  • Posts: 19
Re: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle
« Reply #5 on: July 21, 2016, 12:55:07 pm »

And this might be quicker than using division, if your MCU doesn't have fast division.

Code: [Select]
#include <stdio.h>

/* Byte to ASCII */
void btoa(unsigned char i) {
   char out[4];
   out[0] = '0';
   out[1] = '0';
   out[2] = '0';
   out[3] = '\0';   

   /* Hundreds */
   while(i > 99) {
      out[0]++;
      i -= 100;
   }

   /* tens */
   while(i > 9) {
      out[1]++;
      i -= 10;
   }

   /* units */
   while(i != 0) {
      out[2]++;
      i--;
   }
   printf("Value was %s",out);
}
int main(int argc, char *argv[]) {
   int i;
   if(argc > 1)
     i = atoi(argv[1]);
   btoa((unsigned char)i);
}
Thanx hamster_nz, but could you explain your code? I'm still not very clear what it does, (I touched modified C code when I was working with MatLab long time ago, now I forgot a lot)
 

Offline rollingstoneTopic starter

  • Contributor
  • Posts: 19
Re: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle
« Reply #6 on: July 21, 2016, 12:57:38 pm »
A small detail: you don't need to use use a lookup table to get the ascii values for decimal digits, instead use ascii_value = 48 + digit_value , which is faster and uses less memory.
Thanx Maxlor  :-+ , this somehow didn't came to my mind, now i modiefied my code :)
 

Offline android

  • Regular Contributor
  • *
  • Posts: 134
  • Country: au
Re: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle
« Reply #7 on: July 21, 2016, 01:44:25 pm »
ascii_value = 48 + digit_value
...or even
Code: [Select]
ascii_value = '0' + digit_value...which has the added bonus of relieving the reader of having to know what the magic number 48 means.  :)
Lecturer: "There is no language in which a double positive implies a negative."
Student:  "Yeah...right."
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3461
  • Country: it
Re: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle
« Reply #8 on: July 21, 2016, 05:44:03 pm »
Thanx hamster_nz, but could you explain your code? I'm still not very clear what it does, (I touched modified C code when I was working with MatLab long time ago, now I forgot a lot)
an unsigned char is a 8 bit variable, no sign, so it can store numbers from 0 do 255, right?
okay. now let's say you want to convert the number 123 into a string. this number is
1 hundred
2 tens
3 units, or 1 * 100 + 2 * 10 + 3 * 1.
To know how many "hundreds" there are i check if the number is greater than 99, in that case i add 1 into my "hundred" variable and subtract 100 to the initial number.
Then, when i have no "hundreds" left i check the tens. same principle, while the number is greater than 9 i have at least one more "ten" so i increment my "ten" variable and subtract 10 from the number.
in the end i will be left with the digits.
then i convert them into ascii characters for numbers by adding 48 or, as someone pointed out, adding the character '0'
'0' is 48 in ASCII
'1' is 49
'2' is 50
...
i think you got it
 

Offline rollingstoneTopic starter

  • Contributor
  • Posts: 19
Re: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle
« Reply #9 on: July 22, 2016, 12:06:57 pm »
Its always good to write your own subroutines.

There are many ways to create Ascii from Hex  but this site has lots of such examples including various math solutions.
http://www.piclist.com/tecHREF/microchip/math/radix/index.htm


Thanx picandmix, This is awesome resource,  :-+ I have studied most of these examples, some ideas came to my mind and now I'm trying to do my own code. And somehow I didn't knew  :palm:  that the thing I'm trying to accomplish is called Hex to BCD conversion. Now everything is clear, There are tons of examples and literature on this subject.
Congrats on using  a flow chart, an invaluable tool imho, wish more folk would use them rather than just jumping in.
And yes, I always do a flowchart first, it really save tons of time. It looks like human brain works better (at least mine does) when you are thinking in terms of "graphical objects" and draw a schematic, then "simulate" it using pencil or whatever following lines and arrows, correct mistakes and then convert it into code rather than trying to do it in code straight away.
always add lots of comments to your code, it may seem like simple code now , but in a few months or years time, when looking back you may wonder how it works.
I saw that, how a programmer spends a week trying to understand how his code works after 5 years  |O  . I usually add comment after each line.
 

Offline rollingstoneTopic starter

  • Contributor
  • Posts: 19
Re: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle
« Reply #10 on: July 22, 2016, 12:08:12 pm »
i think you got it
I really did, thanx  :-+
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle
« Reply #11 on: July 22, 2016, 03:18:02 pm »
My solution would be a little bit like this:

Code: [Select]
volatile uint32_t _second_cnt=0;  //second counter, incremented every second in an isr

  tmp0 = _second_cnt; //save second counter
  //process second
  tmp = tmp0 % 60; tmp0 /= 60; //generate seconds, update tmp0
  ultoa(&vRAM[16], tmp, 2); //convert and store the second into a string positioned from 15/16
  //process minute
  tmp = tmp0 % 60; tmp0 /= 60; //genearate minute, update tmp0
  ultoa(&vRAM[13], tmp, 2); //convert and store the minute string positioned from 12/13
  //process hour
  tmp = tmp0 % 24; tmp0 /= 24; //generate hour, update tmp0
  ultoa(&vRAM[10], tmp, 2); //convert and store the hours into a string positioned from 9/10
  //process day
  tmp = tmp0 % 1000;  //max of 999 days
  ultoa(&vRAM[7], tmp, 3); //convert and store the day value into a string positioned from 5/6/7


ultoa() is fairly easy to write. The whole thing should fit within 100 - 200 bytes.

If your chip is sufficiently large and you are already using printf(), use it as well.
================================
https://dannyelectronics.wordpress.com/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf