Recent

Author Topic: (Solved) Convert hexadecimal to double  (Read 2099 times)

arneolav

  • Full Member
  • ***
  • Posts: 197
(Solved) Convert hexadecimal to double
« on: July 27, 2023, 12:01:49 am »
I'v to convert some sensorvalues from hex to double.

Hex '80c0' should be something like -19.2°C,    80bc = 18.8,   80bb = -18.7°C ,   80b5= -19.9
Tried this:
Uses SdpoSerial, Strutils;
strValue:= Inttostr(Hex2Dec64('80c0')); 
dblValue:= StrtoFloat(strValue);
Memo.Lines.add(FormatFloat('0.0', dblValue))

This seems to work for positive values, but not negative as shown above.

......
Tried this program #engkin (slightly modified).
Lazarus »Forum »Programming »General »[SOLVED]  ¿How convert string hexadecimal in Double value?


Result is allways 0;
Can't see what's wrong so need some help.

Code: Pascal  [Select][+][-]
  1. {$mode ObjFPC}{$H+}
  2.  
  3. interface
  4.  
  5. uses
  6.   Classes;
  7.  
  8.   function HexToDouble(const s: string): double;
  9.  
  10.  
  11. implementation
  12.  
  13.  
  14. //program Project1;
  15.  
  16. function HexToNibble(const hexvalue: char; out nibble: byte): boolean;inline;
  17. begin
  18.   if hexvalue IN ['0'..'9'] then
  19.     nibble:=((ord(hexvalue)) and 15)
  20.   else
  21.     if char(byte(hexvalue) or $20) IN ['a'..'f'] then
  22.     nibble:=((ord(hexvalue)+9) and 15)
  23.   else
  24.     Exit(False);
  25.   Result := True;
  26. end;
  27.  
  28. function HexToBin(HexValue, BinValue: PChar; BinBufSize: Integer): Integer;
  29. var
  30.   i,j : integer;
  31.   h,l : byte;
  32.  
  33. begin
  34.   i:=binbufsize;
  35.   while (i>0) do
  36.   begin
  37.     if not HexToNibble(hexvalue^, h) then
  38.       break;
  39.     inc(hexvalue);
  40.  
  41.     if not HexToNibble(hexvalue^, l) then
  42.       break;
  43.     j := l + (h shl 4);
  44.     inc(hexvalue);
  45.  
  46.     binvalue^:=chr(j);
  47.     inc(binvalue);
  48.     dec(i);
  49.   end;
  50.   result:=binbufsize-i;
  51. end;
  52.  
  53. function HexToDouble(const s: string): double;
  54. type
  55.   TNum = record
  56.     case byte of
  57.     1:(n32: DWord);
  58.     2:(n64: QWord);
  59.     3:(fs : Single);
  60.     4:(fd : Double);
  61.   end;
  62.  
  63. var
  64.   i: TNum;
  65. begin
  66.   i.n64:=0;
  67.   if s<>'' then HexToBin(@s[1],@i,sizeof(double));
  68.   if Length(s)<9 then
  69.   begin
  70.     i.n32:=BEtoN(i.n32);
  71.   //  HexToDouble:=i.fs;
  72.     Result:=i.fs;
  73.   end
  74.   else
  75.   begin
  76.     i.n64:=BEtoN(i.n64);
  77.   //  HexToDouble:=i.fd;
  78.     Result:=i.fd;
  79.   end;
  80. end;
« Last Edit: July 27, 2023, 08:34:56 am by arneolav »
Win 11, win64 , Lazarus 4.0RC3
Delphi/DevExpress

jamie

  • Hero Member
  • *****
  • Posts: 7764
Re: Convert hexadecimal to double
« Reply #1 on: July 27, 2023, 12:14:58 am »
If  you use "StrToInt($yourHexNumber); it will resolve it.

Place the $ infront.
The only true wisdom is knowing you know nothing

arneolav

  • Full Member
  • ***
  • Posts: 197
