Editing A Tutorial on PIC interrupts using BoostC including Example Programs

Jump to navigation Jump to search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.

Latest revision Your text
Line 3: Line 3:
 
'''This is still a draft, but mostly right'''
 
'''This is still a draft, but mostly right'''
  
A nice feature of many ( probably all that you want to use ) PICs is the interrupt feature.  This makes some programming tasks much easier, and may make the impossible possible.  This article will give some tips on the why and how of using interrupts.  Please let me know if you find areas needing improvement, or just make them yourself.  The code here is extracted from real working projects.  Normally it has been somewhat simplified, and some of the declarations and setup are not shown.  In all cases there are links to the actual project where all the code is, and, as far as we know works.
+
A nice feature of many ( probably all that you want to use ) PICs is the interrupt feature.  This makes some programming tasks much easier, and make make the impossible possible.  This article will give some tips on the why and how of using interrupts.  Please let me know if you find areas for improvement, or just make them.  The code here is extracted from real working projects.  Normally it has been somewhat simplified, and some of the declarations and setup are not shown.  In all cases there are links to the actual project where all the code is, and, as far as we know works.
  
  
Line 25: Line 25:
 
Features of the external interrupt that we will use.   
 
Features of the external interrupt that we will use.   
  
The interrupt is triggered by an input on RB0, either ( depending on how we set it up ) as the signal goes from 0 to 1, called the rising edge, or as the signal goes from 1 to 0, called the falling edge.  This sets the interrupt flag, and if the interrupt is enabled ( and we are not already in an interrupt ) the microcontroller goes to the interrupt subroutine.   
+
The interrupt is trigger by input on RB0, either ( depending on how we set it up ) as the signal goes from 0 to 1, called the rising edge, or as the signal goes from 1 to 0, called the falling edge.  This sets the interrupt flag, and if the interrupt is enables ( and we are not already in an interrupt ) the microcontroller goes to the interrupt subroutine.   
  
  
Line 35: Line 35:
  
 
===== Setup: =====  
 
===== Setup: =====  
 
Setup occurs in the main-line code, before the main loop.
 
  
 
The RBO interrupt -- Clear the flag, set for rising edge, and enable the interrupt.  
 
The RBO interrupt -- Clear the flag, set for rising edge, and enable the interrupt.  
  
    int main(void){
+
clear_bit( intcon, INTF );  
        ....
+
set_bit( option_reg, INTEDG );  // set for rising edge
 
+
set_bit( intcon, INTE ); // set to enable the interrupt
clear_bit( intcon, INTF );  
 
set_bit( option_reg, INTEDG );  // set for rising edge
 
set_bit( intcon, INTE ); // set to enable the interrupt
 
 
 
        ....
 
 
 
        // main loop
 
        while(1){ // forever
 
            ....
 
        };
 
    }
 
  
 
Here we assume the interrupt is originally off ( or the global interrupt is off ).  If you are not sure then turn them off at the beginning.
 
Here we assume the interrupt is originally off ( or the global interrupt is off ).  If you are not sure then turn them off at the beginning.
Line 60: Line 47:
  
 
In interrupts we almost always make sure that the interrupt is the one we think it is, clear the flag, and do the processing.  A key to the post processing is setting the counts and the  MinAct flag.
 
In interrupts we almost always make sure that the interrupt is the one we think it is, clear the flag, and do the processing.  A key to the post processing is setting the counts and the  MinAct flag.
 
