First, a little background: I've always programmed PICs (12F, 16F, 18F, dsPIC30F) in pure ASM via MPLAB IDE. A few years back, I was quite tickled when I came across GreatCowBasic...about as pure of a "BASIC" for PICs as could be found. Obviously, my ASM background comes in very handy when debugging a GCB project.
All that to say that I'm quite aware of the challenges and difficulties encountered when using numbers over 8 bits in an 8-bit CPU--and of the absolute terror of FLOAT in such CPUs!
I'm no stranger to doing fractional division in whole numbers; for example, I have the following equation to solve (calculating the voltage at an A/D input):
vMeasured = (5vRef / 1024[ADCMax]) * ADC
The first part results in a multiplier of 0.004882813. Easy: multiply that number by a power of 2 (0.004882813 * (2^16)[=65536] = 320), but I want two digits of precision, so multiply the multiplier by 100 = 32000. Now I just have to do a LONG multiplication by that multiplier, followed by a bit-shift division by the original power of 2, with the following solution:
Voltage = FnLSR(32000 * ADC, 16). (Could also simply read the top two bytes of the LONG...)
Easy peasy, resulting numbers from 0 to 499 (0.00 - 4.99v). It's a piece of cake to insert a decimal point on the display with such numbers.
So...my problem: I have an equation to solve that REQUIRES a fractional number (between 0-1) into the LOGE (natural Log) function. Basically, I'm trying to calculate the temperature of an NTC thermistor, using the following (simplified) equation:
It took me a LONG time searching the Internet to find an equation that wasn't all using inverted numbers (i.e. 1/x). I can figure out the entire equation, except for the LOGE--because if I multiply the input by 100, it changes the output number...and not by a factor of 100.
From reading the manual, I see that most of the trig functions give a "x100" output, which is just fine. My question: how do I give them a "x100" input for a fractional number...? Or is there any workaround? Is there a hack for converting NTC thermistor outputs?? I don't need super tight precision, but want it to be fairly close (+/- 5C).
Oh, and ditto for the HPWM function. I'm running a PIC16F15345 @ 1MHz, and getting a 244Hz PWM output (for controlling a cooling fan) takes a little bit of rework...because I can't pass a fractional number to a routine expecting whole KHz. Like this:
HPWM 1, 1, 0 '1KHz, 0% duty
HPWM 2, 1, 0 '1KHz, 0% duty
'...We really want more of a 250Hz PWM, but can't give fractional input to the HPWM function. So will need to manually configure TMR2...
InitTimer2 1, PS2_4, 0 'clock source FOSC/4, prescaler of 4, no postscaler. 250000 / 4 / 256 = 244Hz
PR2 = 255 'ensure full loop...
I tried giving it 0.5...and the end result was a PWM of about 250KHz. Unfortunately, I can't quite figure out a similar workaround for LOGE ;-). Any ideas?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yes, I found the LOGE (natural LOG) function. But the equation gives LOGE a value between 0 and 1--and in an integer environment, that poses quite a problem.
So, if the 10K thermistor is measuring 50 centigrade (=3.592Kohms), the value inputted to the LOGE will be (3592 / 10000) = 0.3592.
That's the link I used to find the above equation...! My problem with option four is that it is the complete Steinberg equation, which requires "A", "B" and "C" values for the thermistor--which I don't have. All I have is that it is a "3950", which requires the Beta calculation.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Microchip MCP9700/9701 thermistors output a linear voltage for the adc to read. Cheap too.
There are a number of PIC enchanced midrange devices that have 16bit PWM like the 12f1572 and 16f1578. That type of resolution will let you home in much closer to your desired PWM frequency.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
True, but that's not the point. I could just buy an LM34 or LM35 and be done with it, too--but I already have 10K 3950 thermistors, and was wondering if there was any SOFTWARE solution in GreatCowBasic for fractional number input into LOGE. It's an extremely capable software suite, and way better than programming in assembler (and it's free!)...I was just hoping to tap into the wizards that made GCB.
Option 6 is probably what I'll have to settle for: RS-232 the thermistor's resistance to a more powerful processor (likely a Raspberry Pi) to convert the number to temperature and display it.
EDIT: My comment about the HPWM routine was NOT that the PIC16F15345 isn't capable of doing what I wanted (it is--I just had to manually reconfigure TMR2 after calling HPWM), but rather that the GCB "HPWM" routine doesn't allow for a calculated output frequency of less than 1KHz. That was all.
Last edit: Siddy 2019-08-06
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Another way to do this is to create a lookup table of ADC values for each temperature (probably for every degree). If you want fractions of a degree use linear interpolation.
That's how I have always done it. The Steinhart-Hart equation is a tricky equation for 8-bit arithmatic.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
First, a little background: I've always programmed PICs (12F, 16F, 18F, dsPIC30F) in pure ASM via MPLAB IDE. A few years back, I was quite tickled when I came across GreatCowBasic...about as pure of a "BASIC" for PICs as could be found. Obviously, my ASM background comes in very handy when debugging a GCB project.
All that to say that I'm quite aware of the challenges and difficulties encountered when using numbers over 8 bits in an 8-bit CPU--and of the absolute terror of FLOAT in such CPUs!
I'm no stranger to doing fractional division in whole numbers; for example, I have the following equation to solve (calculating the voltage at an A/D input):
vMeasured = (5vRef / 1024[ADCMax]) * ADC
The first part results in a multiplier of 0.004882813. Easy: multiply that number by a power of 2 (0.004882813 * (2^16)[=65536] = 320), but I want two digits of precision, so multiply the multiplier by 100 = 32000. Now I just have to do a LONG multiplication by that multiplier, followed by a bit-shift division by the original power of 2, with the following solution:
Voltage = FnLSR(32000 * ADC, 16). (Could also simply read the top two bytes of the LONG...)
Easy peasy, resulting numbers from 0 to 499 (0.00 - 4.99v). It's a piece of cake to insert a decimal point on the display with such numbers.
So...my problem: I have an equation to solve that REQUIRES a fractional number (between 0-1) into the LOGE (natural Log) function. Basically, I'm trying to calculate the temperature of an NTC thermistor, using the following (simplified) equation:
ThermistorC = ((3950×298.15) ÷ (3950 + (298.15 × loge(Resistance / SpecResistance))))-273.15
(3950 = thermistor coefficient; 298.15 = 25C + 0Kevin -> C)
It took me a LONG time searching the Internet to find an equation that wasn't all using inverted numbers (i.e. 1/x). I can figure out the entire equation, except for the LOGE--because if I multiply the input by 100, it changes the output number...and not by a factor of 100.
From reading the manual, I see that most of the trig functions give a "x100" output, which is just fine. My question: how do I give them a "x100" input for a fractional number...? Or is there any workaround? Is there a hack for converting NTC thermistor outputs?? I don't need super tight precision, but want it to be fairly close (+/- 5C).
Oh, and ditto for the HPWM function. I'm running a PIC16F15345 @ 1MHz, and getting a 244Hz PWM output (for controlling a cooling fan) takes a little bit of rework...because I can't pass a fractional number to a routine expecting whole KHz. Like this:
HPWM 1, 1, 0 '1KHz, 0% duty
HPWM 2, 1, 0 '1KHz, 0% duty
'...We really want more of a 250Hz PWM, but can't give fractional input to the HPWM function. So will need to manually configure TMR2...
InitTimer2 1, PS2_4, 0 'clock source FOSC/4, prescaler of 4, no postscaler. 250000 / 4 / 256 = 244Hz
PR2 = 255 'ensure full loop...
I tried giving it 0.5...and the end result was a PWM of about 250KHz. Unfortunately, I can't quite figure out a similar workaround for LOGE ;-). Any ideas?
We have support for Loge. Is this not working for you?
Yes, I found the LOGE (natural LOG) function. But the equation gives LOGE a value between 0 and 1--and in an integer environment, that poses quite a problem.
So, if the 10K thermistor is measuring 50 centigrade (=3.592Kohms), the value inputted to the LOGE will be (3592 / 10000) = 0.3592.
Thusly, ((3950×298.15) ÷ (3950 + (298.15 × loge(3592 / 10000))))-273.15 === 49.9719 centigrade.
The LOGE of 0.3592 = −1.023875943
...but LOGE of 35.92 = 3.581294243
Is there any workaround? I'm not any good at algebra or calculus, so maybe there's a glaringly obvious solution that I just don't see.
This road must have been walked before... :-)
See https://www.allaboutcircuits.com/projects/measuring-temperature-with-an-ntc-thermistor/ the four option looks appropiate.
That's the link I used to find the above equation...! My problem with option four is that it is the complete Steinberg equation, which requires "A", "B" and "C" values for the thermistor--which I don't have. All I have is that it is a "3950", which requires the Beta calculation.
Option 5, let the hardware do the work.
Microchip MCP9700/9701 thermistors output a linear voltage for the adc to read. Cheap too.
There are a number of PIC enchanced midrange devices that have 16bit PWM like the 12f1572 and 16f1578. That type of resolution will let you home in much closer to your desired PWM frequency.
True, but that's not the point. I could just buy an LM34 or LM35 and be done with it, too--but I already have 10K 3950 thermistors, and was wondering if there was any SOFTWARE solution in GreatCowBasic for fractional number input into LOGE. It's an extremely capable software suite, and way better than programming in assembler (and it's free!)...I was just hoping to tap into the wizards that made GCB.
Option 6 is probably what I'll have to settle for: RS-232 the thermistor's resistance to a more powerful processor (likely a Raspberry Pi) to convert the number to temperature and display it.
EDIT: My comment about the HPWM routine was NOT that the PIC16F15345 isn't capable of doing what I wanted (it is--I just had to manually reconfigure TMR2 after calling HPWM), but rather that the GCB "HPWM" routine doesn't allow for a calculated output frequency of less than 1KHz. That was all.
Last edit: Siddy 2019-08-06
Another way to do this is to create a lookup table of ADC values for each temperature (probably for every degree). If you want fractions of a degree use linear interpolation.
That's how I have always done it. The Steinhart-Hart equation is a tricky equation for 8-bit arithmatic.