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

16F684 ADC & Timer2 Query

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



Joined: 06 Mar 2007
Posts: 92
Location: Pune,India

View user's profile Send private message AIM Address Yahoo Messenger

16F684 ADC & Timer2 Query
PostPosted: Wed Aug 20, 2008 7:47 am     Reply with quote

Dear Sir,
I am using 16F684 device & CCS compiler ver. 4.73.
In my application i am reading ADC, channel 5 in Timer2 ISR. Timer2 will overflow every 300 usec.
if i disable ADC or Timer 2 my application is running fine & if i enable i am not getting correct result.
below is part of my application.
Code:
#include <16F684.h>
#fuses INTRC_IO,NOWDT,PUT,NOMCLR,PROTECT,NOCPD,BROWNOUT,NOIESO,NOFCMEN
//Internal RC Osc, no CLKOUT,No Watch Dog Timer,Power Up Time ON,Internal MCLR,Code Protect ON,No EE protection,Brownout detect OFF,
#device ADC=10               // set 10 bit ADC.0
#use delay(clock=8000000)      // 8 MHz internal clock.

/************** function prototypes *********************************************/
void init_CPU();

int1 Solenoid_Flag;   // To make turn On & OFF solenoid
int8 Solenoid_Time;   // HOlds the 3 sec Time to make solenoid OFF
signed int16 Starter_TIme;//holds the time for time < 5sec or >6sec
int1 Starter_flag;         // Flag to set & reset 6sec OFF time 5sec time
int1 Timer2OFF;

/************************************************************************************************
***********************************************************************************************/
#INT_TIMER2
void TIMER2_isr()
{
//Timer 2 will over flow every 300 usec.
int16 Starter_Vol;  // holds the adc count
CLEAR_INTERRUPT(INT_TIMER2);
SET_ADC_CHANNEL(5);             // channel 5 to check starter vol
DELAY_US(20);
Starter_Vol = READ_ADC();   // SOC & EOC
DELAY_US(20);
if((Starter_Vol>= 717)||(Starter_TIme < 0)) // If key is pressed & voltage at pin is greater than 10.5 == 3.5v.
   {
         Starter_TIme++;      
   }
if((Starter_Vol>=717)&&((Starter_TIme>= 0)&&(Starter_TIme < 16667)))   
      {
         OUTPUT_HIGH(PIN_C5);//
         Starter_flag = 0;   
      }
else
   {
      OUTPUT_LOW(PIN_C5);//
      if(Starter_flag == 0)
         {
            Starter_TIme = -20000;   
            Starter_flag = 1;      
         }
   }

   
/************************************************************************************************
************************************************************************************************/
#INT_TIMER0
void Timer0_isr()
{
//Timer0 1 tick == 20 msec.
   Solenoid_Time++;
   if((Solenoid_Time >= 150)&&(Solenoid_Flag == 1)) // check for 3 sec compliton
      {
         OUTPUT_LOW(PIN_C2);
         Solenoid_Time = 0;
         Solenoid_Flag = 0;
         DISABLE_INTERRUPTS(INT_TIMER0);      //Disable timer0 interrupt               
      }
SET_TIMER0(100);         // SET timer0 to overflow after 20 msec.
CLEAR_INTERRUPT(INT_TIMER0);
}

#INT_TIMER1
void TIMER1_isr()
{
   // Timer1 1 count == 4 usec.,So 65535 * 4 usec = 262.14 msec
/*******************************/
// application code....

/*******************************/
if(Timer2OFF == 0)//start timer2 operation
   {
      SETUP_TIMER_2(T2_DIV_BY_4,0X96,1);
      Timer2OFF = 1;
   }
CLEAR_INTERRUPT(INT_TIMER1);
}

void init_CPU()
{
/****************  PORT SETTINGS  ***********************/                         
OUTPUT_A(0x00);         //0010 0000 port A output.
OUTPUT_C(0x00);         //port C output as Zero.     
PORT_A_PULLUPS(FALSE);   //disable internal pullups,bcz external pull ups are connected.   
SET_TRIS_A(0X09);           //0000 1001 = 09h   I/P = RA0,RA3(/MCLR),O/P = RA1,RA2,RA4,RA5.
SET_TRIS_C(0X1A);           //0001 1010 = 10h   I/P = RC1,RC3,RC4  O/P = RC0,RC2,RC5.
/****************  COMPARATOR SETTINGS  ***************/
SETUP_COMPARATOR(NC_NC_NC_NC);         // comparator off
/****************  ADC SETTINGS  *********************/
SETUP_ADC_PORTS(sAN0|sAN5|VSS_VDD );   // PIN RA1 & RC1 IS ANALOG & ALL OTHER DIGITAL
SETUP_ADC(ADC_CLOCK_DIV_8);                     //
/****************  INTERRUPT SETTINGS  *****************/
ENABLE_INTERRUPTS(GLOBAL);         // enable global interrupt.
CLEAR_INTERRUPT(INT_TIMER0);
SET_TIMER0(100);                     // SET timer0 to overflow after 20 msec.
CLEAR_INTERRUPT(INT_TIMER1);
ENABLE_INTERRUPTS(INT_TIMER1);      //enable timer1 interrupt
DISABLE_INTERRUPTS(INT_TIMER0);      //Disable timer0 interrupt               
ENABLE_INTERRUPTS(INT_TIMER2);      //enable timer2 interrupt
SETUP_TIMER_2(T2_DIV_BY_4,0X96,1);//TIMER2 will overfolow after 300 usec.
/***************  END OF CPU INIT  ******************/
}

 
void main()
{
   Starter_TIme =0;
   Starter_flag = 1;         
   
   init_CPU();
   
   Solenoid_Flag = 1;
   Solenoid_Time = 0;
   while((INPUT(PIN_A3)==1)&&(INPUT(PIN_C4)==1))// wait till up i/p comes
      {
         if((INPUT(PIN_C3))&&(Solenoid_Flag == 1))// Check for gas solenoid i/p is ON
            {
               OUTPUT_HIGH(PIN_C2);   // GAS Solenoid ON
               SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_256);   // Start Timer0 count       
               ENABLE_INTERRUPTS(INT_TIMER0);      //enable timer0 interrupt
            }   
         else   
            {
               OUTPUT_LOW(PIN_C2);
               DISABLE_INTERRUPTS(INT_TIMER0);      //Disable timer0 interrupt               
            }         
      }

   Solenoid_Time = 0;   // Reset Solenoid Time counter
   Solenoid_Flag = 0;   // clear this flag to turn ON Gas Solenoid after engine start.   
   DISABLE_INTERRUPTS(INT_TIMER0);      //Disable timer0 interrupt               
   
   while(TRUE)
   {   
      SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_8);      //TIMER 1 ON,Prescalar is 1:4 So 1 count Tick == 4 usec.      
/**********************************/
//   Application code...
/************************************/
   }
}   

