> Hi all,
>
> I need something that would take two ASCII bytes and end up with a Hex value.
>
> For example...
>
> 33, 37 would become 25h (decimal 37)
>
> There are plenty of ASCII to Hex examples but they are a bit simplistic for this case. I thought maybe I could convert the first byte to hex (03h) and multiply that by 10 then add it to the second byte (converted to hex - 07h) to have reach the sum of 37, but there might be a more elegant way...
>
> Any ideas?
Why not just convert the two ascii values to bcd and call one of the bcd to hex
routines?
Scott,
Here is my brute force method for converting a two-byte
ascii decimal representation to the actual binary equivalent.
For example, ascii '3', '7' which is hex 0x33, 0x37
will become binary b'00100101' which is hex 0x25
;enter with ascii_msd and ascii_lsd loaded with ascii
;representation of decimal value to be converted to hex.
;Ascii must be in range 0x30 to 0x39. ( "0" to "9" )
;exit with hex byte in ascii_lsd (or w).
;Numerical value will be between 0 and 99 (decimal).
movlw 0x0f ;set up mask. w has 0x0f
andwf ascii_lsd,f ;ascii_lsd has hex/dec lsd. w has 0x0f
andwf ascii_msd,f ;ascii_msd has hex/dec msd. w has 0x0f
bcf status,c ;carry=0 (so 0 gets rotated in next step)
rlf ascii_msd,w ;w has hex/dec msd*2, and ascii_msd has hex/dec msd
movwf ascii_msd ;w has hex/dec msd*2, and ascii_msd has hex/dec msd*2
rlf ascii_msd,f ;w has hex/dec msd*2, and ascii_msd has hex/dec msd*4
rlf ascii_msd,f ;w has hex/dec msd*2, and ascii_msd has hex/dec msd*8
addwf ascii_msd,w ;w has hex/dec msd*10, and ascii_msd has hex/dec msd*8
addwf ascii_lsd,f ;ascii_lsd has msd*10 + lsd.
;ascii_lsd now contains the desired hex byte
; or use addwf ascii_lsd,w if you want the hex byte in w.
I have an explicit clearing of the carry flag
prior to the rlf instruction. I notice that your (Scott's)
ascii to hex byte solution does not explicity clear the
carry flag. I don't see how you can be *sure* that the carry
is clear prior to your first rlf instruction. Or am I
missing something here?
> Scott,
> Here is my brute force method for converting a two-byte
> ascii decimal representation to the actual binary equivalent.
> For example, ascii '3', '7' which is hex 0x33, 0x37
> will become binary b'00100101' which is hex 0x25
>
> ;enter with ascii_msd and ascii_lsd loaded with ascii
> ;representation of decimal value to be converted to hex.
> ;Ascii must be in range 0x30 to 0x39. ( "0" to "9" )
>
> ;exit with hex byte in ascii_lsd (or w).
> ;Numerical value will be between 0 and 99 (decimal).
>
> movlw 0x0f ;set up mask. w has 0x0f
> andwf ascii_lsd,f ;ascii_lsd has hex/dec lsd. w has 0x0f
> andwf ascii_msd,f ;ascii_msd has hex/dec msd. w has 0x0f
> bcf status,c ;carry=0 (so 0 gets rotated in next step)
> rlf ascii_msd,w ;w has hex/dec msd*2, and ascii_msd has hex/dec msd
> movwf ascii_msd ;w has hex/dec msd*2, and ascii_msd has hex/dec msd*2
> rlf ascii_msd,f ;w has hex/dec msd*2, and ascii_msd has hex/dec msd*4
> rlf ascii_msd,f ;w has hex/dec msd*2, and ascii_msd has hex/dec msd*8
> addwf ascii_msd,w ;w has hex/dec msd*10, and ascii_msd has hex/dec msd*8
> addwf ascii_lsd,f ;ascii_lsd has msd*10 + lsd.
> ;ascii_lsd now contains the desired hex byte
>
> ; or use addwf ascii_lsd,w if you want the hex byte in w.
>
>
> I have an explicit clearing of the carry flag
> prior to the rlf instruction. I notice that your (Scott's)
> ascii to hex byte solution does not explicity clear the
> carry flag. I don't see how you can be *sure* that the carry
> is clear prior to your first rlf instruction. Or am I
> missing something here?
Yes you are (missing something). Immediately following the rlf is an ANDLW
instruction. If the carry is set (before the rlf), then the ANDLW 0x1e will
clear the lsb that got corrupted. At the same time, the RLF clears the carry
because David says the input consist of ASCII encode decimal digits.
Here's the routine again with additional comments:
;ascii1 and ascii2 are the tens and ones digit of a number we wish
;to convert to binary
;
; In C:
;
; binary = (ascii1 & 0xf) * 10 + (ascii2 & 0xf);
;
; (I'd be interested to see how a compiler would generate the asm for this.)
;
movlw 0x0f
andwf ascii2,f ;Clear the upper nibble of the one's digit
; Multiply the ones digit by 10.
rlf ascii1,w ;2*tens
;Note that the carry is also cleared because
;ascii1 is an ASCII number between 0x30-0x39
andlw 0x1e ;Clear upper nibble of tens digit
;In addition, we clear the shifted in carry
movwf ascii1 ;W = ascii1 = 2*original ascii1
rlf ascii1,f ;ascii1 = 4*original ascii1
rlf ascii1,f ;ascii1 = 8*original ascii1
addwf ascii1,w ;W = 2*original ascii1 + 8 *original ascii1
; = 10*original ascii1
addwf ascii2,w ;
> Date: Sat, 1 Apr 2000 22:30:55 +1000
> From: David Thompson <spam_OUTranma21TakeThisOuTEISA.NET.AU>
> Reply-To: pic microcontroller discussion list <.....PICLISTKILLspam@spam@MITVMA.MIT.EDU>
> To: PICLISTKILLspamMITVMA.MIT.EDU
> Subject: Two ASCII bytes to one Hex byte?
>
> Hi all,
>
> I need something that would take two ASCII bytes and end up with a Hex value.
>
> For example...
>
> 33, 37 would become 25h (decimal 37)
>
> There are plenty of ASCII to Hex examples but they are a bit simplistic for this case. I thought maybe I could convert the first byte to hex (03h) and multiply that by 10 then add it to the second byte (converted to hex - 07h) to have reach the sum of 37, but there might be a more elegant way...
>
> Any ideas?
>
> Dave
>
> > I need something that would take two ASCII bytes and end up with
> > a Hex value.
> >
> > For example...
> >
> > 33, 37 would become 25h (decimal 37)
>
> how about:
>
> movlw 15 ; de-ASCIIfy the chars
> andwf char1,f
> andwf char2,f
> swapf char1,w ; w = char1*10
> addwf char1,w
> addwf char1,w
> addwf char2,w ; + char2
Rich:
I assume that the "15" in "movlw 15" is decimal.
Your routine will work for 0-9 [ASCII 30-39], but it fails on A-F
[ASCII 41-46]. Here's a way that works for the whole range:
> Here's a way that works for the whole range:
>
> LIST R = DEC
>
> MOVLW '0'
> BTFSC CHAR1,6
> MOVLW 'A'-10
> SUBWF CHAR1
>
> MOVLW '0'
> BTFSC CHAR2,6
> MOVLW 'A'-10
> SUBWF CHAR2
I don't quite understand this question. ASCII isn't ASCII a 7bit code? meaning
each character is represented with 7 bits and to convert to hex simply interpret
those 7 bits as interpret them as hex correct? which for 2 ASCII bytes would
require 2 bytes. How in your example did you say 33 and 37 becomes 25hex.
This is only one byte of hex to represent 2 bytes of ASCII, not possible.
Please Clarify what's you mean, I'm really curious what I'm missing here.
> > I need something that would take two ASCII bytes and end up with
> > a Hex value.
> >
> > For example...
> >
> > 33, 37 would become 25h (decimal 37)
>
> how about:
>
> movlw 15 ; de-ASCIIfy the chars
> andwf char1,f
> andwf char2,f
> swapf char1,w ; w = char1*10
> addwf char1,w
> addwf char1,w
> addwf char2,w ; + char2
Rich:
I assume that the "15" in "movlw 15" is decimal.
Your routine will work for 0-9 [ASCII 30-39], but it fails on A-F
[ASCII 41-46]. Here's a way that works for the whole range:
I don't see any reason WHY your PACKED BCD 37 (the 3 from 3"3" and the 7
from 3"7") should not be seem as binary 0011 0111 or hexa 37.... It is
really messy think that the PACKED BCD 37 is in true a decimal
representation and needs to be converted to hexa 25... really confused.
> > > I need something that would take two ASCII bytes and end up with
> > > a Hex value.
> > >
> > > For example...
> > >
> > > 33, 37 would become 25h (decimal 37)
Remember, any binary system is in true NOT DECIMAL, it can be octal,
hexadecimal, whatever you want, but it will be always binary represented
as 2^n. The only place where you need Decimal representation is when
inputting or outputting numbers from/to human interface, there is no
other place in digital systems for decimal manipulations.
So, for example, if you have the numbers "5" and "7" it is ASCII
(digital, binary) 35h and 37h, or 0011 0101 and 0011 0111, that when
packed they will turn to be 57h (0101 0111). You can say that its
"decimal" representation is 53 and 55, but what for?
Of course if the result of a binary counter is 57h you should NOT send
35h and 37h to your LCD display, except if you want to see it in
hexadecimal format. This is one of the few moments you should convert it
first to decimal, will be 87, so ASCII 38h and 37h will be sent to the
LCD, then you will see decimal "87" at the display.
I am sorry if you already know that, but some other people don't, and it
is a great moment to explain it.
> isn't ASCII a 7bit code? meaning each character is represented
> with 7 bits and to convert to hex simply interpret those 7 bits as
> interpret them as hex correct? which for 2 ASCII bytes would
> require 2 bytes. How in your example did you say 33 and 37 becomes
> 25hex. This is only one byte of hex to represent 2 bytes of ASCII,
> not possible.
Dave:
In the example (convert 33H 37H to 25H), 33 and 37 are the ASCII
codes for the characters "3" and "7". For clarity, the question
might have been stated "I have a two-digit decimal number (37, for
example) represented as two ASCII characters (33H and 37H). How can
I convert the number from THAT representation into a single value?"
Does that make more sense? The way to do the conversion is to first
convert the two characters from ASCII "3" and "7" to the numbers 3
and 7, then multiply the 3 by 10 and add it to the 7. The result, 37
decimal, is equivalent to hex 25.
And actually... Now that I've re-read te question, I take back what I
wrote in an earlier message. I misread the question and oroiginally
thought that the pair of ASCII characters represented a HEX number;
now I see that it's a decimal number. So to Rich Leggitt: Sorry;
your example would've worked fine.
We say ASCII when we mean that the number is ready to be sent to an ASCII
terminal (window, screen, whatever) and displayed as the digits of the
number. A 33 in ASCII is a '3', 30 is '0' etc.. If you send a 7 to an ASCII
terminal, the bell rings (computer beeps, whatever) an 8 will cause the
terminal to backspace. You wanted to send a 37 or a 38. To send any single
digit from 0...9 you must add 30 to it before sending it to a terminal.
Conversely, when you receive a character from an ASCII terminal, if it is a
digit (in the range 30...39) you need to subtract 30 from it. If you want to
get multiple digits (e.g. allow the user to enter a number between 0...256)
you need to combine the digits into one binary value. So when the user types
234 you actually get 32 33 34 which you convert to 02 03 04 which you then
convert to 02*100 + 03*10 + 04.
Now, all of that was in decimal. PICs compute in binary. 02*100 in binary is
10 * 1100100. It's a bit hard to read so we usually use hexadecimal which is
easier to convert to and from binary since each hex digit is exactly a group
of 4 binary digits. In fact, most displays of the values in PIC registers
are in hexadecimal. When the original poster said he wanted to "end up with
a hex value", he was really saying he needed to convert from decimal to
binary. Our example problem expressed in hex would be 02 * 64h + 03 * 0Ah +
4 which is 0EAh (hex) or 11101010 (binary) or 234 (decimal) or '234' (ASCII
decimal)
Confused? Good, that's why I get paid the big bucks to design and not to
teach. I just wish I could tech. That's why I administrate.
David,
the ascii CODE 30H happens to REPRESENT the character "0" which
in turn represents the NUMBER "zero" which in turn has a VALUE
of 00h.
So the ascii codes 33h and 37h represent "3" and "7" which
together makes "37", which has the same numerical value as 25h.
The original poster was asking for a routine that would take
the two ascii codes 33h and 37h and give 25h as the result.
25h means 2*16 + 5 which equals 37 in decimal notation.
When programming any microcontroller it is often necessary
to make these transformations so that you can, for example,
extract the numbers in ascii format that you receive over a serial
link from a PC or other device, and use them to perform
calculations.
We also often have the need to go in the opposite direction
and take a hex byte like 25h and convert it to "37" so we
can display it on an LCD screen. So a lot of us end up
"re-inventing the wheel" and spending inordinate amounts
of time coming up with methods that thousands of people
have already figured out before us.
Some of us enjoy finding different ways to do the same thing.
Make it easier to understand, or faster, or "elegant",
or do it in such a way that no normal person would have
thought of doing it. There is a challenge in trying to
do it in less steps. And sometimes we don't have all that
much extra space in our code, and we want to cram just
one more routine in there, but we need three extra bytes
to cram it in there, so we go through our code looking
for ways to save a byte here and there. It can be
maddening, or it can be fun... depending on the deadline.
> now I see that it's a decimal number. So to Rich Leggitt: Sorry;
> your example would've worked fine.
Which example? The first example he posted doesn't work. It computes 18*tens +
ones and not 10*tens + ones. The ones Tom and I posted a few days ago do work.
> Date: Tue, 4 Apr 2000 18:15:17 -0500
> From: Scott Dattalo <EraseMEscottDATTALO.COM>
> Reply-To: pic microcontroller discussion list <RemoveMEPICLISTEraseMEEraseMEMITVMA.MIT.EDU>
> To: RemoveMEPICLISTspam_OUTKILLspamMITVMA.MIT.EDU
> Subject: Re: Two ASCII bytes to one Hex byte?
>
> On Tue, 4 Apr 2000, Andrew Warren wrote:
>
> > now I see that it's a decimal number. So to Rich Leggitt: Sorry;
> > your example would've worked fine.
>
> Which example? The first example he posted doesn't work. It computes 18*tens +
> ones and not 10*tens + ones. The ones Tom and I posted a few days ago do work.
>
> Scott
>
If you inputs a number in character format, do some calculations or so,
then outputs in character format, there is also another way as to convert
it to hex/binary, calculate and re-convert. You can convert it into the
so-called packed decimal format. E. g. the number "47" = 34h 37h will be
47h in packed decimal. It is possible to do some calculations (e. g.
additions) directly with this, and the reverse the procedure. The trick
is very simple:
1. You add the digits.
2. If the sum of the paricular digits is less, than 0Ah, do nothing.
3. If the sum of the digits exceeds 0Ah, add 6 to the result, and
mark the carry.
E. g.
+47h BCD
+26h BCD
would result really 73. How?
1. Add the digits:
The result is 6Dh
3. D exceeds A, so add 6 to it. D+6 makes 13h
Write 3 into the result above in place of D and add that 1 of 13h as carry
to the 6. So you get 73. Then, it can be unpacked.
> David,
> the ascii CODE 30H happens to REPRESENT the character "0" which
> in turn represents the NUMBER "zero" which in turn has a VALUE
> of 00h.
>
> So the ascii codes 33h and 37h represent "3" and "7" which
> together makes "37", which has the same numerical value as 25h.
>
>
> The original poster was asking for a routine that would take
> the two ascii codes 33h and 37h and give 25h as the result.
> 25h means 2*16 + 5 which equals 37 in decimal notation.
>
> When programming any microcontroller it is often necessary
> to make these transformations so that you can, for example,
> extract the numbers in ascii format that you receive over a serial
> link from a PC or other device, and use them to perform
> calculations.
>
> We also often have the need to go in the opposite direction
> and take a hex byte like 25h and convert it to "37" so we
> can display it on an LCD screen. So a lot of us end up
> "re-inventing the wheel" and spending inordinate amounts
> of time coming up with methods that thousands of people
> have already figured out before us.
>
> Some of us enjoy finding different ways to do the same thing.
> Make it easier to understand, or faster, or "elegant",
> or do it in such a way that no normal person would have
> thought of doing it. There is a challenge in trying to
> do it in less steps. And sometimes we don't have all that
> much extra space in our code, and we want to cram just
> one more routine in there, but we need three extra bytes
> to cram it in there, so we go through our code looking
> for ways to save a byte here and there. It can be
> maddening, or it can be fun... depending on the deadline.
>
>
> Fr. Tom Mcgahee
>
You are right, and I'm sorry that you are confused but my application does
require exactly this conversion. If you really want to know, Caller-ID
information contains time and date info in this "messy" format..
See... it may seem silly to you, but this is how Caller-ID was designed... I
have to run through this list and turn the quite definately "ASCII" numbers
into hex representation, in this case you would end up with 04,05,16,04.
Thank you to all those in the PIClist that replied with vastly better
routines than my own. All of your ideas have been carefully read and
evaluated and are much appreciated.
To those few that this problem seems to have confused... hmmm stupid as some
requests like mine may sound, as you can see by this example, there ARE some
stupid things we have to deal with.
Why so ? tens is '0' + x , ones is '0' + y , where x and y are in range
of 0..9 So finally '0'*(10+1)=48.*11.=528.=0x210 . it is constant so we
can subtract it back from result. Here we gone ;)