View previous topic :: View next topic |
Author |
Message |
homfray
Joined: 19 Nov 2003 Posts: 45 Location: Oxford
|
EXternal Interrupt |
Posted: Wed Mar 10, 2004 8:07 am |
|
|
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 |
Posted: Wed Mar 10, 2004 11:02 am |
|
|
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
|
|
Posted: Wed Mar 10, 2004 1:38 pm |
|
|
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
|
|
Posted: Wed Mar 10, 2004 1:41 pm |
|
|
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
|
|
Posted: Wed Mar 10, 2004 2:25 pm |
|
|
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
|
|
Posted: Thu Mar 11, 2004 3:32 am |
|
|
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
|
|
Posted: Thu Mar 11, 2004 6:22 am |
|
|
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
|
|
Posted: Thu Mar 11, 2004 8:52 am |
|
|
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. |
|
|
|