Re: Convert hexadecimal to double
« Reply #2 on: July 27, 2023, 12:28:50 am »
You mean like this:
 Memo.Lines.add(FormatFloat('0.0', StrToInt('$' +'80c0')));

But sorry no, result is 32960.
Ok for positive numbers, negative, no.
« Last Edit: July 27, 2023, 12:36:35 am by arneolav »
Win 11, win64 , Lazarus 4.0RC3
Delphi/DevExpress

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: Convert hexadecimal to double
« Reply #3 on: July 27, 2023, 12:43:56 am »
But sorry no, result is 32960.
The point is that yo have a numeric value now.

Mask of the 16th bit (check it to know if it is a positive or negative number, if set then negative else positive). All left is then to divide by 10 (multiply by -1 if 16th bit was set).

btw:
Hex '80c0' should be something like -19.2°C,    80bc = 18.8,   80bb = -18.7°C ,   80b5= -19.9
the 80b5 value.
Should that not read -18.1 ?

If not then there is something else that seem to come into play.
« Last Edit: July 27, 2023, 12:48:21 am by TRon »
Today is tomorrow's yesterday.

jamie

  • Hero Member
  • *****
  • Posts: 7764
Re: Convert hexadecimal to double
« Reply #4 on: July 27, 2023, 12:46:02 am »
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   Caption := FormatFloat('0.0',Single(ShortInt(StrToInt('$80C0'))));
  4. end;                                                                        
  5.  

Its a short integer;
The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 7764
Re: Convert hexadecimal to double
« Reply #5 on: July 27, 2023, 12:54:59 am »
That code I gave you only translates the first LSB because I used a shortInt, IT should of been a smallInt if you want the whole scale.

 I don't know the specifics of the unit you are coding to so I can't say.
The only true wisdom is knowing you know nothing

arneolav

  • Full Member
  • ***
  • Posts: 197
Re: Convert hexadecimal to double
« Reply #6 on: July 27, 2023, 01:05:21 am »
I'm on lazarus 3.0RC1. x64, default European, UTF8

...
ShortInt result: -64
Small int: -32580

Should be -192 (or close to 190)
Win 11, win64 , Lazarus 4.0RC3
Delphi/DevExpress

arneolav

  • Full Member
  • ***
  • Posts: 197
Re: Convert hexadecimal to double
« Reply #7 on: July 27, 2023, 01:11:16 am »

the 80b5 value.
Should that not read -18.1 ?

If not then there is something else that seem to come into play.

