News:

Let's find out together what makes a PIC Tick!

Main Menu

Passing a floating point number with ASCII

Started by JonW, Dec 23, 2021, 09:56 AM

Previous topic - Next topic

JonW

Am working on a tiny Dual 6,4GHz PLL bit of test kit for my Lab so i can automate RF testing for IM products /RF Mixer table creation and want to have the ability to control it over Uart with ASCII.  I have all the algorithms done to calculate the PLL registers and need this it be accurate to 1kHz as it will be locked to a GPS disciplined reference.

Am looking for a simple way to convert the Received Ascii string into a float variable.

My routines accept a Float value of xxxx.xxx which represent 12.5 to 6400MHz.

ex Receive 12.516 ASCII and convert to 12.516 in my float variable
ex Receive 6126.123 ASCII and convert 6126.123 in my float variable

Any ideas? its doing my noodle in!

Jon

JonW

BTW all the receive routines are complete so the RX_BUFF[] array contains the received ASCII String and I have a RX_PNTR that reports the number of bytes in the receive packet

J

tumbleweed

QuoteReceive 6126.123 ASCII and convert 6126.123 in my float variable
Watch out. Due to the nature of the 32-bit floating-point format you only get 6-7 digits of precision,
so that 1KHz digit is likely to be suspect. Especially true if you do any math on the variable.

If you want to represent XXXX.XXX accurately you should look at doing it as a scaled integer (ie dword values, x 1000)

JonW

#3
Thanks for the head up, its already scaled to MHz so only need 3 digits.  I also do scale to integers in the procedures as it makes the calculations for the sigma delta modulator Numerator and denominator much easier for the Fractional portion of the PLL.  I need the float input as there are multiple calls of the procedure from other routines

J


joesaliba

Jon,

Maybe it is of help, what I have is not ASCII to float but String to Float.

sTemp = "-1.567"    is there to only show how it works.

Dim sTemp  As String * 15  ' Variable used to hold temporary strings
Dim Sign    As Bit
Dim fTemp  As Float

'==================================================================================================

sTemp = "-1.567"        ' An example for a negative string number

Sign  = 0                                      ' Clear Sign
fTemp = 0                                      ' Clear fTemp

bTemp = Len(sTemp) -1                          ' Take length of string

fMultiplier = 1                                ' Load fMultiplier with 1

For bTemp = bTemp To 0 Step -1                  ' Create a loop length as sTemp
    bUnit = LookDownL sTemp[bTemp] , ["0123456789.-"] ' Load bUnit according to match
       
    If bUnit = 11 Then                          ' If bUnit = 11, (-) then
        Sign = 1                                ' load Sign with 1 to indicate neg. value
        Continue                                ' jump to Next, skip the following
    EndIf                                      ' End If...Then instruction
   
    If bUnit < 10 Then                          ' If bUnit is smaller or equal 9 then
        fTemp = fTemp + (bUnit * fMultiplier)  ' add fTemp to bUnit and multiply it
        fMultiplier = fMultiplier * 10          ' increase multiplier
    Else                                        ' else if bUnit is greater 9 then
        fTemp = fTemp / fMultiplier            ' divide fTemp by fMultiplier
        fMultiplier = 1                        ' reload fMultiplier with 1
    End If                                      ' End If...Then instruction

Next                                            ' Next loop

If Sign = 1 Then fTemp = -fTemp                ' Convert to negative if required

'==================================================================================================

top204

#5
Many thanks for your lovely cash gift JonW. It is very much appreciated, in fact I cannot put into true words how much kindness from people is appreciated by me. It's not something I am accustomed too as an adult. :-)

The compiler installs quite a few libraries that I have created over the years, and are held in the "Includes" directory: "C:\Users\Computer Name\PDS\Includes\"

One of them is the "Strings.inc" library that contains procedures to convert ASCII to Floating Point and vice-versa, as well as String Trimming etc... The program below shows the StringToFloat procedure in operation:


'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A simple demonstration of the compiler's "Strings.inc" library file, located at: "C:\Users\Computer Name\PDS\Includes\"
' The libraries within the "Includes" directory are installed with the compilers, and the compiler can always see them when included in a program.
'
' The program uses the StringToFloat procedure to convert a String variable holding an ASCII representation of a floating point value into a floating point value
'
' Written for the Positron compilers by Les Johnson
'
    Device = 18F25K20
    Declare Xtal = 16 
    Declare Float_Display_Type = Fast   ' Use the more accurate and faster Floating Point conversion internal library routine