The interrupt routine handles stuff we absolutely must deal with immediately during the interrupt (the "foreground task").
 
  
 
       if ( intf ) {  // are we in the external interrupt.
 
       if ( intf ) {  // are we in the external interrupt.
Line 95: Line 80:
  
  
When you get around to it ( but at least every minute ) check the MinAct flag, then do what you have to.  We assume that this process takes a bit of time, and you always try to take as little time in the interrupt as possible ( this usually makes the interrupts work better and lets you use more than one interrupt at a time).  In fact if you do not get around to executing your code within a minute it may not matter much, the time will still be kept correctly and the flag MinAct will still be set, you will miss executing "what you have to do" once but that may not matter.
+
When you get around to it ( but at least every minute ) check the MinAct flag, then do what you have to.
  
Post-interrupt processing occurs in the main loop (the "background task").
+
if ( MinAct == 1 ) {
 
+
........ what you have to do .....
    int main(void){
+
}
        ...
 
 
 
        // main loop
 
        while(1){ // forever
 
            ....
 
 
 
            if ( MinAct == 1 ) {
 
                MinAct = 0;  // clear the flag
 
                ........ what you have to do .....
 
            };
 
  
            ....
 
 
        };
 
    }
 
  
 
In the full code you also have to have code to move the hands of the clock, set it, etc.  It is in there: [[PIC based Stepper Motor Dancing Analog Clock]]
 
In the full code you also have to have code to move the hands of the clock, set it, etc.  It is in there: [[PIC based Stepper Motor Dancing Analog Clock]]
Line 125: Line 96:
 
=== The problem: ===
 
=== The problem: ===
  
An IR transmitter sends bursts of infra red to a receiver.  This receiver converts the IR to pulses which ( in the case we will consider the NEC protocol ) consists of about 70 transition over a period of time of about .1 seconds.  We want to measure these transitions and determine what button was pressed on the IR transmitter.  Note that the code here is a bit simplified, the better to show the essential ideas.  To make it work go to the project and get the full code.  Email me if you are having problems.
+
An IR transmitter sends bursts of infra red to a receiver.  This receiver converts the IR to pulses which ( in the case we will consider the NEC protocol ) consists of about 70 transition over a period of time of about .1 seconds.  We want to measure these transitions and determine what button was pressed on the IR transmitter.
  
 
=== Solution: ===
 
=== Solution: ===
Line 135: Line 106:
 
===== Issues for IR receive =====  
 
===== Issues for IR receive =====  
  
* Issue: How do we avoid tying up the CPU during the receive?
+
Issue: How do we avoid tying up the CPU during the receive?
  
Response 1: It only takes about 0.1 sec, so what is the problem?  
+
Response 1: It only takes about .1 sec, so what is the problem?  
A tenth of a second can be a long time on a PIC and actually if you are waiting to receive something this can take the CPU forever (until the transmitter decides to send something).
+
A tenth of a second can be a long time on a PIC and actually if you are waiting to receive something this can take the CPU forever ( until the transmitter decides to send something )
  
Response 2: Use interrupts that occur when the state of the IR signal changes, process quickly and go back to other less time-critical tasks.
+
Response 2: Use interrupts that occur when the state of the IR signal changes, process quickly and go back to other less time critical tasks.
  
* Issue: How do we know when to start receiving?
+
Issue: How do we know when to start receiving?
Response 1: If the IR signal has been quiet for a period of time over about 0.1 sec then the next transition must be the beginning of the signal.
+
Response 1: If the IR signal has been quite for a period of time over about .1 sec then the next transition must be the beginning of the signal.
 +
Response 2: If the signal has error checking built in: start receiving wherever check if the data is good.  If it is then you must have started at the beginning.  In any case you are now at the end and start receiving the next burst at the beginning. 
  
Response 2: If the signal has error checking built in: start receiving wherever and check if the data is goodIf it is then you must have started at the beginningIn any case you are now at the end and start receiving the next burst at the beginning.
+
Issue:  How do we no when a received message is finished.
 +
Response 1: Count the number of transitions in the received signal, done when get up to the required countBut if we miss a transition we could be stuck.
 +
Response 2: Wait until a quiet period signals the end of the signal.
 +
Response 3: Some protocols have a special “pulse” or something that we can detect at the end.
 +
Response 1:
  
* Issue: How do we know when a received message is finished?
 
Response 1:  Count the number of transitions in the received signal; done when we get up to the required count.  But if we miss a transition we could be stuck.
 
  
Response 2: Wait until a quiet period indicates the end of the signal.
+
Issue:  How do we know the data is good
 +
Response 1:  It usually is, hope for the best.
 +
Response 2: Many protocols have a fixed number of transition, count and compare.
 +
Response 3:  Some protocols have error checking built in.  For the nec protocol the data in the third byte is repeated, inverted in the fourth byte.  If you exclusive or ( xor ) the bytes together you should get FF or 11111111.
  
Response 3: Some protocols have a special “pulse” or something that we can detect at the end.
 
 
* Issue:  How do we know the data is good?
 
Response 1: It usually is, hope for the best.
 
 
Response 2: Many protocols have a fixed number of transition, so count and compare.
 
 
Response 3: Some protocols have error checking built in.  For the NEC protocol the data in the third byte is repeated, and inverted in the fourth byte.  If you exclusive-or (XOR) the bytes together, you should get FF or 11111111.
 
  
 
===== The program design =====  
 
===== The program design =====  
  
We could have the program go in a tight loop counting the number of times it loops and checking the input port for the transition in the IR signal.  Each time it changes we record the count and restart at 0.  This is how the program '''IR.c''' works.  It is called a blocking routine because it blocks the microcontroller from doing any other operation (except for interrupts) during the receive.  So we will make our routine interrupt driven to end this blocking.
+
We could have the program go in a tight loop counting the number of times it loops and checking the input port for the transition in the IR signal.  Each time it changes we record the count and restart at 0.  This is how the program IR.c works.  It is called a blocking routine because it blocks the microcontroller from doing any other operation ( except for interrupts ) during the receive.  So we will make our routine interrupt driven to end this blocking.
  
In some interrupt driven programming you can do almost all the work required in the interrupt (blinking an LED for example).  But many like this one requires that the work be distributed between the interrupt and non-interrupt processing.  And since we jump in and out of the interrupt (in the interrupt for as short a time as we can), we cannot keep track of what we are doing by where we are in the program.  Instead we will introduce global state variables - 'global' because any routine anywhere can access the variables, and 'state' because they tell the state of the processing.  One of the most important of these is called '''IRState'''.  The states that are defined for this are:
+
In some interrupt driven programming you can do almost all the work required in the interrupt ( blinking a led for example ).  But many like this one requires that the work be distributed between the interrupt and non-interrupt processing.  And since we jump in and out of the interrupt ( in the interrupt for as short a time as we can ) we can not keep track of what we are doing by where we are in the program, instead we will introduce global state variables.  Global because any routine anywhere can access the variables, and state because they tell the state of the processing.  One of the most important of these is called IRState.  The states that are define for this are:
  
*''Waiting'' for the beginning of the receive, perhaps because a signal began before we tried to receive.  In the program this value is the '''#define IRSTATE_WAIT'''.
+
Waiting for the beginning of the receive, perhaps because a signal began before we tried to receive.  In the program this value is the #define IRSTATE_WAIT
  
*''Busy'' meaning that we were waiting for a quiet period, but found that the signal was present.  We could continue to wait, but that might put us in a tight loop of waiting, thus keeping the microcontroller busy. We enter this state so that the program knows that we could not begin the receive, and to try again when we get around to it. In the program this value is the '''#define IRSTATE_BUSY'''.
+
Busy meaning that we were waiting for a quiet period, but found that the signal was present, thus busy.  We could continue to wait, but that might put us in a tight loop of waiting, thus keeping the microcontroller busy. We enter this state so the program know that we could not begin the receive, and to try again when we get around to it.   In the program this value is the #define   IRSTATE_BUSY
  
*''Ready'', meaning that we waited for no signal, found it, and are now ready to receive.  In the program this value is the '''#define IRSTATE_BUSY'''.
+
Ready meaning that we waited for no signal, found it, and are now ready to receive.  In the program this value is the #define   IRSTATE_BUSY
  
*''Reading'', meaning that we are in the process of receiving.  The data should be complete in about a tenth of a second.  In the program this value is the '''#define IRSTATE_READ'''.
+
Reading meaning that we are in the process of receiving, the data should be complete in about a tenth of a second.  In the program this value is the #define IRSTATE_READ.
  
*''Got'', meaning that we have completed the reading of the signal.  In the program this value is the '''#define IRSTATE_GOT'''.
+
Got meaning that we have completed the reading of the signal.  In the program this value is the #define IRSTATE_GOT
  
*''Not applicable'' is a special state that means that we are not trying to receive anything.
+
Not applicable is a special state that means that we are not trying to receive anything.
  
So in a normal receive we go through the states in the order Wait -> Ready -> Reading -> Got and then around again.
+
So in a normal receive we go through the states in the order wait -> ready ->read->got and then around again.
  
OK, so how do we do the programming?  I am going to take a bit of an odd approach to the explanation here by focusing on the main part of the receive loop.  This is where most of the action occurs, so I think that is a good place to start. Later, I will have to explain how we get into and out of this loop.  The plan here is to set up an interrupt on the port for the IR receive (this is port RB0), while at the same time a timer is running.  When the interrupt occurs, we will measure the time by reading the timer.   
+
OK so how do we do the programming?  I am going to take a bit of an odd approach to the explanation here by focusing on the main part of the receive loop, this is where most of the action occurs, so I think that is a good place to start. Later I will have to explain how we get into and out of this loop.  The plan here is to set up an interrupt on the port for the IR receive ( this is port RB0 ) while at the same time a timer is running.  When the interrupt occurs we will measure the time by reading the timer.   
  
Features of the external interrupt that we will use:
+
Features of the external interrupt that we will use
  
The interrupt is triggered by an input on RB0, either (depending on how we set it up) as the signal goes from 0 to 1, called the rising edge, or as the signal goes from 1 to 0, called the falling edge.  This sets the interrupt flag, and if the interrupt is enabled (and we are not already in an interrupt) the microcontroller goes to the interrupt subroutine.  Since we want to time all transitions, we will sometimes set the interrupt for the falling edge, sometimes for the rising edge.
+
The interrupt is trigger by input on RB0, either ( depending on how we set it up ) as the signal goes from 0 to 1, called the rising edge, or as the signal goes from 1 to 0, called the falling edge.  This sets the interrupt flag, and if the interrupt is enables ( and we are not already in an interrupt ) the microcontroller goes to the interrupt subroutine.  Since we want to time all transitions we will sometimes set the interrupt for the falling edge, sometimes for the rising edge.
  
Features of the counter/timer we will use:
+
Features of the counter/timer we will use.
  
The timer can be connected to a crystal clock to count up.  It is a two-byte counter.  We will use only the high byte because we are timing fairly long values.  The timer can be turned off or on.  We can also divide (or pre-scale) the clock, before counting it.  This is useful because it allows us to count longer times, but with less precision.
+
The timer can be connected to crystal clock to count up.  It is a two byte counter.  We will use only the high byte because we are timing fairly long values.  The timer can be turned off or on.  We can also divide, or pre-scale the clock, before counting it.  This is useful because it allows us to count longer times, but with less precision.
  
A feature of the C compiler is that all register values of the controller, which it needs to return to the place where the interrupt occurs, are automatically saved at the beginning of the interrupt (called the “context save”) and restored at the end.  In assembler, you need to write the code yourself to do this.
+
A feature of the C compiler is that all values of the controller that it needs to return to the place where the interrupt occurs are automatically saved at the beginning of the interrupt ( called the “context save” ) and restored at the end.  In assembler you need to write the code yourself to do this.
  
 
===== Main Loop =====  
 
===== Main Loop =====  
Line 202: Line 171:
 
====== Interrupt: ======  
 
====== Interrupt: ======  
  
The first thing to remember is that there are several reasons that the program can end up in the interrupt routine.  That is because there are different reasons that interrupts can occur.  So the first thing to check is that you are in for the reason you think.  In the case of the '''RB0''' external interrupt, that is usually done by checking the interrupt flag.  I have discovered however that the flag may be set even if the interrupt is not enabled and another interrupt has been triggered.  Thus you should consider checking that not only is the flag set but also that the interrupt is enabled.  If this is true, we next stop the timer ('''TIMER0''') and read it.  Then we reset it for the next count.  To get ready for the next interrupt, we need to reset the interrupt flag (set by the processor when the interrupt is triggered), set the edge we are triggering on to rising if it was falling and vise versa.
+
The first thing to remember is that there are several reasons that the program can end up in the interrupt routine, that is because there are different reasons that cause an interrupt.  So the first thing to check is that you are in for the reason you think.  In the case of the RB0 external interrupt that is usually done by checking the interrupt flag.  I have discover however that the flag may be set even if the interrupt is not enabled and another interrupt has be triggered.  Thus you should consider checking that not only is the flag set but also that the interrupt is enabled.  If this is true we next stop the timer ( TIMER0 ) and read it.  Then we reset it for the next count.  To get ready for the next interrupt we need to reset the interrupt flag ( set by the processor when the interrupt is triggered ) set the edge we are triggering on to rising if it was falling and vise versa.  
  
 
====== Post Interrupt: ======  
 
====== Post Interrupt: ======  
Line 210: Line 179:
 
The code in the interrupt subroutine, also know as the interrupt service routine or isr:
 
The code in the interrupt subroutine, also know as the interrupt service routine or isr:
  
if  ( ( test_bit( intcon, INTE ) ) &&  ( test_bit( intcon, INTF ) ) ) {
+
if  ( ( test_bit( intcon, INTE ) ) &&  ( test_bit( intcon, INTF ) ) ) {
clear_bit( intcon, INTF );  // the flag  
+
clear_bit( intcon, INTF );  // the flag  
+
 
+
 
unsigned char period = 0;  // time from last transition
+
unsigned char period = 0;  // time from last transition
clear_bit( intcon, INTF );    // the flag  
+
clear_bit( intcon, INTF );    // the flag  
+
// read the timer1
+
// read the timer1
clear_bit( t1con, TMR1ON );       
+
clear_bit( t1con, TMR1ON );       
// T1CON: Timer1 On  1 = Enables Timer1 0 = Stops Timer1
+
// T1CON: Timer1 On  1 = Enables Timer1 0 = Stops Timer1
 
+
period = tmr1h;    // just use the high byte
+
period = tmr1h;    // just use the high byte
+
// reset timer1
+
// reset timer1
tmr1l = 0;
+
tmr1l = 0;
tmr1h = 0;
+
tmr1h = 0;
+
set_bit( t1con, TMR1ON );      // Timer1 On  1 = Enables Timer1 0 = Stops Timer1
+
set_bit( t1con, TMR1ON );      // Timer1 On  1 = Enables Timer1 0 = Stops Timer1
+
// store in the log
+
// store in the log
  logData[ logIx ] = period;
+
logData[ logIx ] = period;
 
+
 
// set up for next interrupt
+
// set up for next interrupt
+
if ( iRLow ) {
+
if ( iRLow ) {
set_bit( option_reg, INTEDG ); // set  rising edge  clear falling edge
+
set_bit( option_reg, INTEDG ); // set  rising edge  clear falling edge
} else {
+
} else {
clear_bit( option_reg, INTEDG ); // set  rising edge  clear falling edge
+
clear_bit( option_reg, INTEDG ); // set  rising edge  clear falling edge
}
+
}
iRLow = !iRLow;
+
iRLow = !iRLow;
+
set_bit( intcon, INTE );  // set = enable
+
set_bit( intcon, INTE );  // set = enable
+
+
}
+
}
return;
+
return;
}
+
}
 
 
 
