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

Sampling with ADC

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



Joined: 31 Jan 2006
Posts: 6

View user's profile Send private message

Sampling with ADC
PostPosted: Thu Mar 16, 2006 1:40 pm     Reply with quote

I am having troubles sampling multiple voltages with the ADC of a 16F877. I was initially sampling within a timer interrupt but saw on this board that I could use ADC_READ_ONLY and ADC_START_ONLY to not delay within the interrupt. I can get it working when I sample only one analog port but when I try to sample two ports my values are wrong. For example, when I apply 5V to A2 and 0V to A3 then the corresponding ADC outputs are 345 and 34 respectively. They should be 1023 and 0. If I apply the same voltage to both A2 and A3 then the ADC displays the correct values. It seems as if one analog port is affecting the other. Is there a problem with not having enough delay between switching analog ports and sampling them? I even tried putting a 20us delay at the end of my timer interrupt. This improved it a little but it was still not correct. The timer interrupt is called 125 times per second. So I sample one channel 62 times per second and the other channel 63 times per second and then take the average. Here is my code:

Code:
#include<16f877.h>

#fuses HS,NOWDT,NOPROTECT
#device ADC=10
#use delay(clock=20000000)
#use rs232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7)
#opt 9

#ORG 0x1F00,0x1FFF {} //reserve top 255 bytes of memory for the bootloader

#include <lcd.c>

//-----------------------------------------------------------------------------------------

#define INTERRUPTS_PER_SECOND 125            // 125 interrupts per second
int32 seconds = 0;                        // A running seconds counter
long interrupt_count;                     // Number of interrupts left before a second has elapsed

long CT1_Sample = 0;                     // Save average sample               
long CT2_Sample = 0;                     // Save average sample
long CT1_Sample_temp = 0;                  // Save instantaneous sample
long CT2_Sample_temp = 0;                  // Save instantaneous sample
boolean update;

void clock_isr();
void print_sample();
void reset();

//-----------------------------------------------------------------------------------------------------
// #INT_TIMER2
//-----------------------------------------------------------------------------------------------------
#INT_TIMER2
void clock_isr() {

   if (interrupt_count%2 == 0){                  // Happens 62 times per second
      CT1_Sample_temp += read_adc(ADC_READ_ONLY);      // Sample CT1
      set_adc_channel(3);                        // Change ADC channel to sample CT2
   }else{                                    // Happens 63 times per second
      CT2_Sample_temp += read_adc(ADC_READ_ONLY);      // Sample CT2
      set_adc_channel(2);                        // Change ADC channel to sample CT1
   }

   if(--interrupt_count == 0) {                  // One second reached.
      ++seconds;
       interrupt_count = INTERRUPTS_PER_SECOND;
      
      CT1_Sample = (long)(CT1_Sample_temp/62);      // Calculate average
      CT2_Sample = (long)(CT2_Sample_temp/63);

      if (seconds%2 == 0){
         update=true;                        // To call print_sample()
      }

      CT1_Sample_temp = 0;
      CT2_Sample_temp = 0;
   }

   read_adc(ADC_START_ONLY);
}


//-----------------------------------------------------------------------------------------------------
// print_sample()
//-----------------------------------------------------------------------------------------------------
void print_sample(){
   printf("CT1 Sample: %lu \n\r", CT1_Sample);
   printf("CT2 Sample: %lu \n\r", CT2_Sample);
}


//-----------------------------------------------------------------------------------------------------
// reset()
//-----------------------------------------------------------------------------------------------------
void reset(){
   update = false;
   interrupt_count = INTERRUPTS_PER_SECOND;
   CT1_Sample_temp = 0;
   CT2_Sample_temp = 0;
   CT1_Sample = 0;
   CT2_Sample = 0;

   // Setup ACD Ports
   SETUP_ADC_PORTS(ALL_ANALOG);            // A0 A1 A2 A3 A5 E0 E1 E2 Ref=Vdd
   setup_adc( ADC_CLOCK_INTERNAL );

   set_adc_channel(2);
   delay_us(20);
   read_adc(ADC_START_ONLY);
   
   // Setup Timer2 to count every second
   set_timer2(0);
   setup_timer_2(T2_DIV_BY_16, 250, 10);      // setup_timer_2(mode, period, postscale)
   
   enable_interrupts(INT_TIMER2);
   enable_interrupts(GLOBAL);

}


//-----------------------------------------------------------------------------------------------------
// main()
//-----------------------------------------------------------------------------------------------------
void main(){
   
   reset();

   printf("\n\rPrint Analog Samples\n\r");
   
   while(true){
      if (update==true){
         update=false;
         print_sample();
      }
   }
}




Here is the code I used without using ADC_READ_ONLY and ADC_START_ONLY.

Code:

#include<16f877.h>

#fuses HS,NOWDT,NOPROTECT
#device ADC=10
#use delay(clock=20000000)
#use rs232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7)
#opt 9

#ORG 0x1F00,0x1FFF {} //reserve top 255 bytes of memory for the bootloader

#include <lcd.c>

//-----------------------------------------------------------------------------------------