Suppose you are correct, the values change fast but are always close to -19,0  (or mostly between -18 to -20)
« Last Edit: July 27, 2023, 01:14:17 am by arneolav »
Win 11, win64 , Lazarus 4.0RC3
Delphi/DevExpress

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: Convert hexadecimal to double
« Reply #8 on: July 27, 2023, 01:34:51 am »
No idea what the cast as shown by jamie is doing (should work but doesn't seem to).

so, instead:
Code: Pascal  [Select][+][-]
  1. function HexWord2Single(const s: string): double;
  2. var
  3.   multiply: single;
  4.   w : word;
  5. begin
  6.   w := StrToInt(s);
  7.  
  8.   // check if 16th bit is set
  9.   if w and $8000 <> 0 then
  10.   begin
  11.     // mask off the 16th bit
  12.     w := w and $7FFF;
  13.     // because 16th bit was set it is now known the number is negative
  14.     multiply := -0.1; // divide by 10 at the same time
  15.   end
  16.   else
  17.   begin
  18.     // 16th bit was not set so is is know the number is positive
  19.     multiply := 0.1; // dive by ten at the same time
  20.   end;
  21.   HexWord2Single := w * multiply;
  22. end;
  23.  
  24. begin
  25.   WriteLn(HexWord2single('$80c0'));
  26.  
  27.   WriteLn(FormatFloat('0.0', HexWord2single('$80c0')));
  28.   WriteLn(FormatFloat('0.0', HexWord2single('$80bc')));
  29.   WriteLn(FormatFloat('0.0', HexWord2single('$80bb')));
  30.   WriteLn(FormatFloat('0.0', HexWord2single('$80b5')));
  31. end.
  32.  
which for me outputs:
Code: [Select]
-1.9200000762939453E+001
-19.2
-18.8
-18.7
-18.1

edit: craps. I messed up the function name as initially I used a single instead of a double.
« Last Edit: July 27, 2023, 01:38:07 am by TRon »
Today is tomorrow's yesterday.

jamie

  • Hero Member
  • *****
  • Posts: 7764
Re: Convert hexadecimal to double
« Reply #9 on: July 27, 2023, 01:57:49 am »
I came up with this.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. Var
  3.   V:SmallInt;
  4.   S:Single;
  5. begin
  6.   V := StrToInt('$80C0');
  7.   If v < 0 Then V := $FFFF-(V and $7FFF);
  8.   S := V / 10;
  9.   Caption := FormatFloat('0.0',S);
  10. end;                                
  11.  
  12.  
The only true wisdom is knowing you know nothing

rca

  • Full Member
  • ***
  • Posts: 124
Re: Convert hexadecimal to double
« Reply #10 on: July 27, 2023, 02:32:07 am »
I came up with this.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. Var
  3.   V:SmallInt;
  4.   S:Single;
  5. begin
  6.   V := StrToInt('$80C0');
  7.   If v < 0 Then V := $FFFF-(V and $7FFF);
  8.   S := V / 10;
  9.   Caption := FormatFloat('0.0',S);
  10. end;                                
  11.  
  12.  

The result is not correct, since it would be added 0.1

Following your strategy, it should be:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   V:SmallInt;
  4.   S:Single;
  5. begin
  6.   V := StrToInt('$80C0');
  7.   If v < 0 Then V := -(V and $7FFF);
  8.   S := V / 10;
  9.   Caption := FormatFloat('0.0',S);
  10. end;  



jamie

  • Hero Member
  • *****
  • Posts: 7764
Re: Convert hexadecimal to double
« Reply #11 on: July 27, 2023, 03:02:02 am »
It only resulted in a 0.1 difference

in any case I did see that after posting it..


$10000-(.... or just 0 or just - etc.

also corrects it.
« Last Edit: July 27, 2023, 03:04:00 am by jamie »
The only true wisdom is knowing you know nothing

arneolav

  • Full Member
  • ***
  • Posts: 197
Re: Convert hexadecimal to double
« Reply #12 on: July 27, 2023, 08:32:09 am »
Thanks very much guys!
This did the trick (code just to inform others):

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   V:SmallInt;
  4.   S:Single;
  5. begin
  6.   V := StrToInt('$' + MyHexValue);
  7.   If v < 0 Then V := -(V and $7FFF);
  8.   S := V / 10;
  9.   Caption := FormatFloat('0.0',S);
  10. end;
« Last Edit: July 27, 2023, 08:35:49 am by arneolav »
Win 11, win64 , Lazarus 4.0RC3
Delphi/DevExpress

Raskaton

  • New Member
  • *
  • Posts: 27
Re: Convert hexadecimal to double
« Reply #13 on: January 30, 2025, 08:02:24 pm »
Sorry for necroposting, but search gived me this topic. And answer is wrong.
This will not work:
Code: Pascal  [Select][+][-]
  1. Single(ShortInt(StrToInt('$80C0')));
  2.  
becouse Converting occured, but not Typecast.
For real Typecast some memory buffer with IEEE754 coded float recived from MCU use pointers:
Code: Pascal  [Select][+][-]
  1. function BufferToSingle(DwBuf: DWord): Single;
  2. begin
  3.   Result := PSingle(@DwBuf)^;
  4. end;
  5.  
If buffer recived from microcontroller with BigEndian core, then use BEToN(DwBuf) before Typecast.
And in past I have problems with absolute keyword when trying approach same. Ended with ugly pointers :(
More interesting functions will be with Extended type and Modbus "Word-BigEndians". But idea is same.
{$Necroposting off}  :)

 

TinyPortal © 2005-2018