CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

ADC Problem hope it is not common cant find in Forum?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Eleengnrng



Joined: 21 Apr 2006
Posts: 6

View user's profile Send private message

ADC Problem hope it is not common cant find in Forum?
PostPosted: Mon Jul 31, 2006 1:03 pm     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Jul 31, 2006 1:24 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Aug 01, 2006 6:50 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Tue Aug 01, 2006 9:40 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Aug 02, 2006 1:47 am     Reply with quote

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. Laughing
_________________
Tim
rwyoung



Joined: 12 Nov 2003
Posts: 563
Location: Lawrence, KS USA

View user's profile Send private message Send e-mail

PostPosted: Wed Aug 02, 2006 6:45 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Aug 02, 2006 7:39 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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