|
|
View previous topic :: View next topic |
Author |
Message |
viki2000
Joined: 08 May 2013 Posts: 233
|
PIC10F322 - Internal Temperature Indicator |
Posted: Fri Jul 24, 2015 6:10 am |
|
|
I have read next 2 posts:
https://www.ccsinfo.com/forum/viewtopic.php?p=162517
http://www.ccsinfo.com/forum/viewtopic.php?t=50053&view=next
I use next code:
Code: | #include <10F322.h>
#use delay(internal=16000000)
#use FIXED_IO( A_outputs=PIN_A2 )
unsigned char i, TEMPX;
void TX(unsigned char TEMP);
void main(){
setup_vref(TEMPERATURE_INDICATOR_ENABLED | TEMPERATURE_RANGE_HIGH);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(TEMPERATURE_INDICATOR);
while(TRUE){
TEMPX=read_adc();
TX(TEMPX);
delay_ms(100);
}
}
void TX(unsigned char TEMP){
output_low(PIN_A2);
delay_us(412);
for (i = 0; i < 8; i++){
if( ((TEMP>>i)&0x1) == 0x1)
{
output_high(PIN_A2);
}
else
{
output_low(PIN_A2);
}
delay_us(406);
}
output_high(PIN_A2);
delay_us(416);
} |
The code works, but is not calibrated.
If I use the formula from AN1333 the result is impossible.
http://ww1.microchip.com/downloads/en/AppNotes/01333A.pdf
http://microchip.wikidot.com/8bit:temp
I try to measure the internal temperature of the PIC10F322.
The result is a 8bit value which I store it in a variable TEMPX and I send it to one pin (RA2) using RS232 Bit Banging (RS232 software emulation) with 2400 baud rate (416us for each bit).
I read the RS232 with PIC18F4550 and I display it on a small OLED.
I know the RS232 communication works, because if I set a fixed known value for the TEMPX in PIC10F322 is seen correctly on OLED.
I can heat it up with a air heat gun and I can cool it down to -30°C with a spray used for such dedicated purpose in electronics.
I would like to use this internal temperature indicator with a precision of +/-10°C. I do not need a better precision. I only need to know if is very cold or very hot.
The problem is the AD conversion value obtained when I measure the internal temperature indicator.
It has a strange value in the range 1-37. If I heat up more then goes more than 37. Basically at 24°C ambient temperature, the AD conversion result of the temperature indicator is around 12. Below 0°C the result is 1 and then lower jumps to 127. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Fri Jul 24, 2015 7:08 am |
|
|
It seems the internal temp sensor isn't the best choice and I wonder WHY Microchip included it in the PICs. Too many variables to consider and do the 'math' for in calibration. It's far simpler and more accurate to use an LM34,MCP790? or even a DS1820 type temp. sensor. I know you only need 'hot' or 'cold' but the amount of time getting the internal to work right doesn't seem justified. Add a 20 cents LM34 and be up and running in minutes.
Also...
Instead of you're serial function, why not use the CCS #USE RS232(...) ? It'll create a proper software serial port for you without you having to deal with 'timing' issues.
just ideas....
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Fri Jul 24, 2015 10:20 am |
|
|
It's main design is to allow you to know if the PIC is getting 'too hot'. It's fairly easy to use for this. A single point calibration, and 90% of the maths can be done in advance so you just look for the reading going above a specified level.
As Temtronic says, using it for anything much beyond this gets really awkward.
It depends massively on how much of your code space is available. To use it for a reasonable temperature reading, there needs to be a two point calibration, so 'lots of code'. Given the small ROM space in the chip, if you are doing much else, it gets difficult.... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 24, 2015 10:52 am |
|
|
You're missing the 200 usec initial delay. The 10F322 data sheet says:
Quote: | 14.4 ADC Acquisition Time
To ensure accurate temperature measurements, the
user must wait at least 200 us after the ADC input
multiplexer is connected to the temperature indicator
output before the conversion is performed. In addition,
the user must wait 200 us between sequential
conversions of the temperature indicator output |
Without this delay, your first reading will be incorrect. To fix this,
add the line of code shown below:
Quote: |
setup_vref(TEMPERATURE_INDICATOR_ENABLED | TEMPERATURE_RANGE_HIGH);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(TEMPERATURE_INDICATOR);
delay_us(200);
while(TRUE){
TEMPX=read_adc();
TX(TEMPX);
delay_ms(100);
}
} |
Also I wonder why you don't let CCS do the serial port output with this:
Code: |
#use rs232(baud=2400, xmit=PIN_A2)
.
.
.
while(TRUE){
TEMPX=read_adc();
putc(TEMPX);
delay_ms(100);
}
|
It takes less code than your TX() routine.
Quote: | #use delay(internal=16000000)
setup_adc(ADC_CLOCK_DIV_8); |
This is not the correct clock divisor for 16 MHz. The following table
in the PIC data sheet shows you must use at least Div by 16:
Quote: | TABLE 15-1: ADC CLOCK PERIOD (TAD) VS. DEVICE OPERATING FREQUENCIES |
Finally, what is the Vdd voltage on your PIC ? The reason I ask is because
the PIC data sheet says Vdd must be a minimum of 3.6v if you use the
high temperature range setting.
Quote: |
14.2 Minimum Operating VDD vs. Minimum Sensing Temperature
When the temperature circuit is operated in low range,
the device may be operated at any operating voltage
that is within specifications.
When the temperature circuit is operated in high range,
the device operating voltage, VDD, must be high
enough to ensure that the temperature circuit is
correctly biased. |
|
|
|
viki2000
Joined: 08 May 2013 Posts: 233
|
|
Posted: Mon Jul 27, 2015 5:35 am |
|
|
I was aware of the initial 200us delay, but I neglected it for 2 reasons: I did not care about the first reading and I tested the code in different ways, having also the 100ms delay in the beginning.
Here is the full working code now:
Code: | #include <10F322.h>
#use delay(internal=16000000)
#use rs232(baud=2400, xmit=PIN_A2)
unsigned char TEMPX;
void main(){
setup_vref(TEMPERATURE_INDICATOR_ENABLED | TEMPERATURE_RANGE_HIGH);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(TEMPERATURE_INDICATOR);
while(TRUE){
delay_ms(100);
TEMPX=read_adc();
putc(TEMPX);
}
} |
About #use RS232 I was not aware and I wanted to maintain the compatibility with other compilers. I test the same code in parallel with XC8 , which does not have such function implemented, to see which one generates smaller HEX code.
The ADC_CLOCK_DIV_8 was a really mistake. I used 8MHz clock before and I forgot about ADC_CLOCK_DIV_8 when I changed to 16MHz clock. Because is no rush for me I use FRC as ADC clock source which is good for all the PIC frequencies .
The real problem was a RS232 communication problem at the receiver side.
I have read 8 bits, but one was the start bit, always 0, that’s why I got number only up to 127. And additional the shifting was not done at the proper moment. By receiver side, PIC18F4550, I use FlowCode. For who is interested here is the code used. Later I will try to implement also the internal USART inside the PIC18F4550.
https://drive.google.com/file/d/0BwXmKaSw75eKUFI1bko0bDdKZVE/view?usp=sharing
By the way, I do not know how do you debug/synchronize serial communications, but what I do is I generate markers at the receiver side. I turn on/off a pin somewhere in the middle of the code when I read the bit, if the protocol is software written, and I look on oscilloscope at that pin using a seconds channel – seen as a marker at the bit reading moment – and the first channel has the sender output. Then I adjust the timing to synchronize the markers to be in the middle of the reading bits.
Now I receive all the numbers is the range 0-255 and the ADC result of the temperature gives me “normal” acceptable numbers in the expected range 120-154.
There is version B of the AN1333:
http://ww1.microchip.com/downloads/en/AppNotes/00001333B.pdf
At the room temperature I got 137 as ADC result for example, without calibration, tested on 2x PIC10F322.
Using the formula from AN 1333B page 3, I generated a list with the ADC result for different temperatures seen in next Excel file:
https://docs.google.com/spreadsheets/d/1rBOJLwyYqgIp_JZod2CZamyNLYc-HQKMrZYFJ8OyF54/edit?pli=1#gid=865582353
We notice that for each ADC number corresponds 3 up to 4 values of the temperature in case of 8bit ADC as PIC10F322 has, but for 10bit ADC we have 1 ADC number change for 1 degree Celsius.
On the page 5 of AN 1333B there is a graphic with offset error from 12 devices. Comparing with the graphics from page 1 and page 4 I assume the Temperature axes is ticked from 10 to 10 degree Celsius.
I remade the graphic here:
https://drive.google.com/open?id=0BwXmKaSw75eKMURvWVVMQXA2eWc
I see for example that for 1 value of the ADC we can have 40°C error from different PICs if they are not calibrated.
My problem is that I cannot calibrate the PICs.
They will come programmed with my code from Microchip in big quantity.
I will try to investigate if the 40°C error for non-calibrated devices is “reliable”.
Actually I would be still satisfied if without calibration I could rely on 3 ranges: cold -40°C…0°C, normal 0°C…40°C, hot 40°C…85°C.
I will test more PICs with the working code above and I will try to make my own statistics, but probably, eventually I will contact Microchip directly.
Right now, on the bench I use stabilized power supply 5V for VDD, but in real application, just to make the situation worse, the VDD of the PIC is not stabilized and not constant. The VDD will vary between 3.6-4.5V. Then I guess the next step is investigating the Fixed Voltage Reference (FVR) module as described in AN1072
http://ww1.microchip.com/downloads/en/AppNotes/01072A.pdf
Then I could determine the VDD value in the moment of temperature measurement. |
|
|
viki2000
Joined: 08 May 2013 Posts: 233
|
|
Posted: Mon Jul 27, 2015 8:19 am |
|
|
FVR – Fixed Voltage Reference
Here is the code used:
Code: | #include <10F322.h>
#use delay(internal=16000000)
#use rs232(baud=2400, xmit=PIN_A2)
unsigned char TEMPX;
void main(){
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(FVR_CHANNEL);
setup_vref(VREF_1v024);
while(TRUE){
delay_ms(100);
TEMPX=read_adc();
putc(TEMPX);
}
} |
The formula from AN1072 page 2
http://ww1.microchip.com/downloads/en/AppNotes/01072A.pdf
becomes VDD = 1.024*254/(ADC reading).
Below is an Excel table where the VDD is calculated based on ADC result got with the help of FVR.
https://docs.google.com/spreadsheets/d/1_NSSHlYrjQAtG6oR2JvniBdZfoqaYSiwujn-1VIzOeE/edit?usp=sharing
I tested it in the range 3.6V-5.5V with 3x PIC10F322 and works fine.
The error that I got, without any calibration, was 0.04V max. compared with a FLUKE 83 digital multimeter measurements.
Probably for a higher number of PICs the error spread is higher.
If I apply this FVR feature to find VDD, then the error in temperature indicator module will be lower.
I will come back later with more results. |
|
|
viki2000
Joined: 08 May 2013 Posts: 233
|
|
Posted: Tue Jul 28, 2015 1:32 pm |
|
|
Do you have any suggestions how to implement the Temperature formula below which deals with floating numbers using the small memory of the PIC10F322?
The end result does not necessarily have to be a float real number. Rounding the end result to the closest integer is good enough precision. But the calculation should be done with decimal numbers and should be as good as possible, meaning 5 decimal points if we look at 0.00132.
A direct implementation is out of question, even if we break the equation on several lines. Takes too much memory.
For sure are some tricks.
Any suggestions?
http://s926.photobucket.com/user/viki2000/media/Microchip/Temperature%20formula_zpsmleu8hhj.jpg.html |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Tue Jul 28, 2015 3:02 pm |
|
|
You can simplify the math to integers without losing very much precision.
temp C = 459-(194*(255-ADCti)/ADCfvr)
This should get very close if I copied the original equation correctly. |
|
|
viki2000
Joined: 08 May 2013 Posts: 233
|
|
Posted: Wed Jul 29, 2015 12:35 am |
|
|
Thank you for suggestion.
I went through the steps too:
Temperature = [0.659 – (65.28/ADCfvr)*(1-ADCti/255)]/0.00132 – 40
Temperature = 0.659/0.00132 – (65.28/ADCfvr)*(1-ADCti/255)/0.00132 – 40
Temperature = 499.2424 – (65.28/ADCfvr)*(1/255)*(255-ADCti)/0.00132 – 40
Temperature = 459.2424 – (65.28/(255*0.00132*ADCfvr)*(255-ADCti)
Temperature = 459.2424 – (193.9393/ADCfvr)*(255-ADCti)
Approximated to:
Temperature = 459 – (194*(255-ADCti)/ADCfvr)
There is one problem to it.
The code with the above formula takes 15% more flash memory than without it.
I expect the division is taking too much resources.
Any trick to reduce the ROM memory used? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Wed Jul 29, 2015 1:22 am |
|
|
Not really. I refer you to my original answer:
"To use it for a reasonable temperature reading, there needs to be a two point calibration, so 'lots of code'. Given the small ROM space in the chip, if you are doing much else, it gets difficult...."
It is really silly that they supply this feature, on chips that barely have enough code space to use it.
However if the integer version is taking more ROM, then it suggests you are not using it right. Post what you are doing. |
|
|
viki2000
Joined: 08 May 2013 Posts: 233
|
|
Posted: Wed Jul 29, 2015 1:50 am |
|
|
What I am doing is reading the ADCfvr, then ADCti, then I try some calculation of the temperature – where I have the problem now. All these 3 variables of 8 bit I send serial from PIC10F322 to PIC18F184550 to see the results on a display in order to understand what the PIC10F322 is doing inside and where might be a mistake.
ADCfvr and ADCti are correct, but the Temperature is not right. All 3 should be an 8 bit integer in the range 0-255, including the temperature, so it should be no problem when I send/receive them serial each one as a byte. The communication is tested and working with the numbers in the range 0-255.
Here is the code that I use, for sure with necessary correction where the Temperature formula is implemented:
Code: | #include <10F322.h>
#use delay(internal=16000000)
#use rs232(baud=2400, xmit=PIN_A2)
unsigned char ADCfvr, ADCti, TEMPY;
float TEMP;
void main(){
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_INTERNAL);
while(TRUE){
delay_ms(100);
set_adc_channel(FVR_CHANNEL);
setup_vref(VREF_1v024);
delay_ms(1);
ADCfvr=read_adc();
delay_ms(1);
setup_vref(TEMPERATURE_INDICATOR_ENABLED | TEMPERATURE_RANGE_HIGH);
set_adc_channel(TEMPERATURE_INDICATOR);
delay_ms(1);
ADCti=read_adc();
delay_ms(1);
TEMP = 459-(194*(255-ADCti)/ADCfvr);
TEMPY=(int8)TEMP;
putc(1);
delay_ms(15);
putc(ADCfvr);
delay_ms(15);
putc(2);
delay_ms(15);
putc(ADCti);
delay_ms(15);
putc(3);
delay_ms(15);
putc(TEMPY);
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Wed Jul 29, 2015 2:30 am |
|
|
No wonder!....
1) You are still using float.
2) You need int16 values, not int8.
Not tested, but the point is to work in integer.
Code: |
#include <10F322.h>
#use delay(internal=16000000)
#use rs232(baud=2400, xmit=PIN_A2)
unsigned int16 ADCfvr, ADCti, TEMPY;
#separate
void pause(void)
{
delay_ms(1);
}
#separate
void lpause(void)
{
delay_ms(15);
}
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_INTERNAL);
while(TRUE)
{
delay_ms(100);
set_adc_channel(FVR_CHANNEL);
setup_vref(VREF_1v024);
pause();
ADCfvr=read_adc();
pause();
setup_vref(TEMPERATURE_INDICATOR_ENABLED | TEMPERATURE_RANGE_HIGH);
set_adc_channel(TEMPERATURE_INDICATOR);
pause();
ADCti=read_adc();
pause();
TEMPY = 459-(194*(255-ADCti)/ADCfvr);
putc(1);
lpause();
putc(ADCfvr);
lpause();
putc(2);
lpause();
putc(ADCti);
lpause();
putc(3);
lpause();
putc(TEMPY);
}
}
|
Just #separate-ing the two repeated delays saves 2%. Then going integer for the maths saves 10%. |
|
|
viki2000
Joined: 08 May 2013 Posts: 233
|
|
Posted: Wed Jul 29, 2015 3:17 am |
|
|
Thank you.
That worked good.
Now I can see correctly those 3 values on the display, including the temperature.
Next step will be to prepare a setup to test 20-30 PIC10F322 and see what differences do I get for the temperature indicator without calibration.
I will post here later the results.
One more thing noticed is the fact the temperature is in the range -40…+85, so also negative. That is not good for serial transmission. So I modify the formula to by adding the offset 40:
TEMPY = 499-(194*(255-ADCti)/ADCfvr);
And I subtract -40 at the receiver side.
In this way I get only positive numbers to be sent via RS232 and I see also negative temperature values on the display. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Wed Jul 29, 2015 3:51 am |
|
|
Depends if your chip is ever going to get this cold. |
|
|
viki2000
Joined: 08 May 2013 Posts: 233
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|