How to get a decimal value, and convet the decimal value to a float point value?
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 "." .
Thanks a lot.
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
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
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.
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.GetDecSomething like that, the result always display the last value.
Instead like this, it always wait for my input.
Thanks for your attention!!
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
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
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!
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) / cThen, 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.GetDecAbove 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.
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 := 1You 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
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 := _RxThe code maybe not a good method, do you have any suggestion for me?Thanks a lot~
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
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
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
From the last code you posted, it looks like you want to be able to change one value at a time. Right?
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
I am grateful for your assistance~