|
|
View previous topic :: View next topic |
Author |
Message |
Eleengnrng
Joined: 21 Apr 2006 Posts: 6
|
ADC Problem hope it is not common cant find in Forum? |
Posted: Mon Jul 31, 2006 1:03 pm |
|
|
Hello here is my problem i am using PIC 16F877A, using channel 0 as my ADC line. the ADC line is conected to an opamp and that is connected to AD597. This is to measure temperature. the ad597 has a tempeature accuracy to about 10mV per degree C. i am using the pic as 8 bit AD which gives me a aprox 20mV per step. the opamp is aranged to give a gain of 2 which is ajustable depencing on the chips because they are all not the same. I am working with a 20MHZ clock so the aDC Claock is at 20Mhz / 64 = 312.5Khz which is well below 625khz. i am trying to get about ten values at diffrent times and average them together but my result keeps bouncing all over the place here is an example of two ways that i have tryied to average values to gether.
Code: | delay_us(20);
samptemp[x] = tempact(); // gets my infomation from the ADC
tottemp = tottemp + samptemp[x];// Adds current value to var tottemp
x++; // increment the array for next value
if (x>9){
acttemp = tottemp/arrays; // if x > 9 then acttemp gets the average
x=0;
} |
Another way which i have tryied this and got the same results is:
Code: | for (x = 0; x > (arrays-1); x++){
delay_us(20);
samptemp[x] = tempact();
}
for (x = 0; x > (arrays-1); x++){
tottemp = tottemp + samptemp[x];
}
acttemp = tottemp/arrays; |
in this one arrays = 10 and sampletemp[10], so 10 samples averaged together but a result that is all over the chart. i am using timer 2 interupt to do this averaging every 20 seconds.
any help is appreciated. |
|
|
rwyoung
Joined: 12 Nov 2003 Posts: 563 Location: Lawrence, KS USA
|
|
Posted: Mon Jul 31, 2006 1:24 pm |
|
|
1) Post short and COMPLETE program. Can't decern your FUSE statement, configuration of the ADC, declaration of tottemp, samptemp[] or tempact() from example. Include compiler version number too.
2) op-amp circuit has been set up to be single sided, ranging from 0 to Vref, right?
3) Vref is quiet and stable as used by the PIC, right?
4) related to #1, if samptemp[] or tottemp are overflowing you will get odd results.
5) can you get a single good reading from your ADC if you drive it with a relatively low value potentiometer (less than 10K full scale resistance) wired as a rheostat?
6) when you do get things to work, consider a moving average type filter or the "olympic" filter that has been discussed several time in this forum. Using a power-of-2 number of samples into the filter lets you make the filter much more instruction cycle efficient. _________________ Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month! |
|
|
Eleengnrng
Joined: 21 Apr 2006 Posts: 6
|
|
Posted: Tue Aug 01, 2006 6:50 am |
|
|
Here is some extra code to go on:
Code: |
/*-------------------------------------------------------------*/
/* Standard Header */
/*-------------------------------------------------------------*/
#include <16f877A.h>
#device ADC=8
#include "stdlib.h"
#include "stdio.h"
#include "stdlibm.h"
#include "stddef.h"
#fuses HS, NOWDT, PUT, NOBROWNOUT, NOLVP, NOPROTECT
#use delay(clock=20000000)
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)
/*-------------------------------------------------------------*/
/* Outside Function Declarations */
/*-------------------------------------------------------------*/
#include "lcdnewconn.c"
#include "tempread.c"
//#include "Msgtemp.c"
#include "digdec.c"
//#include "scrollingmsg.c"
#define Timer_LOC 0x00 // Timer data Location 5
#define Temp_LOC 0x01 // Temp Data Location 10 EEprom
#define XTAL_FREQUENCY 20000000
#define TIMER1_FREQUENCY (XTAL_FREQUENCY / 4) // 1 clock tick = 1 instr. cycle = crystal frequency / 4
/*--------------------------------------------------------------*/
/* Variable Declaration */
/*--------------------------------------------------------------*/
int8 STSP=0,digit,min=0,mil=0,sec=0,tempsetp=0,tempsetpm,acttemp=0,t=0;
int8 scroll=0,acttemp1,acttemp2,acttemp3,timera,timerb,timerval, x;
int32 Ticker, tottemp, ADRead;
int8 Seconds=0, Choice=0, rawtemp;
int32 dispR = 0, dispH = 0;
//int8 samptemp[10], arrays = 10;
/*--------------------------------------------------------------*/
/* Variable Defintions */
/*--------------------------------------------------------------*/
/*
STSP: Start/Stop (0/1) bit for timer control
Digit: user timer input 0-99 Decimal
Mil: Register counts Milliseconds for timer
Sec: Register counts Seconds for timer
Min: Register counts Minutes for timer
Tempsetp: Register that stores Temperature set point
Tempsetpm: Manipulation register for Temperature set point
Acttemp: Register that contains actual temperature from sensor
T=variable used to offset heating cycle
*/
/*-----------------------RTC Function Intitalzation--------------*/
void Initialize_RTC(void)
{
if (Choice == 1)
{
Ticker = TIMER1_FREQUENCY-dispR; // initialize clock counter to number of clocks per second
}
if (Choice == 2)
{
Ticker = TIMER1_FREQUENCY-dispH; // initialize clock counter to number of clocks per second
}
setup_timer_1( T1_INTERNAL | T1_DIV_BY_1 ); // initialize 16-bit Timer1 to interrupt
// exactly every 65536 clock cycles
// (about 76 times per second)
enable_interrupts( INT_TIMER1 ); // Start RTC
}
/*----------------------END RTC Function Intitalzation----------*/
/*--------------------------------------------------------------*/
/* Interrupt Section */
/*--------------------------------------------------------------*/
void Scroll_MSG();
void Ready_MSG();
#int_EXt
Void Ext_isr()
{
delay_ms(150);
set_tris_c(0xff);//set port c to all inputs
Output_low(Pin_B1);// Output Enable BCD counter
Output_low(Pin_B3);// Dir Bit Pic Chip
Output_low(Pin_B2);// Output Enable Pic Chip
digit=input_c();//input timer data
delay_ms(10);
OUtput_High(Pin_B1);// Output Enable BCD counter
Output_high(Pin_B3);// Dir Bit Pic Chip
Output_low(Pin_B2);// Output Enable Pic Chip
If(STSP==0)//if equal to 0 then its in start mode
{
stsp=stsp+1;//increment stsp
digman(digit,0);//load dig manipulation function with timer data
output_low(Pin_B4);//turn timer buzzer off
Initialize_RTC();
lcd_goto(2,16);
printf(write_LCD,"%c",0x78);
}else if(STSP!=0)//if equal to 1 then its in stop mode
{
digman(digit,0);//load dig manipulation function with timer data
stsp=0;//set STSP back to start position
disable_interrupts( INT_TIMER1 ); // disable RTC
lcd_goto(2,16);
printf(write_LCD,"%c",0x20);
output_low(Pin_B4);//turn off buzzer
Output_low(Pin_B1);// Output Enable BCD counter
Output_high(Pin_B2);// Output Enable Pic Chip
Output_High(Pin_B3);// Dir Bit Pic Chip
}
}//External int routine for Timer
#int_timer1
void TImer1_isr()
{
Ticker -= 65536; // Decrement ticker by clocks per interrupt
if ( Ticker <65536>=150)//make sure tempsetp not 150
{
tempsetp=tempsetp;//if 150 keep it at 150
}else if(tempsetp<150>=0)//if not zero
{
tempsetp=tempsetp-5;//decrement by 5
}
}
/*
if(input(pin_B4)==0)
{
timera++;
if (timera > 9)
{timera=0;}
}
if(input(pin_B7)==0)
{
timerb++;
if (timerb > 9)
{timerb=0;}
}
swap(timera);
timerval = timera&&timerb;
output_C(timerval);
*/
delay_ms(10);
lcd_goto(1,1);
printf(write_LCD,"%3u",tempsetp);//displays temperature set point
lcd_goto(1,4);
printf(write_lcd,"%c",0x0df); //degree symbol
lcd_goto(1,5);
printf(write_lcd,"%c",0x43); //Celcius
lcd_goto(1,6);
printf(write_lcd,"%c",0x20); //Blank
lcd_goto(1,7);
printf(write_lcd,"%c",0x20); //Blank
lcd_goto(1,8);
printf(write_lcd,"%c",0x20); //Blank
lcd_goto(1,9);
printf(write_lcd,"%c",0x20); //Blank
lcd_goto(1,10);
printf(write_lcd,"%c",0x20); //Blank
lcd_goto(1,11);
printf(write_lcd,"%c",0x20); //Blank
lcd_goto(1,12);
printf(write_LCD,"%3u",acttemp);//Display the temperature
lcd_goto(1,15);
printf(write_lcd,"%c",0x0df); //degree symbol
lcd_goto(1,16);
printf(write_lcd,"%c",0x43); //Celcius
enable_interrupts(INT_RB);//enable port B int
}//Port b on change int routine for temp setting
/*----------------------------------------------------------------------*/
/* Main Program */
/*----------------------------------------------------------------------*/
main()
{
SET_TRIS_A (0x2f); //set reg a for temp sensor input
setup_adc_ports(RA0_ANALOG);//set ADC port RA0 to analog
setup_adc(ADC_CLOCK_DIV_64);//Set ADC clock for internal
SET_TRIS_B (0x61); //Misc Data Pins
SET_TRIS_C (0xff); //set port C to all inputs
SET_TRIS_D (0x00); //LCD Data Port
SET_TRIS_E (0x00); //LCD Control Port
port_b_pullups(TRUE);//use internal port b pullup resistors
enable_interrupts(global);//enable all interuppts
enable_interrupts(INT_EXT);//enable ext int
set_adc_channel(0);//set A-D converter channel to 0
ext_int_edge(L_TO_H);//activate on high to low
setup_timer_2(T2_DIV_BY_16,240,13); // temperature refreshes every 10s
enable_interrupts(INT_Timer2);//enable tmr1 int
enable_interrupts(INT_RB);//enable port B int
LCD_init();//Intilize the LCD Display
output_low(Pin_b4);//turn buzzer off
if (READ_EEPROM(Timer_LOC) != 0xff)
digit = READ_EEPROM(Timer_LOC);
if (READ_EEPROM(Temp_LOC) != 0xff)
tempsetp = READ_EEPROM(Temp_LOC);
set_tris_c(0x00);//set port c for all outputs
OUtput_low(Pin_B1);// Output Enable BCD counter
Output_low(Pin_B2);// Output Enable Pic Chip
Output_low(Pin_B3);// Dir Bit Pic Chip
output_c(digit);//output timer data
OUtput_low(Pin_B1);// Output Enable BCD counter
Output_high(Pin_B2);// Output Enable Pic Chip
Output_high(Pin_B3);// Dir Bit Pic Chip
delay_ms(10);
While(True)
{
lcd_goto(1,1);
printf(write_LCD,"%3u",tempsetp);//Display the temperature set point
lcd_goto(1,4);
printf(write_lcd,"%c",0x0df); //degree symbol
lcd_goto(1,5);
printf(write_lcd,"%c",0x43); //Celcius
acttemp1=tempsetp+3;
if (tempsetp != 0)
{acttemp2=tempsetp-3;}
lcd_goto(1,12);
printf(write_LCD,"%3u",acttemp);//Display the temperature
lcd_goto(1,15);
printf(write_lcd,"%c",0x0df); //degree symbol
lcd_goto(1,16);
printf(write_lcd,"%c",0x43); //Celcius
if (acttemp>acttemp2&&acttemp<acttemp1>tempsetp)
{
output_low(Pin_b7);
Choice = 1;
ready_msg();
}else if (acttemp<acttemp2)
{
output_high(Pin_B7);
Choice = 2;
scroll_msg();
}
if (read_eeprom(Timer_LOC) != digit)
{write_eeprom(Timer_LOC,digit);}
if (read_eeprom(Temp_LOC) != tempsetp)
{write_eeprom(Temp_LOC,tempsetp);}
}
}
/*--------------------------------------------------------------*/
/* End Of Main Program */
/*--------------------------------------------------------------*/ |
|
|
|
rwyoung
Joined: 12 Nov 2003 Posts: 563 Location: Lawrence, KS USA
|
|
Posted: Tue Aug 01, 2006 9:40 am |
|
|
Thanks but nearly useless. You still haven't shown how the function
tempact() works and you have commented out your declarations for samptemp[]. Which by the way are 8-bits and you will be overflowing if you keep that up.
Also, on an unrelated note, it is very bad practice to call the delay functions in your interrupt. Likewise calling printf in an interrupt service routine.
Don't post all your code, especially stuff that is irrelevent. Write and post the SMALLEST possible program the exhibits the problem. _________________ Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month! |
|
|
TIMT
Joined: 02 Sep 2005 Posts: 49 Location: Nottingham, UK
|
|
Posted: Wed Aug 02, 2006 1:47 am |
|
|
Hi, I'm having a similar problem with getting stable readings from the A/D converter. My pic is running off 5v with a vref of 1.235v. I've looked at the data sheet for the device (18f452) and it states that with a supply of 5v, vref must not be lower than 3v, the accuracy of the a/d is effected if the difference between the supply voltage and vref is over a certain amount. What's your vref? I'm thinking of changing mine to 4.096v to see if it helps. I'm a bit of a newbe so I don't claim to be an expert, but I'd be interested to see what the cause is.
Regards Tim. _________________ Tim |
|
|
rwyoung
Joined: 12 Nov 2003 Posts: 563 Location: Lawrence, KS USA
|
|
Posted: Wed Aug 02, 2006 6:45 am |
|
|
The quickest thing you can try for chaning the reference voltage is to use the internal Vcc connection of the PIC as your reference. This assumes you have a good quiet Vcc (which you should have anyway, no matter what you select for Vref).
If you feel that you needed Vref=1.235V, consider using an op-amp to gain your input signal(s) by a factor of at least 3 (more like 3.3) and Vref=4.096V. Besides getting back inside the specification for Vref you now have the opportunity to easily low-pass filter your input signal and you are less likely to be driving the ADC input with an impedance greater than 10KOhm. You do introduce other errors (offset, tempco drift, etc) with the op-amp however.
Some good application notes and webinars by Bonnie Baker on the microchip.com web site for selecting and applying op-amps. Go and read. _________________ Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month! |
|
|
Eleengnrng
Joined: 21 Apr 2006 Posts: 6
|
|
Posted: Wed Aug 02, 2006 7:39 am |
|
|
ok here is what tempact() is
Code: |
int8 TEMPACT()//function to retrieve temperature data from the thermocouple
{int8 TINP,temp;
set_adc_channel(0);//set A-D converter channel to 0
delay_us(100);//wait 100 us
Tinp=read_adc();//read data from A-D convertor
TEMP=tinp;//set Temp equal to data recieved
Return(TEMP);//return value in temp register from function
}//end of temperature function
|
Now here is a question on top of that i am trying to use the a-d more efficently by using the A-D interupt but now i cant any information. below is a small i dea of what i am doing. i am not going to place variable defionitions they exist i am tying to put very little code up here. as you previous reponce stated.
Code: |
#include <16F877A.h>
#device adc=8
#FUSES NOWDT, HS, PUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=20000000)
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlibm.h>
/*****************************************************************************/
/* A/D Interupt */
/*****************************************************************************/
#int_AD
AD_isr()
{
set_adc_channel(0);//set A-D converter channel to 0
delay_us(10);
acttemp = read_adc(); // says to read the A-D Converter
set_adc_channel(0);//set A-D converter channel to 0
}
void main()
{
SET_TRIS_A (0x2f); //set reg a for temp sensor input
SET_TRIS_B (0x61); //Misc Data Pins
SET_TRIS_C (0xff); //set port C to all inputs
SET_TRIS_D (0x00); //LCD Data Port
SET_TRIS_E (0x00); //LCD Control Port
port_b_pullups(TRUE);
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_64);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
ext_int_edge(L_TO_H);//activate on high to low
enable_interrupts(INT_RB);
enable_interrupts(INT_EXT);
enable_interrupts(INT_AD);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
LCD_init();//Intilize the LCD Display
set_adc_channel(0);//set A-D converter channel to 0
While (true){
output_d(acttemp);
}
|
Thanks for any assistance |
|
|
|
|
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
|