View Single Post
  #5   Spotlight this post!  
Unread 25-08-2006, 12:44
GlennGraham's Avatar
GlennGraham GlennGraham is offline
Registered User
AKA: Glenn Graham
FLL #0006 (Shark Bait!)
Team Role: Coach
 
Join Date: Jan 2006
Rookie Year: 2003
Location: Beaverton, Oregon
Posts: 20
GlennGraham is an unknown quantity at this point
Re: Reading an encoder with interrupts

Thanks, yes, it does look like the timer is used to measure the interval between interrupts.

I made some good progress last night working with the white paper on using timer interrupts as well as the data sheet for the controller. I first got the timer working and then was able to hook up a switch to the #2 interrupt port and react to it. The switch was REALLY noisy so I ended up coding an example that disables the switch interrupt for a short time after it triggers to let it settle by using the timer interrupt. Tonight I will replace the switch with the encoder. I might hook up the scope to see how noisy the transitions from low/high/low are.

In the hopes that this thread might be helpful to someone later doing a search on this subject, here are snippets of my code (use the whitepaper and data sheet mentioned above for context):

Add to User_Initialization() in user_routines.c
Code:
  // Example of how to set up a timer to be handled through interrupt
  T1CON = 0;
  T1CONbits.T1CKPS1 = 0;       // Prescale 11=1:8, 10=1:4, 01=1:2, 00=1:1
  T1CONbits.T1CKPS0 = 0;
  TMR1H = 0x85;                // Pre-load TMR1
  TMR1L = 0xED;                //   - Done to remove time from total to get correct period.
  T1CONbits.TMR1ON = 0;        // Turn timer off
  IPR1bits.TMR1IP = 0;          // Set Timer1 Interrupt to low priority
  PIE1bits.TMR1IE = 1;          // Interrupt when Timer1 overflows
  INTCONbits.GIEL = 1;          // Enable Global Low Priority Interrupts

  // Example of how to set up a peripheral interrupt
  INTCON2bits.INTEDG3 = 0;     // Set INT3/rc_dig_int2/Interrupt port #2 - falling edge triggered
  INTCON2bits.INT3IP = 0;      // set rc_dig_int2 low priority
  INTCON3bits.INT3IF = 0;      // clear int flag for rc_dig_int2
  INTCON3bits.INT3IE = 1;      // Enable rc_dig_int2
In user_routines_fast.c
Code:
/*** DEFINE MY ROUTINES AND VARIABLES ***/
void Handle_Timer1_Interrupt(void);
void Handle_Encoder_Interrupt(void);
unsigned char UpdateDisplay;
unsigned int EncoderTickCount;
Code:
void InterruptHandlerLow ()     
{                               
  unsigned char int_byte;       

  if (INTCON3bits.INT2IF && INTCON3bits.INT2IE)       /* The INT2 pin is RB2/DIG I/O 1. */
  { 
    INTCON3bits.INT2IF = 0;
  }
  else if (INTCON3bits.INT3IF && INTCON3bits.INT3IE)  /* The INT3 pin is RB3/DIG I/O 2. */
  {
    INTCON3bits.INT3IF = 0;      // Clear the flag
    Handle_Encoder_Interrupt();
  }
  else if (INTCONbits.RBIF && INTCONbits.RBIE)  /* DIG I/O 3-6 (RB4, RB5, RB6, or RB7) changed. */
  {
    int_byte = PORTB;        /* You must read or write to PORTB */
    INTCONbits.RBIF = 0;     /*     and clear the interrupt flag         */
  }                          /*     to clear the interrupt condition.  */
  else if (PIR1bits.TMR1IF )
  {
    PIR1bits.TMR1IF = 0;        // Clear the Timer1 Interrupt Flag
    Handle_Timer1_Interrupt();
  }
}
Code:
/*
* Interrupt Handlers: Set up the handlers so that if an interrupt occurs on
* the Interrupt #2 port we:
*  1) Disable the interrupt so that noise does not re-trigger it
*  2) Increment the counter
*  3) Turn on timer2 which, when overflow occurs will re-enable interrupt #2 after noise has passed
*
* Works well with a noisy switch connected to interrupt 2. The timer allows the switch to settle
* before re-enabling the interrupt. 
*/

void Handle_Encoder_Interrupt(void)
{
  INTCON3bits.INT3IE = 0;      // Disable encoder interrupt
  EncoderTickCount++;          // Increment counter
  T1CONbits.TMR1ON = 1;        // Start timer to wait until noise settles
  UpdateDisplay = 1;           // Set flag to output current count in
                               // Process_Data_From_Local_IO()
}

void Handle_Timer1_Interrupt(void)
{

    T1CONbits.TMR1ON = 0;            // Stop 10MHz Timer
    TMR1H = 0xBF;                    // Reset Timer. Pick value based on switch characheristics 
    TMR1L = 0xFF;                    // BFFF works, EFFF too short (lets bounces through).
    INTCON3bits.INT3IF = 0;          // Re-clear any pending interrupts that may have occured.
    INTCON3bits.INT3IE = 1;          // Enable encoder interrupt
}
Code:
void Process_Data_From_Local_IO(void)
{
  /* Add code here that you want to be executed every program loop. */
  if (UpdateDisplay) {
    INTCONbits.GIEL = 0;               // Disable low priority interrupts
    UpdateDisplay = 0;
    INTCONbits.GIEL = 1;               // Enable low priority interrupts
    printf("Ticks %d\n",(int)EncoderTickCount);
  }
}
Reply With Quote