please suggest any suggestion to overcome this problem
_________________
Thank You,
With Best Regards,
Deepak.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: 16F684 ADC & TImer2 Query
PostPosted: Wed Aug 20, 2008 9:02 am     Reply with quote

Please explain more fully what you mean by not getting correct result. Exactly what do you expect to happen and what is actually happening?
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
Ttelmah
Guest







PostPosted: Wed Aug 20, 2008 9:48 am     Reply with quote

First, learn to layout your code to help you read it (and us)...
You will be less likely to make mistakes then...

You do not need to clear interrupts at the end of the interrupt handlers. Unless you add the option 'NOCLEAR' to the interrupt declaration, the compiler does this for you.

Check the data sheet for the allowable ADC clock settings. Note that ADC_CLOCK_DIV_8 becomes illegal above 5MHz.

You don't need a delay after reading the ADC.

You only need a delay before reading the ADC, when you have changed the channel selected. Set the channel _once_ in the main, and then you can get rid of the channel selection, and both delays in the interrupt.

The timer2 interrupt is going to take a _long_ time. Currently, 12uSec for the ADC conversion (but this is illegal), 40uSec for the two delays, several uSec transferring data around, then several uSec for the tests etc., and a lot more when arithmetic is involved. Add the overhead for saving the registers, restoring them, and selecting the right interrupt (probably another 40uSec), and timing is becoming very 'tight'. Instead change your ADC clock selection to /16, and code the ADC read like:

Code:

#INT_TIMER2
void TIMER2_isr(void) {
   //Timer 2 will over flow every 300 usec.
   int16 Starter_Vol;  // holds the adc count
   Starter_Vol = READ_ADC(ADC_READ_ONLY);

   //rest of your interrupt code here

   READ_ADC(ADC_START_ONLY);
}


This way the ADC reading occurs in the background, 'between' the interrupts, and only the result is read at the start of the routine, which is _quick_.

Best Wishes
deepakomanna



Joined: 06 Mar 2007
Posts: 92
Location: Pune,India

View user's profile Send private message AIM Address Yahoo Messenger

ADC & Timer2 query
PostPosted: Thu Aug 21, 2008 9:18 pm     Reply with quote

Many thanks for reply,
Suppose if the key pressed voltage to pin no. 9 is between 3.5 v to 5v (vol. to this pin is from external power supply).Then the result i am getting correct.
& if key is not pressed i.e. pin voltage below 1 v then sometime result is correct sometimes getting unknown result.
But in my application i am using two channels i.e ch0 & ch5.
After your suggestion i defined ch0 in main() function like this,
Code:
main()
{
while{
   //Application code..................

         
   SET_ADC_CHANNEL(0);   // CHANNEL_0 FOR CutOFF I/P.
   DELAY_US(10);
   CutOFF = READ_ADC();   // read CutOFF i.e. ADc SOC & EOC

   //Application code.........
}

}

but in timer2 isr i also want to use ch5 ADC.by defining below code like this

#INT_TIMER2
void TIMER2_isr()
{
//Timer 2 will over flow every 300 usec.
int16 Starter_Vol;  // holds the adc count

SET_ADC_CHANNEL(5);             // channel 5 to check starter vol
DELAY_US(10);
Starter_Vol = READ_ADC(ADC_READ_ONLY); //Reads last conversion result
READ_ADC(ADC_START_ONLY);       // starts conversion & Returns.

}

_________________
Thank You,
With Best Regards,
Deepak.
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