|
|
|
![]() |
|
|||||||
|
||||||||
![]() |
| Thread Tools | Rate Thread | Display Modes |
|
#1
|
||||
|
||||
|
Reading an encoder with interrupts
I started with EasyC, and then moved to MPLab using EasyC libraries. Now I am trying to get the same functionality by making the necessary changes to the VexCode source (user_routines.[ch] and user_routines_fast.c). I am trying to count clicks of the shaft encoder using an interrupt and I've been analyzing the user_routines_sensor_test_fast.c code as an example. The comment at the top that "Encoder not ready yet" had me worried but I saw a lot of code associated with it so I read on
With few comments in the code associated with the encoder, its tough for a beginner to work out the behavior. VexLabs makes it clear that they don't support the code so I thought I would ask and see if anyone here can lend some guidance.Has anyone here used this example successfuly? Would you mind explaining how the encoder interrupt handler works with the timer2 interrupt handler? Does anyone have another (possibly clearer) example they would like to share? Can someone explain why they would make this assignment: rc_dig_out11 ^= 1; rather than rc_dig_out11 = 1; ? Its a digital output so would there be a difference? I see quite a few uninitialized variables. EncoderDataTickCounter is an example. It is declared and incremented but never initialized. Must not be an issue for some reason. In the interrupt handler, EncoderDataFlag.bit1 is set but I don't see anywhere that it is cleared. The comment says it indicates that data is ready to be read. I will keep working on the problem and report back if I have anything useful for others in the same situation. Thanks for your time, -Glenn |
|
#2
|
||||
|
||||
|
Re: Reading an encoder with interrupts
Ok, I've been doing more searches through the messages. This time focusing on timers (rather than encoders) and interrupts. Lots of good stuff and the IFI white paper has been useful ( http://www.ifirobotics.com/docs/time...004-jan-14.pdf ).
Answered one question I had. I see that ^= is an exclusive OR assignment rather than OR so it will toggle the value. I'll be spending some time writing some code to exercise the timer interrupt. Hopefully that will shed some light on why it is being used in conjunciton with the encoder interrupt. -Glenn |
|
#3
|
||||
|
||||
|
Re: Reading an encoder with interrupts
Quote:
|
|
#4
|
|||
|
|||
|
Re: Reading an encoder with interrupts
Quote:
the timer interrupt occurs when the timer overflows, so that you will know if and how many times that has occurred between encoder interrupts. can't look at the code right now, but will if i have a minute later. |
|
#5
|
||||
|
||||
|
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 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);
}
}
|
![]() |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Problem with reading and writing EEPROM | DKolberg | Programming | 4 | 16-03-2004 19:29 |
| Help with pots/interrupts | mtrawls | Programming | 10 | 24-02-2004 17:01 |
| EDU Demo Code: Encoder Interfacing Using Interrupts | Kevin Watson | Programming | 4 | 08-01-2004 23:14 |
| help with Interrupts | thoughtful | Programming | 5 | 08-01-2004 16:07 |
| Problem with interrupts on the PIC | Mike Betts | Programming | 7 | 16-12-2003 21:26 |