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

EXternal Interrupt

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



Joined: 19 Nov 2003
Posts: 45
Location: Oxford

View user's profile Send private message Visit poster's website

EXternal Interrupt
PostPosted: Wed Mar 10, 2004 8:07 am     Reply with quote

I have written this code

Code:

#define Fosc 40000000  // I'm using a 40 MHz crystal
#include <18F452.h>
#device *=16 ADC=8

//---------------------------------------------------------------------------
// COMPILER DIRECTIVES and HARDWARE CONFIGURATION

#fuses HS, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(clock = Fosc)

char ext2Flag;
long counter;

#int_rtcc
void int_rtcc_isr(void)
{
   static short rtccState = 0;
   set_timer0(60600);   // 2000 Hz reload value (pre-scaler = 1)
   output_bit(PIN_E1, rtccState);
   rtccState = ~rtccState;
   counter++;
}

#int_ext2
void int_ext2_isr(void)
{
   ext2Flag=0;
   enable_interrupts(INT_RTCC);
   enable_interrupts(GLOBAL);    
   disable_interrupts(INT_EXT2);
}

//===========================================
void main()
{
   static short state = 0;
   counter = 0;

   setup_counters(RTCC_INTERNAL, RTCC_DIV_1);
   set_timer0(60600);
   ext2Flag=0;
   
   enable_interrupts(INT_RTCC);
   enable_interrupts(GLOBAL);
   disable_interrupts(INT_EXT2);

   while(1){
      if (counter==10000)
      {
         enable_interrupts(INT_EXT2);
         enable_interrupts(GLOBAL);
         disable_interrupts(INT_RTCC);
         ext2Flag=1;
         counter=0;
      }
      if (ext2Flag==1)
      {
         output_bit(PIN_E1, state);
         state = ~state;
         delay_ms(250);
      }
         
   } 
}


which uses the rtcc interrupt and after about 4-5 seconds it disabled the rtcc interupt and enables the ext2 interrupt and then waits until some presses B1 and then enables rtcc, disables ext2 etc.

The code works fine but I find when I change it from waiting for a counter to waiting for a button press I find that the button has no effect on changing between interupt it is only the ext2 (PIN_B1). So when I hold B1 down it stays in one state until I let go of the button. Any ideas it almost seems as if I am not disabling the interrupt

Code:
while(1){
      if (input(PIN_B2))
      {
         enable_interrupts(INT_EXT2);
         enable_interrupts(GLOBAL);
         disable_interrupts(INT_RTCC);
         ext2Flag=1;
         counter=0;
      }
}


WHAT IS THE AFFECT TO THE REST OF THE B PORT IF ONE OF THE PINS IS BEING USED AS INTERRUPT
Ttelmah
Guest







Re: EXternal Interrupt
PostPosted: Wed Mar 10, 2004 11:02 am     Reply with quote

homfray wrote:
I have written this code

Code:

#define Fosc 40000000  // I'm using a 40 MHz crystal
#include <18F452.h>
#device *=16 ADC=8

//---------------------------------------------------------------------------
// COMPILER DIRECTIVES and HARDWARE CONFIGURATION

#fuses HS, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(clock = Fosc)

char ext2Flag;
long counter;

#int_rtcc
void int_rtcc_isr(void)
{
   static short rtccState = 0;
   set_timer0(60600);   // 2000 Hz reload value (pre-scaler = 1)
   output_bit(PIN_E1, rtccState);
   rtccState = ~rtccState;
   counter++;
}

#int_ext2
void int_ext2_isr(void)
{
   ext2Flag=0;
   enable_interrupts(INT_RTCC);
   enable_interrupts(GLOBAL);    
   disable_interrupts(INT_EXT2);
}

//===========================================
void main()
{
   static short state = 0;
   counter = 0;

   setup_counters(RTCC_INTERNAL, RTCC_DIV_1);
   set_timer0(60600);
   ext2Flag=0;
   
   enable_interrupts(INT_RTCC);
   enable_interrupts(GLOBAL);
   disable_interrupts(INT_EXT2);

   while(1){
      if (counter==10000)
      {
         enable_interrupts(INT_EXT2);
         enable_interrupts(GLOBAL);
         disable_interrupts(INT_RTCC);
         ext2Flag=1;
         counter=0;
      }
      if (ext2Flag==1)
      {
         output_bit(PIN_E1, state);
         state = ~state;
         delay_ms(250);
      }
         
   } 
}


which uses the rtcc interrupt and after about 4-5 seconds it disabled the rtcc interupt and enables the ext2 interrupt and then waits until some presses B1 and then enables rtcc, disables ext2 etc.

The code works fine but I find when I change it from waiting for a counter to waiting for a button press I find that the button has no effect on changing between interupt it is only the ext2 (PIN_B1). So when I hold B1 down it stays in one state until I let go of the button. Any ideas it almost seems as if I am not disabling the interrupt

Code:
while(1){
      if (input(PIN_B2))
      {
         enable_interrupts(INT_EXT2);
         enable_interrupts(GLOBAL);
         disable_interrupts(INT_RTCC);
         ext2Flag=1;
         counter=0;
      }
}


