View previous topic :: View next topic |
Author |
Message |
varadharaj
Joined: 09 Apr 2012 Posts: 19 Location: Salem
|
ntc interfacing with pic microcontroller |
Posted: Sat May 26, 2012 6:23 am |
|
|
Hi,
I am interfacing NTC 10k with pic microcontroller by voltage divider circuit.
The +5v supply is connected with 10k resistor (1/4 watts, 1%tolerance). The other end of 10k is connected to the ntc 10k. Other end of ntc is connected to ground.
The ntc and 10k interconnection point is connected to 100k resistor. The other end of 100k resistor is connected to the a0 of pic microcontroller 16f877a. 0.1uf is taken from the a0 pin to ground.
All the resistors, i have taken are 1% tolerance. The output will be in lcd. The problem is the value is jumping always.for example, it is showing 30.4 in the next second, it is showing 31.2 without changing anything. next it is changing to 30.4. Can we arrest the jumping. And also If i change the temperature by heating it, it is jumping. I expect it to increase by 0.1 step. I have given the code below. Please suggest me to eliminate this jumping problem.
Code: |
#include <16f877a.h>
#device adc=10
#fuses XT,NOWDT,NOLVP
#use delay(clock=4000000)
#separate
void adc_calc()
{
float step_value,volt_value,temp_value;
set_adc_channel(0); // water temp
delay_ms(100);
step_value = read_adc();
// this calculation is for linearizing the output of adc
volt_value = (step_value * 5) / (float)1024;
if(volt_value >= 2.759 && volt_value <= 5)
temp_value = -(24.4688 * volt_value) + 88.3155 ;
else if(volt_value <= 2.663 && volt_value >= 0.936)
temp_value = (-27.536 * volt_value) + 91.516 ;
else if(volt_value <= 0.894 && volt_value >= 0.462)
temp_value = -(67.4352 * volt_value)+ 129.6397 ;
lcd_gotoxy(1,1);
if(step_value > 950 || step_value < 20)
{
printf(lcd_putc,"Sen Open ");
open_flag = 0;
output_high(pin_b1);
output_high(pin_b0);
lcd_gotoxy(1,2);
printf(lcd_putc,"Change");
}
else if(open_flag == 1)
{
if((temp_value - buffer ) >= 0.5 || (temp_value - buffer) <= -0.5)
temp_value = temp_value;
else
temp_value = buffer;
printf(lcd_putc,"T:%3.1fC ",temp_value);
}
lcd_gotoxy(1,2);
if(temp_value > inlet_set_temp_max && open_flag == 1)
{
printf(lcd_putc,"T:Hi");
}
if(temp_value < inlet_set_temp_min && open_flag == 1)
{
printf(lcd_putc,"S:ON");
output_low(pin_b0); // solenoid on
output_high(pin_b1); // fan off
output_high(pin_a1);
output_low(pin_a3);
flag_sol = 1;
}
if(temp_value < inlet_set_temp_max && temp_value > inlet_set_temp_min && flag_sol == 0 && open_flag == 1)
{
printf(lcd_putc,"F:ON");
output_low(pin_b1); // fan on
output_high(pin_b0); // solenoid off
output_low(pin_a1);
output_high(pin_a3);
}
if(flag_sol == 1)
{
if(temp_value > (inlet_set_temp_min + Diff_inlet))
flag_sol = 0;
else if(temp_value > inlet_set_temp_min)
printf(lcd_putc,"S:ON");
}
delay_ms(300);
buffer = temp_value;
}
void main()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_INTERNAL);
while(1)
{
adc_calc();
}
} |
_________________ Embedding Innovation |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Sat May 26, 2012 7:01 am |
|
|
The ADC can make a lot of readings in a short time relative to your need to report it via your LCD. Why not use a moving average. It is fast if you use 16 for this. Avg value=last_avg_value-last_avg_value/16 +this value/16.
Init last_avg_value to the initial read of the ADC. You can improve upon it by casting out anomalies relative to the average..Ex a 2 degree jump is cast out. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Sat May 26, 2012 7:37 am |
|
|
In your adc_calc() function you're delaying 100ms which is a HUGE amount of time, so the RTC can change dramatically from reading to reading.
It is best to take several readings and average them (8 or 16 works well). This is software averaging.
You may need a 1mfd cap or more to smooth out the RTC voltage to ADC input. This is hardware averaging.
Also if the +5 supply is NOT tightly regulated to say 1%, the readings will never be stable or accurate. Any extra current demands by your circuit will 'dip' the Vdd( +5) and affect the ADC.
Your program refers to a solenoid...it must have a diode across it to reduce EMI and be sure the power supply can handle the high current demand for it as well.
Any noise or spikes will show up as 'bad' RTC/ADC readings. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sat May 26, 2012 1:10 pm |
|
|
What happens if you replace the 10k & ntc with a multi-turn pot. then SLOWLY rotate the adjuster?
Mike |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Sat May 26, 2012 2:40 pm |
|
|
You can also just replace the RTC with a fixed resistor (say 2.49K) and just loop forever....to see how stable the system is. Display both raw data(ADC bits), computed voltage and temperature.
If the reading varies say 3-4 bits that not too bad for overall noise.
Then you can say add filter caps, here and there, to tweak the performance to reduce the noise down to say 1-2 bits. Pretty good really 1/512-1/1024.
Once you're satisfied with this 'base level' test, then replace the fixed resistor with the RTC. All things considered it should be OK. If the reading is not 'solid', you probably have noise coming in through the RTC. |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Sat May 26, 2012 4:34 pm |
|
|
Print out the raw A/D counts instead of calculating the temperature. If the count is only jumping 1 count that is the best you can do without a higher resolution A/D. If it is jumping several counts you may have a noise problem in your circuit.
Search the forum for "Olympic average" to find a very simple fast effective way to smooth A/D readings. Here is some code:
Code: |
int16 olympic_ten(void) {
int16 imax=0;
int16 imin=1023;
int16 isum=0;
int16 itemp;
int8 ctr;
for (ctr=0;ctr<10;ctr++) {
itemp=read_adc();
if (itemp<imin) imin=itemp;
if (itemp>imax) imax=itemp;
isum+=itemp;
delay_us(250);
}
//Now have the sum of ten readings, and the max/min readings
isum-=imin;
isum-=imax; //subtract the min and max from the sum leaving 8 readings
itemp=isum/8; //compiler will automatically optimise this to a shift
return itemp;
} |
_________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
|