Note that:
 
Note that:
*we save the period in a ( global ) array, logData[ logIx ],  for later use,
+
we save the period in a ( global ) array, logData[ logIx ],  for later use,
*set the interrupt edge to the opposite it was,   
+
set the interrupt edge to the opposite it was,   
*and keep a ( global ) variable, iRLow, to tell us if the next state will be high or low ( iRLow )
+
and keep a ( global ) variable, iRLow, to tell us if the next state will be high or low ( iRLow )
  
  
OK that is the heart of the routine, how do we get in and how do we get out?
+
OK that is the heart of the routine, how do we get in and how do we get out.
  
 
===== Getting In: =====  
 
===== Getting In: =====  
  
 
Getting In:
 
Getting In:
For this code ( and I am not sure this is a great way, but it works and uses more interrupt programming ) I chose to wait for a period of no signal.  My basic idea is this.  Set two interrupts, one based on time, and one based on getting an IR signal.  If the time interrupt goes off first then there was no IR if the IR interrupt goes off first then there is an IR signal.  While I am waiting for the interrupt I can have the processor do something else.
+
For this code ( and I am not sure this is a great way, but it works and uses more interrupt programming ) I chose to wait for a period of no signal.  My basic idea is this.  Set two interrupts one based on time and one based on getting an IR signal.  If the time interrupt goes off first then there was no IR if the IR interrupt goes off first then there is an IR signal.  While I am waiting for the interrupt I can have the processor do something else.
  
 
Setup:
 
