HEX to DEC converter algorithm for 2-5 bytes on 8 bit MCU puzzle - Page 1
Forum section: electronics / general

author: rollingstone
author_rank: Contributor
timestamp: July 18, 2016, 06:53:57 pm
content: 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)

author: dannyf
author_rank: Super Contributor
timestamp: July 18, 2016, 07:25:29 pm
content: 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.

author: hamster_nz
author_rank: Super Contributor
timestamp: July 18, 2016, 07:55:28 pm
content: 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:#include <stdio.h>/* Byte to ASCII */void btoa(unsigned char i) {char out;out = '0';out = '0';out = '0';out = '\0';/* Hundreds */while(i > 99) {out++;i -= 100;}/* tens */while(i > 9) {out++;i -= 10;}/* units */while(i != 0) {out++;i--;}printf("Value was %s",out);}int main(int argc, char *argv[]) {int i;if(argc > 1)i = atoi(argv);btoa((unsigned char)i);}

author: picandmix
author_rank: Frequent Contributor
timestamp: July 18, 2016, 08:00:37 pm
content: 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.htmAlso 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/delayAttached 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.

author: Maxlor
author_rank: Frequent Contributor
timestamp: July 18, 2016, 09:00:09 pm
content: A small detail: you don't need to use use a lookup table to get the ascii values for decimal digits, instead useascii_value = 48 + digit_value, which is faster and uses less memory.

author: rollingstone
author_rank: Contributor
timestamp: July 21, 2016, 12:55:07 pm
content: Quote from: hamster_nz on July 18, 2016, 07:55:28 pmThanx 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)

author: rollingstone
author_rank: Contributor
timestamp: July 21, 2016, 12:57:38 pm
content: Quote from: Maxlor on July 18, 2016, 09:00:09 pmThanx Maxlor, this somehow didn't came to my mind, now i modiefied my code

author: android
author_rank: Regular Contributor
timestamp: July 21, 2016, 01:44:25 pm
content: Quote from: Maxlor on July 18, 2016, 09:00:09 pm...or evenCode:ascii_value = '0' + digit_value...which has the added bonus of relieving the reader of having to know what the magic number 48 means.

author: JPortici
author_rank: Super Contributor
timestamp: July 21, 2016, 05:44:03 pm
content: Quote from: rollingstone on July 21, 2016, 12:55:07 pman 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 is1 hundred2 tens3 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

author: rollingstone
author_rank: Contributor
timestamp: July 22, 2016, 12:06:57 pm
content: Quote from: picandmix on July 18, 2016, 08:00:37 pmThanx 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 knewthat 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.Quote from: picandmix on July 18, 2016, 08:00:37 pmAnd 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.Quote from: picandmix on July 18, 2016, 08:00:37 pmI saw that, how a programmer spends a week trying to understand how his code works after 5 years. I usually add comment after each line.

author: rollingstone
author_rank: Contributor
timestamp: July 22, 2016, 12:08:12 pm
content: Quote from: JPortici on July 21, 2016, 05:44:03 pmI really did, thanx

author: dannyf
author_rank: Super Contributor
timestamp: July 22, 2016, 03:18:02 pm
content: My solution would be a little bit like this:Code:volatile uint32_t _second_cnt=0; //second counter, incremented every second in an isrtmp0 = _second_cnt; //save second counter//process secondtmp = tmp0 % 60; tmp0 /= 60; //generate seconds, update tmp0ultoa(&vRAM, tmp, 2); //convert and store the second into a string positioned from 15/16//process minutetmp = tmp0 % 60; tmp0 /= 60; //genearate minute, update tmp0ultoa(&vRAM, tmp, 2); //convert and store the minute string positioned from 12/13//process hourtmp = tmp0 % 24; tmp0 /= 24; //generate hour, update tmp0ultoa(&vRAM, tmp, 2); //convert and store the hours into a string positioned from 9/10//process daytmp = tmp0 % 1000; //max of 999 daysultoa(&vRAM, tmp, 3); //convert and store the day value into a string positioned from 5/6/7ultoa() 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.