![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
deepakomanna
Joined: 06 Mar 2007 Posts: 92 Location: Pune,India
|
16F684 ADC & Timer2 Query |
Posted: Wed Aug 20, 2008 7:47 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
RLScott
Joined: 10 Jul 2007 Posts: 465
|
Re: 16F684 ADC & TImer2 Query |
Posted: Wed Aug 20, 2008 9:02 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Wed Aug 20, 2008 9:48 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
deepakomanna
Joined: 06 Mar 2007 Posts: 92 Location: Pune,India
|
ADC & Timer2 query |
Posted: Thu Aug 21, 2008 9:18 pm |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|