Setup:
Line 270: Line 239:
  
  
iRLow = true;
+
iRLow = true;
clear_bit( option_reg, INTEDG ); // set  rising edge  clear falling edge
+
clear_bit( option_reg, INTEDG ); // set  rising edge  clear falling edge
clear_bit( intcon, INTF ); // the interrupt flag
+
clear_bit( intcon, INTF ); // the interrupt flag
logIx = 0;  // reset the log
+
logIx = 0;  // reset the log
+
// turn off all the interrupts we are using
+
// turn off all the interrupts we are using
 
+
  clear_bit( pie1, TMR1IE );     // TMR1IE = timer 1 interrupt enable / set = enable
+
clear_bit( pie1, TMR1IE );     // TMR1IE = timer 1 interrupt enable / set = enable
  clear_bit( pir1, TMR1IF ); // clear timer 1 interrupt flag bit
+
clear_bit( pir1, TMR1IF ); // clear timer 1 interrupt flag bit
 
+
 
  clear_bit( intcon, INTE ); // INTE = external int erupt enable / set = enable
+
clear_bit( intcon, INTE ); // INTE = external int erupt enable / set = enable
clear_bit( intcon, INTF ); // INTF = external int erupt flag / clear = clear
+
clear_bit( intcon, INTF ); // INTF = external int erupt flag / clear = clear
+
 