#define INTERRUPTS_PER_SECOND 125            // 125 interrupts per second
int32 seconds = 0;                        // A running seconds counter
long interrupt_count;                     // Number of interrupts left before a second has elapsed

int32 CT1_Sample = 0;                     // Save instantaneous sample               
int32 CT2_Sample = 0;                     // Save instantaneous sample
boolean update;

void clock_isr();
void print_sample();
void reset();

//-----------------------------------------------------------------------------------------------------
// #INT_TIMER2
//-----------------------------------------------------------------------------------------------------
#INT_TIMER2
void clock_isr() {
   if(--interrupt_count == 0) {            // One second reached.
      ++seconds;
       interrupt_count = INTERRUPTS_PER_SECOND;
      
      CT1_Sample = 0;
      CT2_Sample = 0;

      set_adc_channel(2);
      delay_us(20);
      CT1_Sample = read_adc();


      set_adc_channel(3);
      delay_us(20);
      CT2_Sample = read_adc();
 
      if (seconds%2 == 0){
         update=true;
      }
   }
}



//-----------------------------------------------------------------------------------------------------
// print_sample()
//-----------------------------------------------------------------------------------------------------
void print_sample(){
   printf("CT1 Sample: %lu \n\r", CT1_Sample);
   printf("CT2 Sample: %lu \n\r", CT2_Sample);
}




//-----------------------------------------------------------------------------------------------------
// reset()
//-----------------------------------------------------------------------------------------------------
void reset(){
   update = false;
   interrupt_count = INTERRUPTS_PER_SECOND;

   // Setup ACD Ports
   SETUP_ADC_PORTS(ALL_ANALOG);            // A0 A1 A3 Ref=Vdd
   setup_adc( ADC_CLOCK_INTERNAL );
   
   // Setup Timer2 to count every second
   set_timer2(0);
   setup_timer_2(T2_DIV_BY_16, 250, 10);      // setup_timer_2(mode, period, postscale)
   
   enable_interrupts(INT_TIMER2);
   enable_interrupts(GLOBAL);

}


//-----------------------------------------------------------------------------------------------------
// main()
//-----------------------------------------------------------------------------------------------------
void main(){
   
   reset();

   printf("\n\rs - Print Analog Samples\n\r");
   
   while(true){
      if (update==true){
         update=false;
         print_sample();
      }
   }

}


This code worked but I've read on this forum that it is not good to sample the ADC from within the interrupt and I wanted to get rid of the delays within the interrupt. The CCS manual says that you should have a 10us delay after switching analog ports but I took out the delay and it still works. Any ideas?
micknfld



Joined: 31 Jan 2006
Posts: 6

View user's profile Send private message

PostPosted: Thu Mar 16, 2006 2:17 pm     Reply with quote

It seems that it might have something to do with my math when I am trying to compute the average. I seem to get correct results when I just do this:

Code:

#INT_TIMER2
void clock_isr() {

   if(--interrupt_count == 0) {                     // One second reached.
      ++seconds;
       interrupt_count = INTERRUPTS_PER_SECOND;
      
      if (seconds%2 == 0){                        // Happens 62 times per second
         CT1_Sample = read_adc(ADC_READ_ONLY);         // Sample CT1
         set_adc_channel(7);                        // Change ADC channel to sample CT2
         update=true;
      }else{                                    // Happens 63 times per second
         CT2_Sample = read_adc(ADC_READ_ONLY);         // Sample CT2
         set_adc_channel(2);                        // Change ADC channel to sample CT1
      }
   }

   read_adc(ADC_START_ONLY);
}


But I still need to average my samples. I'll keep trying.....
micknfld



Joined: 31 Jan 2006
Posts: 6

View user's profile Send private message

PostPosted: Thu Mar 16, 2006 2:59 pm     Reply with quote

I changed it to print just the sum of the 62/63 samples per second:

Code:

void clock_isr() {
   
   if (interrupt_count%2 == 0){                  // Happens 62 times per second
      CT1_Sample_temp += read_adc(ADC_READ_ONLY);      // Sample CT1
      set_adc_channel(3);                        // Change ADC channel to sample CT2
   }else{                                    // Happens 63 times per second
      CT2_Sample_temp += read_adc(ADC_READ_ONLY);      // Sample CT2
      set_adc_channel(2);                        // Change ADC channel to sample CT1
   }

   if(--interrupt_count == 0) {                  // One second reached.
      ++seconds;
       interrupt_count = INTERRUPTS_PER_SECOND;
      
      CT1_Sample = CT1_Sample_temp;      // Calculate average
      CT2_Sample = CT2_Sample_temp;

      if (seconds%2 == 0){
         update=true;                        // To call print_sample()
      }

      set_adc_channel(3);
      CT1_Sample_temp = 0;
      CT2_Sample_temp = 0;
   }


For A2 at 5V and A3 low I get :
CT1 Sample: 23091
CT2 Sample: 220

CT1 should be around 1023*62=63426.

For A2 at 5V and A3 at 5V I get :
CT1 Sample: 63293
CT2 Sample: 64431

Not sure whats happening here.
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