'
' Setup USART1
'
    Declare Hserial_Baud = 9600
    Declare HRSOut1_Pin = PORTC.6

    Include "Strings.inc"               ' Load the String library procedures into the program
'
' Create some variables
'   
    Dim MyString As String * 12
    Dim MyFloat As Float

'-----------------------------------------------------
' The main program starts here
'
Main:
    MyString = "6126.123"               ' Load a string with an ASCII representation of a floating point value
    MyFloat = StringToFloat(MyString)   ' Call the procedure to convert it to a floating point value
    HRSOutLn Dec3 MyFloat               ' Transmit the value to a serial terminal

JonW

You are very welcome Les, many on here really appreciate the effort you put into keeping the compiler going and for the continual help you provide.

Many thanks for the pointer, saved me a SH*t load of time

Jon

JonW

Hi Les

I tried the StrToFLoat() proc and it seems to work the first time but if called twice or more then the result seems to expand and give errors?  If the PIC is reset then it works again for the first time only

Jon

top204

#8
Sorry about that Jon. I forgot to reset the Result variable within the StrToFloat procedure, so it keeps the value it finished with on the previous call to it. But "wow", doesn't it convert a big value? :-)

Add the line: Result = 0 to the beginning of the procedure's code. For example:

Proc StrToFloat(ByRef pValAddr As Word), Float
    Dim fPow10 As Float = 1
    Dim tSign As Bit = 0
    Dim bChar As Byte
    Result = 0

The rest of the procedure's code is here........

I obviously did not test it within a loop when I wrote it. :-)

I'll add the changed procedure to the next free updates installer.

JonW

boom, you don't realise how good you are Les!


Many thanks

tumbleweed

Quoteits already scaled to MHz so only need 3 digits.
It's not the number of digits past the dec pt that's an issue, it's the TOTAL number of digits.

6400.001 MHz (1KHz resolution) requires 7 digits. It's something to watch out for since you might not be able to directly represent some values.

As I said, it gets worse if you do any math on the numbers.

JonW

Les why don't you offer a service to write procedures on an hourly rate. You can write code that most of us cannot so why mot offer the service on an hourly basis.  Recon an average consultant £100 per hour.

JonW

#12
Tumbleweed :

In my case it rounds nicely so there is no issue, I fully understand the bounding limits and errors.  I really appreciate the post but its taken care of and as I said, in previous posts  it was an attempt to keep it simple as the basis of the post was for ASCII to Float conversion.

But appreciate the post dude. 

J

 

 

JonW

You are a rare breed Les, don't ever stop being you.

xx Jon

JonW

Les

 I modified your routine to do a StringToDwrd  conversion as the StringToFloat Proc does have some rounding errors with certain numbers (as Tumbleweed rightly  mentioned), Even though I had already corrected for this in the main routine I decided to take a look at the doing all the math in DWRD for the PLL and other routines as it saved a load of code space.  Here is the procedure if you want to add it to the strings.inc file as others may find it useful.

It can accept 1234567,  1234,567 or 1234.567 etc

(***************************************************************************************************
* Title     :  StringToDwrd                                                                        *
* Input     :  Passes the String as Pointer                                                        *
* Output    :  Dwrd converted                                                                      *
* Notes     :  Converts a string to DWRD EX "1233.456"  to 1233456                                 *
***************************************************************************************************)

proc SringToDwrd (ByRef pValAddr As Word),dword
       dim Bchar as byte
       result  = 0

       bChar = Ptr8(pValAddr++)                            ' Get a character from the String
    Do                                                  ' Scan the digits before the decimal point (if included)
        If bChar < "0" Then Break                       ' \
        If bChar > "9" Then Break                       ' / Exit the loop if non numeric characters found
        Result = Result * 10                            ' \
        Result = Result + bChar                         ' | Calculate the whole part of the floating point value
        Result = Result - "0"                           ' /
        bChar = Ptr8(pValAddr++)                        ' Get another character from the string
    Loop
     If bChar == "." Then                                ' Have we found a "." character?
        bChar = Ptr8(pValAddr++)
     endif
     If bChar == "," Then                                ' Have we found a "," character?
        bChar = Ptr8(pValAddr++)
     endif
    Do                                                  ' Scan the digits before the decimal point (if included)
        If bChar < "0" Then Break                       ' \
        If bChar > "9" Then Break                       ' / Exit the loop if non numeric characters found
        Result = Result * 10                            ' \
        Result = Result + bChar                         ' | Calculate the whole part of the floating point value
        Result = Result - "0"                           ' /
        bChar = Ptr8(pValAddr++)                        ' Get another character from the string
    Loop
endproc