+
IRState = IRSTATE_WAIT;
+
IRState = IRSTATE_WAIT;
// clear timer0 flag and enable
+
// clear timer0 flag and enable
+
 
// set counter to something low ( do we need to mess with the prescaler )
+
// set counter to something low ( do we need to mess with the prescaler )
+
clear_bit( t1con, TMR1ON );      // Timer1 On  1 = Enables Timer1 0 = Stops Timer1
+
clear_bit( t1con, TMR1ON );      // Timer1 On  1 = Enables Timer1 0 = Stops Timer1
tmr1l = 0;
+
tmr1l = 0;
tmr1h = 0;
+
tmr1h = 0;
  set_bit( t1con, TMR1ON );          // Timer1 On  1 = Enables Timer1 0 = Stops Timer1
+
set_bit( t1con, TMR1ON );          // Timer1 On  1 = Enables Timer1 0 = Stops Timer1
+
  // now turn them both on and let the race begin  
+
// now turn them both on and let the race begin  
+
set_bit( pie1, TMR1IE );     // TMR1IE = timer 1 interrupt enable / set = enable
+
set_bit( pie1, TMR1IE );     // TMR1IE = timer 1 interrupt enable / set = enable
set_bit( intcon, INTE ); // INTE = external interrupt enable / set = enable
+
set_bit( intcon, INTE ); // INTE = external interrupt enable / set = enable
+
 
