Using floating point


Closed Thread
Results 1 to 9 of 9
  1. #1
    Join Date
    Jan 2012
    Location
    Grid EN19MV
    Posts
    159

    Default Using floating point

    First off, I should mention that math and I don't get along very well.....

    I doing a complete redesign of my charcoal smoker temperature controller. It worked very well, but I made some hardware mistakes when I designed the board, and I ran out of memory on the 16F886 I was using BEFORE I ran out of features I wanted to add.

    To that end, I redesigned the board for an 18F2550, and decided on a fresh start with the program as I made some poor efficiency decisions on the first one. I am using Henrik's PID routines as before, and DT's Analog oversampling this time.

    I want to have the temperature displays have one decimal place instead of just integer, so I am trying to comprehend the floating point example in 4FUNC.BAS (provided by MELabs). I am currently at work (testing a fire alarm system in a huge building), but I am basically sitting here while the Sprinkler Fitter moves around sending in his signals once in a while. That means I have time to play a bit.

    C_TEMP and COOK_ADJUST are word variables.

    Can someone 'vet' the following code and let me know if I'm on the right track here? Any suggestions or advice would be appreciated. I have tried to whittle down the example code so it only works for one decimal place. I have included the 18F 24-bit include file at the beginning of the program.

    Thanks

    Code:
    	
        C_TEMP = C_TEMP * 100 	'MULTIPLY RAW ADC READING BY 100 THEN DIVIDE BY CALIBRATION VALUE TO GET
    							'CELCIUS TEMPERATURE
        aint = C_TEMP
        resulthold = aint
        Gosub itofa     	' Convert aint to float  
        bint = COOK_ADJUST	'DIVIDE BY ADJUST VALUE TO GET CELCIUS
        Gosub itofb     	' Convert int to float
        Gosub fpdiv     	' FP divide (/ COOK_ADJUST)
        resulthold = aint	'STORE RESULT OF DIVISION IN RESULTHOLD
        'NOW NEED TO CONVERT CELCIUS TO FARENHEIGHT
        'F = ((C * 9) / 5) + 32
        Gosub itofa     	' Convert aint to float  aint=result from divide
        bint = 9
        Gosub itofb     	' Convert int to float
        Gosub fpmul     	' FP multiply (*9)
        resulthold = aint	'STORE RESULT OF MULTIPLICATION IN RESULTHOLD	
        Gosub itofa     	' Convert int back to float - aint=result from multiply
        bint = 5
        Gosub itofb     	' Convert int to float
        Gosub fpdiv     	' FP divide (/5)
        resulthold = aint	'STORE RESULT OF DIVISION IN RESULTHOLD	
        Gosub itofa			' Convert aint to float
        bint = 32
        Gosub itofb			' Convert bint to float
        Gosub fpadd			' FP add (+32)	
        fpplaces = 1 		'DISPLAY WITH ONE DECIMAL PLACE
        Gosub fpdisplayr				' Call display routine
    
        'OTHER STUFF
    	
    fpdisplayr: 
        'I DISPENSED WITH THE IF STATEMENTS, ONLY EVER WANT ONE DECIMAL PLACE
        ' Set floating point barg to 0.05
        bexp = $7A
        bargb0 = $4C
        bargb1 = $CD
    	
    fpdisplay:	
        bexp = aexp					' Store the FP value of aarg to the barg variables
        bargb0 = aargb0
        bargb1 = aargb1
        Gosub ftoia					' Convert aarg to integer
        ahold = aint				' Save this value for the final display
        Gosub itofa					' Convert integer back to float
        Swap aexp,bexp				' Swap the FP values of aarg and barg before subtraction
        Swap aargb0,bargb0
        Swap aargb1,bargb1
        Gosub fpsub					' Subtract the integer portion from the full number
        bint = 10					' Make bint = 10 E fpplaces		
        Gosub itofb					' Convert bint to integer prior to FP multiply
        Gosub fpmul					' Multiply the decimal portion x 10 E fpplaces
        Gosub ftoia					' Convert result to aint integer
        'DISPLAY    CT:xxx.x COOKER TEMP TO ONE DECIMAL PLACE
        Lcdout $FE, 1, "CT:", dec abs ahold, ".", dec abs aint
        RETURN
    "I have noticed that even those who assert that everything is predestined and that
    we can change nothing about it still look both ways before they cross the street"


    -Stephen Hawking

  2. #2
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    947


    Did you find this post helpful? Yes | No

    Default Re: Using floating point

    I usually avoid use of floating point on a processor that does not have native support for it. It is an intensive computation and in most cases will eat up a sizeable amount of time to achieve the same result that you could with clever integer manipulations. In your case, you seem pretty clear you need fixed point arithmetic and so it is easier. You may need 32 bit integers to handle larger numbers.

    In your case, the equations you show boil down to these

    Assuming Temp is the input temperature read via the ADC and you want to calibrate the reading by temp*100/calc_adjust

    Temp = Temp *100 ' max temp = 65535/100 ($FFFF hex)
    Temp = Temp / Cook_Adjust ' Divide and keep the integer part of result.

    Assuming you want a 0.1 deg resolution, I would do this (keep in mind the largest value that Temp can hold. Temp*1000 will define the limit of temperature going into the routine)
    Temp = (Temp*1000)/Cook_Adjust (max input temp is now 65 since 65*1000 approximately fills the 16b integer)
    You could also do this
    Temp = (Temp*100) / (Cook_Adjust / 10) (max input temp is 650. However, cook_adjust should be multiples of 10 to impact the calculations)

    Now, convert to F
    Temp = Temp + (Temp << 3) ' mul by 9 x + 8*x = 9x
    Temp = Temp / 5 ' div by 5
    Temp = Temp + (32*10) ' add 32 with 1 decimal accounted for

    and display it by splitting the value thus
    Display Temp / 10, ".", Temp MOD 10

    You need to specify your input range to make this technique practical for you.

  3. #3
    Join Date
    Jan 2012
    Location
    Grid EN19MV
    Posts
    159


    Did you find this post helpful? Yes | No

    Default Re: Using floating point

    Well, as far as temperature ranges go, the cooker temp can be as high as 500F. The meat temp as high as 230F.

    The adjust value for the raw ADC value is actually 1.64 for the meat thermocouple I am using. That was the reason for the 'times 100'.

    I suppose it could be done with longs since I am using an 18F2550?

    Thanks again for the advice
    "I have noticed that even those who assert that everything is predestined and that
    we can change nothing about it still look both ways before they cross the street"


    -Stephen Hawking

  4. #4
    Join Date
    Jan 2012
    Location
    Grid EN19MV
    Posts
    159


    Did you find this post helpful? Yes | No

    Default Re: Using floating point

    Quote Originally Posted by Jerson View Post

    Assuming you want a 0.1 deg resolution, I would do this (keep in mind the largest value that Temp can hold. Temp*1000 will define the limit of temperature going into the routine)
    Temp = (Temp*1000)/Cook_Adjust (max input temp is now 65 since 65*1000 approximately fills the 16b integer)
    You could also do this
    Temp = (Temp*100) / (Cook_Adjust / 10) (max input temp is 650. However, cook_adjust should be multiples of 10 to impact the calculations)

    Now, convert to F
    Temp = Temp + (Temp << 3) ' mul by 9 x + 8*x = 9x
    Temp = Temp / 5 ' div by 5
    Temp = Temp + (32*10) ' add 32 with 1 decimal accounted for

    and display it by splitting the value thus
    Display Temp / 10, ".", Temp MOD 10

    You need to specify your input range to make this technique practical for you.
    Well then, that seems a LOT easier now that I've had time to look at it. I'm going to use longs so that my max temp will fit and do the * 1000.

    Thanks for the help!
    "I have noticed that even those who assert that everything is predestined and that
    we can change nothing about it still look both ways before they cross the street"


    -Stephen Hawking

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,521


    Did you find this post helpful? Yes | No

    Default Re: Using floating point

    Hi,
    So you have a raw reading which you want to divide by 1.64, is that correct? Or do you want to multiply the raw value by 1.64?

    TempC = TempC ** 39961 ' Multiplu by 0.60976 which is the same as dividing by 1.64

    or

    TempC = TempC */ 420 ' Multiply by ~1.641

    or

    TempC = TempC + (TempC ** 41943) ' Multiply by 0.64 and add result to previous value.

    If neither of these works can you give us a bit more details about how the raw values correlates to actual temperature. Ie what raw value do you get at 0 temp and what raw value do you get at max temp (500 degrees in this case).

    /Henrik.

  6. #6
    Join Date
    Jan 2012
    Location
    Grid EN19MV
    Posts
    159


    Did you find this post helpful? Yes | No

    Default Re: Using floating point

    Quote Originally Posted by HenrikOlsson View Post
    Hi,
    So you have a raw reading which you want to divide by 1.64, is that correct? Or do you want to multiply the raw value by 1.64?

    TempC = TempC ** 39961 ' Multiplu by 0.60976 which is the same as dividing by 1.64

    or

    TempC = TempC */ 420 ' Multiply by ~1.641

    or

    TempC = TempC + (TempC ** 41943) ' Multiply by 0.64 and add result to previous value.

    If neither of these works can you give us a bit more details about how the raw values correlates to actual temperature. Ie what raw value do you get at 0 temp and what raw value do you get at max temp (500 degrees in this case).

    /Henrik.
    Divide by 1.64. I found that the meat thermocouple in boiling water required me to divide by 1.64 to get 100C. The cooker thermocouple was a similar (but slightly different) number. In reality, I have a calibration routine that determines the number then it is stored in COOK_ADJUST or MEAT_ADJUST. This is so I can easily correct if a new thermocouple is installed.

    After reading Jerson's post, I changed C_TEMP and M_TEMP (the cooker and meat raw ADC values, respectively) to LONGS. I came up with the following that I will try when I finish building the new board:

    Code:
     	C_TEMP = C_TEMP * 1000
    	C_TEMP = C_TEMP / COOK_ADJUST 'ADJUST * 1000
    	C_TEMP = C_TEMP + (C_TEMP << 3) ' mul by 1 x + 8*x = 9x
    	C_TEMP = C_TEMP / 5 ' div by 5
            C_TEMP = C_TEMP + 320 ' add 32 with 1 decimal accounted for
    	M_TEMP = M_TEMP * 1000
    	M_TEMP = M_TEMP / MEAT ADJUST
    	M_TEMP = M_TEMP + (M_TEMP << 3) ' mul by 1 x + 8*x = 9x
    	M_TEMP = M_TEMP / 5 ' div by 5
            M_TEMP = M_TEMP + 320 ' add 32 with 1 decimal accounted for	
    		           'CT:nnn.nF  MT:nnn.nF
    	LCDOUT $FE, $80, "CT:", DEC3 (C_TEMP / 10), ".", DEC1 (C_TEMP MOD 10), "F"
    	LCDOUT $FE, $80 + 9, "  ", "MT:", DEC3 (M_TEMP /10), ".", DEC1 (M_TEMP MOD 10), "F"
    I think this will work. Opinions?
    Last edited by andywpg; - 24th February 2015 at 19:59.
    "I have noticed that even those who assert that everything is predestined and that
    we can change nothing about it still look both ways before they cross the street"


    -Stephen Hawking

  7. #7
    Join Date
    Jan 2012
    Location
    Grid EN19MV
    Posts
    159


    Did you find this post helpful? Yes | No

    Default Re: Using floating point

    Henrik, I just had a thought. How is the fact that I changed my temperature value to a long going to affect your PID routine? Specifically, pid_error and my set point are words, the actual temperature is a long.

    I've never used longs before, can you mix them with words? And I guess that I will have to use C_TEMP / 10 to get the integer portion in the equation: pid_error = setpoint - temperature?
    "I have noticed that even those who assert that everything is predestined and that
    we can change nothing about it still look both ways before they cross the street"


    -Stephen Hawking

  8. #8
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    947


    Did you find this post helpful? Yes | No

    Default Re: Using floating point

    Andy, your code looks workable. To simplify things, I use a tool from http://www.miscel.dk called miscellaneous electronic calculations. In that you will find an integer math module that tells you 1.64 is same as 41/25 if you want to use 8 bit math. It's a nice tool to augment your collection and I suggest you give it a try

  9. #9
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,521


    Did you find this post helpful? Yes | No

    Default Re: Using floating point

    Henrik, I just had a thought. How is the fact that I changed my temperature value to a long going to affect your PID routine? Specifically, pid_error and my set point are words, the actual temperature is a long.
    It doesn't really matter as long as you make sure that you don't overflow the pid_Error variable. And remember that pid_Error is a two's complement variable so anything above 32767 is considered negative.

    I've never used longs before, can you mix them with words?
    Yes, a LONG minus a LONG can still fit a WORD or even a BYTE. There MAY be some differences when it comes to multiplications because LONGs are signed while WORDS and BYTES are not - I'd take a look at the manual in case it's mentioned there.

    And I guess that I will have to use C_TEMP / 10 to get the integer portion in the equation: pid_error = setpoint - temperature?
    The general rule is to have the PID routine work with your raw numbers as long as the raw numbers aren't big enough to risk overflowing. There's no need for "empty resolution". The PID routine is just crunching numbers, it doesn't know what the numbers mean or represent so there's no need to have the values scaled to degrees C or whatever. As long as YOU remember to have the setpoint and actual temp variable scaled equally when you calculate pid_Error it'll be fine - then you can scale those value up or down all you want for humans to be able to make sense out of them ;-)

    /Henrik.

Similar Threads

  1. Using floating point
    By andywpg in forum PBP3
    Replies: 0
    Last Post: - 24th February 2015, 16:42
  2. Floating point math
    By Glenn in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 5th January 2009, 03:47
  3. Getting out of floating point
    By jcb344 in forum General
    Replies: 3
    Last Post: - 5th August 2008, 21:18
  4. Floating Point
    By jrudd in forum mel PIC BASIC Pro
    Replies: 0
    Last Post: - 15th May 2005, 14:19
  5. help floating Point!
    By Eric in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 7th December 2003, 21:18

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts