Shop OBEX P1 Docs P2 Docs Learn Events
How to get a decimal value, and convet the decimal value to a float point value? — Parallax Forums

How to get a decimal value, and convet the decimal value to a float point value?

kevinspacekevinspace Posts: 56
edited 2011-08-21 01:15 in Propeller 1
Hello everyone~
How to get a decimal value, and convet the decimal value to a float point value?
In my code, I tried to get the decimal value from Parallax Serial Terminal,
but the Parallax Serial Terminal which seems like couldn't to accept the float point "." .
VAR long Stack[150] 
        long GetValue
        long GetFloatValue
    
OBJ 
   Debug: "FullDuplexSerialPlus"
   FMath : "FloatMath"
   FString : "FloatString"
   
PUB Main
coginit(3, Get, @stack[0]) 
Debug.start(31, 30, 0, 9600) 
Debug.tx(16)
repeat
  GetFloatValue := FMath.FFloat(GetValue)
  Debug.str(fstring.FloatToString(GetFloatValue))        
  Debug.str(string(13))
 
PUB Get
repeat
  GetValue := Debug.GetDec 
Are there any example or any suggesstion?

Thanks a lot.

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-06-14 01:01
    VAR long Stack[150] 
            long GetValue, GetValueLow, ValueLowDenominator
            long GetFloatValue
     
    OBJ 
       Debug: "FullDuplexSerialPlus"
       FMath : "FloatMath"
       FString : "FloatString"
     
    PUB Main
    coginit(3, Get, @stack[0]) 
    Debug.start(31, 30, 0, 9600) 
    Debug.tx(16)
    repeat
      GetFloatValue := Get
      Debug.str(fstring.FloatToString(GetFloatValue))        
      Debug.str(string(13))
     
     
    PUB Get : size | localCharacter, afterDecimalFlag
     
      GetValue := 0
      GetValueLow := 0
      ValueLowDenominator := 1
      afterDecimalFlag := 0  repeat
        localCharacter := Debug.rx
        if localCharacter == "."
          afterDecimalFlag := 1
        if afterDecimalFlag == 0
          GetValue := (GetValue * 10) + (localCharacter - "0")
        else 
          GetValueLow := (GetValueLow * 10) + (localCharacter - "0")
          ValueLowDenominator *= 10
      while localCharacter <> 13
     
      ''change GetValue, GetValueLow and ValueLowDenominator to floats
     
      '' do following using float math  result := GetValue + (GetValueLow / ValueLowDenominator) 
     
    

    Something like that.

    It's late here. I'll be able to help more tomorrow if needed.

    Duane
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-06-14 06:35
    So much for writing code at 2am.

    Here's a version without all the bugs.
    CON
     
      _clkmode  = xtal1 + pll16x    '  You'll probably need a crystal to use
      _xinfreq  = 5_000_000         ' FullDuplexSerialPlus
     
    VAR
      long Stack[150] 
      long GetFloatValue
     
    OBJ 
       Debug: "FullDuplexSerialPlus"
       FMath : "F32" '"FloatMath"
       FString : "FloatString"
     
    PUB Main
      FMath.Start
      'coginit(3, Get, @stack[0]) 
      Debug.start(31, 30, 0, 9600) 
      Debug.tx(16)
      repeat
        GetFloatValue := Get
        Debug.str(fstring.FloatToString(GetFloatValue))        
        Debug.str(string(13))
     
     
    PUB Get | localCharacter, afterDecimalFlag, GetValue, GetValueLow, ValueLowDenominator
     
      GetValue := 0
      GetValueLow := 0
      ValueLowDenominator := 1
      afterDecimalFlag := 0
      repeat
        localCharacter := Debug.rx
        if localCharacter == "."
          afterDecimalFlag := 1
        elseif afterDecimalFlag == 0 and localCharacter => "0" and localCharacter =< "9"
          GetValue := (GetValue * 10) + (localCharacter - "0")
        elseif localCharacter => "0" and localCharacter =< "9"
          GetValueLow := (GetValueLow * 10) + (localCharacter - "0")
          ValueLowDenominator *= 10
      while localCharacter <> 13
      GetValue := FMath.fFloat(GetValue)
      GetValueLow := FMath.fFloat(GetValueLow)
      ValueLowDenominator := FMath.fFloat(ValueLowDenominator)
      GetValueLow := FMath.fDiv(GetValueLow, ValueLowDenominator)
      result := FMath.fAdd(GetValue, GetValueLow)
    

    The attached archive assumes a 80MHz clock.

    I used Lonesock's F32 object since it's faster than FloatMath.

    Duane

    EDIT: I just looked at the code you originally attached. I didn't see any clock settings. I'm pretty sure you need a crystal to use FullDuplexSerialPlus. (It's probably possible to use FullDuplexSerialPlus without a crystal, but you'd have to have a way of accurately measuring your clock speed.)

    I had previously included clock settings in the attached code but I just now added the clock settings to the in-line code. You'll need to make sure and use the appropriate settings for your crystal.

    I realized I didn't add many comments to the code. I was in a hurry when I wrote it this morning. Let me know if you have any questions about it.

    I'm sure there are better ways to do this (entering floats with decimal points). There almost always is a better solution than ones/my first attempt to solve a problem.
  • kevinspacekevinspace Posts: 56
    edited 2011-06-14 19:27
    Thanks, Duane Degn~
    But I'm still have another problem, because the project of mine which have to input a float point value to change my robot velocity variable, so I hope the velocity variable always as my last input value.
    In other words, the code from your help which seems like have to wait for my input.
    How to modify the code and let the velocity variable always as my last input ?
    CON
        _clkmode = xtal1 + pll16x
        _xinfreq = 5_000_000
     
    VAR long Stack[150] 
        long GetValue
        long GetFloatValue   
     
    OBJ 
       Debug: "FullDuplexSerialPlus"
       FMath : "FloatMath"
       FString : "FloatString" 
     
    PUB Main
    coginit(3, Get, @stack[0]) 
    Debug.start(31, 30, 0, 9600) 
    Debug.tx(16)
    repeat
       GetFloatValue := FMath.FFloat(GetValue)
       Debug.str(fstring.FloatToString(GetFloatValue))        
       Debug.str(string(13))
     
    PUB Get
    repeat
      GetValue := Debug.GetDec  
    

    picture1.jpg

    Something like that, the result always display the last value.

    picture2.jpg

    Instead like this, it always wait for my input.

    Thanks for your attention!!
    1024 x 414 - 37K
    1024 x 415 - 34K
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-06-14 19:38
    There are several ways to do what you want.

    You could have a separate cog monitor the input.

    You could also use the rxcheck method instead of the rx method. The rx method of FullDuplexSerialPlus waits for a character. The rxcheck method returns -1 if there isn't a character in the buffer.

    By using rxcheck you'd just make checking for input (probably one character at a time) part of your main loop.

    Duane
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-06-15 08:08
    kevinspace,

    Here's pretty much the same program as the one I uploaded earlier except now it uses the rxcheck method instead of the rx method.

    You could also use the "newFloatFlag" technique with the data entry done in a second cog.

    I remember earlier in learning to use the Prop, I'd throw another cog in the mix long before it was really needed. In this case, I don't think a second cog is really needed (FDX+ is already running in a second cog).
    CON
            _clkmode        = xtal1 + pll16x
            _xinfreq        = 5_000_000
    VAR
      long floatValue
      long valueHigh, valueLow, valueLowDenominator
      byte afterDecimalFlag, newFloatFlag
     
    OBJ 
       Debug: "FullDuplexSerialPlus"
       FMath : "F32" '"FloatMath"
       FString : "FloatString"
     
    PUB Main | localCharacter
      newFloatFlag := 0          
      valueHigh := 0    ' initialize the variables used to build the float
      valueLow := 0
      valueLowDenominator := 1
      afterDecimalFlag := 0
     
      FMath.Start 
      Debug.start(31, 30, 0, 9600) 
      Debug.tx(16)
      repeat
        localCharacter := Debug.rxcheck
        if localCharacter <> -1
          BuildFloat(localCharacter)
        if newFloatFlag == 1        ' If floatValue has been changed do something
          UpdateRobotCommand
          newFloatFlag := 0
        Debug.str(string("Robot Continuing on course = "))     
        Debug.str(fstring.FloatToString(floatValue))        
        Debug.str(string(13))
        ' add normal robot action here.
     
    PUB BuildFloat(localCharacter)
      if localCharacter == 13       ' indicates we're done building a float 
        valueHigh := FMath.fFloat(valueHigh)  ' change values to floats
        valueLow := FMath.fFloat(valueLow)
        valueLowDenominator := FMath.fFloat(valueLowDenominator)
        valueLow := FMath.fDiv(valueLow, valueLowDenominator) 
        floatValue := FMath.fAdd(valueHigh, valueLow)
        newFloatFlag := 1  ' tell the robot there is a new speed/direction command           
        valueHigh := 0    ' reset the variables used to build the float
        valueLow := 0
        valueLowDenominator := 1
        afterDecimalFlag := 0
      elseif localCharacter == "."
        afterDecimalFlag := 1
      elseif afterDecimalFlag == 0 and localCharacter => "0" and localCharacter =< "9"
        valueHigh := (valueHigh * 10) + (localCharacter - "0")
      elseif localCharacter => "0" and localCharacter =< "9"
        valueLow := (valueLow * 10) + (localCharacter - "0")
        valueLowDenominator *= 10
    PUB UpdateRobotCommand
      Debug.str(string("Robot's new course = "))     
      Debug.str(fstring.FloatToString(floatValue))        
      Debug.str(string(13))
     
      ' Take action that only happens when the data is changed.
    

    I changed the variable names. I personally think a name like "GetFloatValue" sounds like a method instead of a variable. I switched to my own naming convention to made it easier for me to code. You can use the Find and Replace feature to change them to variable names you'd prefer.

    Do you really need floating point numbers? Have you used pseudo-real numbers before?

    If you're using trig functions then floating point is probably a good route to take.

    I also wonder why you're using coginit instead of cognew? I just keep reading suggestions by others to use cognew unless there some reason coginit is needed.

    I've modified Tim Moore's four port serial object several times. One of my modifications was to include an end of message flag. A flag would be incremented every time a port received an end of message character (I usually use 13(CR)). The object is in post #9 of this thread.

    When I use the above mentioned driver, I'd compare the value in the counter (I called it a flag above) to the previous know value. If the new value was different, I knew there was a new message.

    I found many of my programs listened to serial ports lines but the action came only at the end of the message. Since I had increased the rx buffer of the driver, I could just let the data sit in the driver's buffer until a full message was received. I think it's very useful.

    Well time to get back to work.

    Duane
  • kevinspacekevinspace Posts: 56
    edited 2011-06-16 00:45
    Duane, I am grateful for your assistance !

    I have downloaded your code and the tried it successfully.
    Because I am a new learner of the propeller controller, so I have to spend more times to study your code.
    After the disscussion, I have learned more than previously.

    Thanks a lot!
  • kevinspacekevinspace Posts: 56
    edited 2011-06-16 18:59
    Hi~ Duane
    How to get some decimal value, and set the value into my PUB command ?
    Just like the code, the command which have to input a, b, and c value .
    CON
        _clkmode = xtal1 + pll16x                           
        _xinfreq = 5_000_000
        
    VAR long  Stack[150]
        long  Value               
                   
    OBJ
        Debug: "FullDuplexSerialPlus"
     
    PUB Main     
        Debug.start(31, 30, 0, 9600)  
        Debug.tx(16)
        Command(6, 2, 4)
        
        repeat   
           Debug.Dec(Value)
           Debug.str(string(13))
        
    PUB Command(a, b, c)
        Value := (a * b) / c 
    


    Then, I tried to get a decimal value, and set the value into my PUB command.
    Just like it :
    CON
        _clkmode = xtal1 + pll16x                           
        _xinfreq = 5_000_000
        
    VAR long  Stack[150]
        long  Value
        long  GetValue
        
    OBJ
        Debug: "FullDuplexSerialPlus"
     
    PUB Main
        coginit(3, Get, @stack[0])    
        Debug.start(31, 30, 0, 9600)  
        Debug.tx(16)
        
        repeat
           InputCommandValue(GetValue, 2, 4)
           Debug.Dec(Value)
           Debug.str(string(13))
       
    PUB InputCommandValue(a, b, c)
        Value := (a * b) / c 
        
    PUB Get
        repeat
           GetValue := Debug.GetDec 
    

    Above the code, I just change the "a" value only, but I don't know how to change the "a","b", and "c" value respectively.
    How to achieve the idea ?

    Are there any example or any suggesstion?

    Thanks a lot.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-06-17 08:39
    kevinspace,

    It kind of depends on how you want a, b and c updated. Are you always going to update all three values at once? Or do you want to be able to change one value at a time.

    If you want the first case you could do this:
    CON
        _clkmode = xtal1 + pll16x                           
        _xinfreq = 5_000_000
     
    VAR long  Stack[150]
        long  Value
        long  GetValue, ValueB, ValueC
        byte  NewValuesFlag
     
    OBJ
        Debug: "FullDuplexSerialPlus"
     
    PUB Main
        coginit(3, Get, @stack[0])    
        Debug.start(31, 30, 0, 9600)  
        Debug.tx(16)
     
        repeat
           if NewValuesFlag == 1
              InputCommandValue(GetValue, ValueB, ValueC)
              Debug.str(string(13, "Command Value = "))
              Debug.Dec(Value)
              Debug.tx(13)
              NewValuesFlag := 0
    PUB InputCommandValue(a, b, c)
        Value := (a * b) / c 
     
    PUB Get
        repeat
           repeat while NewValuesFlag == 1 ' this line makes this cog wait for the other
                                           ' cog to finish using the serial line.                                                                                                                                                                                                                                                           
           Debug.str(string(13, "Enter a: "))
           GetValue := Debug.GetDec
           Debug.Dec(GetValue)        
           Debug.str(string(13, "Enter b: "))
           ValueB := Debug.GetDec
           Debug.Dec(ValueB)
           Debug.str(string(13, "Enter c: "))
           ValueC := Debug.GetDec
           Debug.Dec(ValueC)
           NewValuesFlag := 1
    
    You don't want both cogs trying to use the serial line at the same time.

    As the code is now, you don't benefit from using the extra cog. I assume you have plans that will make use of the extra cog.

    I know I have code that update values for a robot. Most of my robot code uses some sort of controller other than a terminal. I'll try to find something that I think will be helpful in learning to enter commands that change the Props behavior.

    Since you are using a separate cog for data input, you could probably use Simple Serial and save a cog.

    Duane
  • kevinspacekevinspace Posts: 56
    edited 2011-06-21 20:28
    Thanks, Duane~
    I have downloaded your code and the tried it successfully.
    I tried to modify your code to conform for my case recently.

    Because, the code from your help which seems like have to wait for my input, just like the previous example.

    I try to modify the code and let the ValueA, ValueB, ValueC variable always as my last input ?

    For example, If I input a value for the ValueA variable, however the ValueB and ValueC variables which will maintain to the last input value for them.

    Just like it :
    CON
        _clkmode = xtal1 + pll16x                           
        _xinfreq = 5_000_000
     
    VAR long  Stack[150]
            long  Rx
            long  Calculate_Value
            long  ValueA, ValueB, ValueC
     
    OBJ
        Debug : "FullDuplexSerialPlus.spin"
     
    PUB Receive  
        Debug.start(31, 30, 0, 9600)  
        Debug.tx(16) 
        coginit(3, Main, @stack[0])
        Display   
     
    PUB Display
    repeat
        Debug.str(string("ValueA: ", 13))
        Debug.Dec(ValueA)  
        Debug.str(string(13))
        Debug.str(string("ValueB: ", 13))
        Debug.Dec(ValueB)  
        Debug.str(string(13))
        Debug.str(string("ValueC: ", 13))
        Debug.Dec(ValueC)  
        Debug.str(string(13))
     
        Debug.str(string("Calculate_Value: ", 13))
        Debug.Dec(Calculate_Value)  
        Debug.str(string(13))
     
        waitcnt(clkfreq + cnt)        
     
    PUB Main
    repeat
        Rx := GetDataByte
        case Rx
     
             "a"   : if GetDataByte == 13
                        ValueA := Debug.GetDec
                        Opertate
     
             "b"   : if GetDataByte == 13
                        ValueB := Debug.GetDec
                        Opertate
     
             "c"   : if GetDataByte == 13
                        ValueC := Debug.GetDec
                        Opertate
     
    PUB Opertate
        Calculate_Value := ValueA + ValueB + ValueC
     
    PUB GetDataByte|Flag,Data,_Rx   '' Retrieves serial data BYTE from two seperate locations
        Flag := 0                   '  Note: Only one serial data channel should be
        repeat while Flag == 0      '        active at a time and should be read as
          Data := Debug.rxcheck  '        an either/or but not both.
          if Data <> -1
             _Rx := Data
             Flag := 1      
        Result := _Rx
     
    
    The code maybe not a good method, do you have any suggestion for me?

    Thanks a lot~
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-06-22 03:56
    Hi Kevin,

    to me it is still not clear what you want to do. And - maybe - this is a tick from me - please give me an overview of what you want to do in the end.
    Entering three decimal values is not a self-purpose. What are you doing with these values after entering them?

    You are posing a unspecific question
    The code maybe not a good method, do you have any suggestion for me?

    Please take yourself the time to write down the different situations that the code should cope with.
    Write a verbal description of what the could should do ideally.

    keep the questions coming
    best regards

    Stefan
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-06-22 08:06
    kevinspace wrote: »
    Because, the code from your help which seems like have to wait for my input, just like the previous example.

    The code seems like it's waiting for your input because the code doesn't do anything else.

    I should have made it more clear that the loop below is running in parallel with the data entry cog. You can add other things to this loop.
        repeat
           if NewValuesFlag == 1
              InputCommandValue(GetValue, ValueB, ValueC)
              Debug.str(string(13, "Command Value = "))
              Debug.Dec(Value)
              Debug.tx(13)
              'Do stuff that gets done only once when new data is entered
              NewValuesFlag := 0
          ' Do other stuff here.  Stuff that needs to be done with each loop of your main loop.
          ' Move robot etc.
    

    You could have one cog controlling the robot with the current information and another cog waiting for input.

    There are lots of different ways to do this. You don't really even need the extra cog at this point.

    Since you're using FDX+ you could use the rxcheck method to see it a new character has been entered from your main program loop. If you want to have the data input done with a separate cog you can use SimpleSerial and save yourself a cog.

    I do agree with Stefan, I think you need to provide more information.

    Duane
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-06-22 08:09
    Duane Degn wrote: »
    kevinspace,

    It kind of depends on how you want a, b and c updated. Are you always going to update all three values at once? Or do you want to be able to change one value at a time.

    From the last code you posted, it looks like you want to be able to change one value at a time. Right?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-08-19 12:59
    kevinspace,

    I added support for negative numbers to the code I previously posted.

    As written, the negative sign needs to be the first character of the number.

    The program could be easily changed to allow the negative sign to be added in any location. I thought I'd limit it to the first location since that's the way we write numbers.

    Duane
  • kevinspacekevinspace Posts: 56
    edited 2011-08-21 01:15
    Duane Degn ,
    I am grateful for your assistance~
Sign In or Register to comment.