====== Interrupt: ======  
 
====== Interrupt: ======  
  
Line 304: Line 273:
 
We need to use our state variables, flags etc to distinguish between the earlier interrupt and then to figure out who won the race.  If the signal was absent we set up for the ready state. If the signal was present we enter the busy and turn off the interrupts.
 
We need to use our state variables, flags etc to distinguish between the earlier interrupt and then to figure out who won the race.  If the signal was absent we set up for the ready state. If the signal was present we enter the busy and turn off the interrupts.
  
if  ( ( test_bit( intcon, INTE ) ) &&  ( test_bit( intcon, INTF ) ) ) {
+
if  ( ( test_bit( intcon, INTE ) ) &&  ( test_bit( intcon, INTF ) ) ) {
clear_bit( intcon, INTF );  // the flag  
+
clear_bit( intcon, INTF );  // the flag  
+
  if ( ( IRState  == IRSTATE_READY ) ||  ( IRState  == IRSTATE_READ )) {
+
if ( ( IRState  == IRSTATE_READY ) ||  ( IRState  == IRSTATE_READ )) {
+
..... this is the code we have already covered  
+
..... this is the code we have already covered  
+
}
+
}
} else {  // should be state wait  
+
} else {  // should be state wait  
// bad, we got ir before time out
+
// bad, we got ir before time out
IRState  = IRSTATE_BUSY;
+
IRState  = IRSTATE_BUSY;
...... both interrupts off  
+
...... both interrupts off  
 
 
}
 
}
 
 
 