WHAT IS THE AFFECT TO THE REST OF THE B PORT IF ONE OF THE PINS IS BEING USED AS INTERRUPT


No it does not affect the rest of PortB, if one pin is used as an interrupt. I haven't bothered to look through your code, but a couple of comments apply 'at a glance':
1) Never _ever_ enable_interrupts(GLOBAL), inside an interrupt handler. This is a sure fire way to crash the CPU. At this point, the interrupt flag is still set (it is cleared when you exit the interupt handler), and you could potentially end up interrupting to the RTCC interrupt, or back into the external interrupt itself, leading to a massive stack overflow and crash by doing this. The global interrupt has allready been enabled in main, to get to the interrupt handler itself, and will _automatically_ be reset when you exit the handler. This is probably the cause of your problems...
2) As a general comment, try to avoid setting timers to values inside an interrupt. The timer may well have allready had several counts at this point (depending on the latency to get to the handler), so the results will not quite be what you expect. Either add a value to the timer (which can still have one count of error, but is 'better'), adjust the prescaller values, so that the timer is running much slower (if the timer takes at least 50 instruction times to advance, the problem generally disappears), or change your crystal frequency so that no adjustment is necessary (the best solution)...

Best Wishes
Guest








PostPosted: Wed Mar 10, 2004 1:38 pm     Reply with quote

Thanks for the tips. One question how do I reset the timer if I can't do it in the interrupt surely when I return from the interrupt to the code it will mean that I am not acurately restarting the interupt timer (as I could be anywhere in the code).

Is there a way of returning from an interrupt to a certain part of the code??
homfray



Joined: 19 Nov 2003
Posts: 45
Location: Oxford

View user's profile Send private message Visit poster's website

PostPosted: Wed Mar 10, 2004 1:41 pm     Reply with quote

I need to run my osc this fast as I need to run a loop within 0.5ms
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

PostPosted: Wed Mar 10, 2004 2:25 pm     Reply with quote

This is my method.

Code:

int1  Clock_Been_Initialized=0;

Int16 Miliseconds;
#locate Miliseconds = Registry_Map+6
Int16 Seconds;
#locate Seconds = Registry_Map+8
int1  Second_Tick=0;

// Global Real Time Clock Information
#int_TIMER2                                                 // Clock interrupt adjusted to occurs ~ 1ms
void TIMER2_isr()
{  Miliseconds++;
   if(Miliseconds>999)
   {  Miliseconds=0;
      Seconds++;
      Second_Tick=1;
   }
}
/***********************************************************
*    Service Hardware Modules                              *
***********************************************************/
#inline
void Clock_Service(void)
{  if(!Clock_Been_Initialized)
   {  setup_timer_2(T2_DIV_BY_4,249,1);                     // Set 1mS period
      enable_interrupts(INT_TIMER2);
      Seconds=0;
      Clock_Been_Initialized=1;
   }
   if(Second_Tick)
   {  Second_Tick=0;
      Registry_Map[6]=Registry_Map[5];
      Registry_Map[5]=0;
      Registry_Map[2]=Registry_Map[1];
      Registry_Map[1]=0;
   }
   Registry_Map[5]++;
}


This is for a 4Mhz xtal so for you it would cause an interupt every 100uS and the second count would be fast by a factor of 10.
homfray



Joined: 19 Nov 2003
Posts: 45
Location: Oxford

View user's profile Send private message Visit poster's website

PostPosted: Thu Mar 11, 2004 3:32 am     Reply with quote

Code:
 #inline
void Clock_Service(void)
{  if(!Clock_Been_Initialized)
   {  setup_timer_2(T2_DIV_BY_4,249,1);                     // Set 1mS period
      enable_interrupts(INT_TIMER2);
      Seconds=0;
      Clock_Been_Initialized=1;
   }
   if(Second_Tick)
   {  Second_Tick=0;
      Registry_Map[6]=Registry_Map[5];
      Registry_Map[5]=0;
      Registry_Map[2]=Registry_Map[1];
      Registry_Map[1]=0;
   }
   Registry_Map[5]++;
}

OK #inline just read up about it (i am such a newbie). but the code underneath it is not MAIN(). what makes the code under #inline go back to MAIN(). Sorry about being really stupid but this is fairly confusing. Is this the full code apart from the define's head section? What is Registry_Map?

Do I need

INTERUPT CODE
{

}

#INLINE
{
RESET TIMERS
}

VOID MAIN
{

}
homfray



Joined: 19 Nov 2003
Posts: 45
Location: Oxford

View user's profile Send private message Visit poster's website

PostPosted: Thu Mar 11, 2004 6:22 am     Reply with quote

Tried to implement #inline. Doesn't work, re-read the #inline in the compiler book doesn't make any sens. WHAT??? Any nice easy of what it does where I can put it
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

PostPosted: Thu Mar 11, 2004 8:52 am     Reply with quote

I was calling Clock_Service(); from within main.
Basicly a while loop that calls it repeatedly.
The regester variables are externally readable variables for my MODBUS driver. For example I could read register map 6 to see how many loops were excecuted in the last 1 second period. It is there for the purpose of debugging. It allows a measurment of how fast things are running.

If you understand what I posted you should be able to create a good solution for your own problem.
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