//Handle timer1 interrupt
 
if( pir1 & (1<<TMR1IF) )  {
 
 
// timer interrupted before ir began
 
IRState = IRSTATE_READY;
 
clear_bit( pie1, TMR1IE ); // done with the time interrupt 
 
 
clear_bit( intcon,  INTF );  // the flag
 
set_bit( intcon, INTE );     
 
// inte = interrupt enable, think just rb0, set = enable
 
 
}
 
 
return;
 
  
Note:  not show here ( but present in the full code ) is the use of the global interrupt enable.  It is one instruction that can turn off all interrupts.  It has to be turned on before any interrupts will take place. Also in the full code an interrupt is used to support the RS232 receiver.
 
  
===== Getting Out =====
+
}
 +
}
 +
 
 +
//Handle timer1 interrupt
 +
if( pir1 & (1<<TMR1IF) )  {
 +
 +
// timer interrupted before ir began
 +
IRState = IRSTATE_READY;
 +
clear_bit( pie1, TMR1IE ); // done with the time interrupt 
 +
 +
clear_bit( intcon,  INTF );  // the flag
 +
set_bit( intcon, INTE );     
 +
// inte = interrupt enable, think just rb0, set = enable
 +
 +
}
  
My way of detecting the end of transmission is to wait a while for the IR signal to "go out".  How do I do this?  It is based on another race between the RB0 and Timer interrupt.  If the Timer goes off then the IR signal is out and the signal is over.  As a slight additional trick I do not start the timer at 0 so I still control how long the delay of no IR is.  So after checking why we are in the timer interrupt:
+
return;
  
    clear_bit( intcon, INTE );      // inte = interrupt enable, think just rb0, set = enable
+
Note:  not show here ( but present in the full code ) is the use of the global interrupt enable.  It is one instruction that can turn off all interrupts.  It has to be turned on before any interrupts will take place. Also in the full code an interrupt is used to support the RS232 receiver.
    clear_bit( pie1, TMR1IE );     // TMR1IE = timer 1 interrupt enable set = eanble
 
    IRState = IRSTATE_GOT;
 
    serial_printf( "irstate=got\r" );
 
  
===== Breaking Out =====
 
  
On receiving the ! character the program should "break out" of the reading IIR routine.  The problem is that it is not really in a routine, it is almost always waiting for interrupts.  The key is to get the interrupts off.  That is pretty much it.  Do not turn on again untill you are all set up.
+
===== Getting Out =====
  
[[category:Microcontroller]][[category:PIC]]
+
need to write this still

Please note that all contributions to OpenCircuits may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see OpenCircuits:Copyrights for details). Do not submit copyrighted work without permission!

Cancel Editing help (opens in new window)