Arrgghhh... rotary encoder with interrupt issues

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Has anybody had success using a (cheap) rotary quadrature encoder in interrupt mode and is willing to share their GCC code?

I'm having a dickens of a time with erratic behaviour – mostly because of bounce I’m sure. I’ve done it successfully on am ehhem… :oops: PIC but have switched my design some time ago to a Mega32.

I'm trying to do this without adding additional hardware for debounce and need to do it through interrupt instead of polling.

I already have very little hair as it is and cannot afford to pull the rest out.

here's the very basic interrupt code

Encoder_Input_Port_DDR &= ~((1<<Encoder_Pin_1) | (1<<Encoder_Pin_2));    //set the pins on the encoder port for input (Logic 0)
MCUCSR &= ~(1<<ISC2);//Clear the ISC2 bit to 0 (falling edge trigger) in the MCUCSR
GICR |= (1<<INT2); //Enable the INT 2 interrupt
}              
 
ISR(INT2_vect)  // Interrupt Service Routine if using INT on encoder
{
_delay_ms(5);     //debounce – perhaps wait longer?
 
// if the other pin is high on the falling edge of the interrupt 
// then the encoder is going one way
//if the pin is low it’s going the other way so…
 
if (Encoder_Input_Port & (1<<Encoder_Pin_2))
{
                Encoder--;
}
 
else 
{
                Encoder++;
} 
 
}
 

Thank you for your time

Tom

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

is Encoder_Input_Port expanding to PORTx or PINx ?

It should be expanding to PINx, and not PORTx

Where, x, is the port letter you are using of course.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define Encoder_Pin_1		2											// Define the pins on the port the encoder is on
#define Encoder_Pin_2		3											// make sure it support interrups if you need them
#define Encoder_Input_Port		PINB						//define the port the encoder is on
#define	Encoder_Input_Port_DDR	DDRB					//define the direction register - 

:wink:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think the likely-hood is bounce too, but probably something you can get around.

You do not disable the interrupt in GICR when you enter the ISR, so any further negative edges will result in the flag being set again whilst you are waiting for the "debounce" to timeout.

Once you come out of the interrupt, you'll enter it again because of the trigger from the bounce - producing an erroneous result.

I would suggest disabling INT2 as the first thing you do in the ISR and then waiting 5ms before checking the second input. This should stop false interrupt triggers from bounce. Then re-enable INT2 at the end of the ISR.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hmm... thanks Brian. I was under the impression that the ISR code 'automatically' disables any other interrupts until the ISR is complete. (Using latest WinAVR)

I'll try your suggestions anyway.

Tom

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Note: if you want interrupts (globally) disabled in your ISR, use SIGNAL instead. ISR enables interrupts again before executing your code.

- kwr

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If I read the avr-libc documentation correctly ISR and SIGNAL are the same. i.e. Both disable global interrupts when the interrupt routine is called.

Only a few follicles
T

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Note: if you want interrupts (globally) disabled in your ISR, use SIGNAL instead. ISR enables interrupts again before executing your code.

No it doesn't. ISR is exactly equivalent to the old SIGNAL macro, with the change being due to people not reading the manual and using INTERRUPT when they really wanted SIGNAL. Nowadays there isn't a modern equivalent for the deprecated INTERRUPT macro, at least until my enhanced ISR macro header file is accepted into the AVRLibC codebase.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tomasch wrote:
hmm... thanks Brian. I was under the impression that the ISR code 'automatically' disables any other interrupts until the ISR is complete. (Using latest WinAVR)

I'll try your suggestions anyway.

Tom

Well yes it disables them in the sense that they are not executed when they happen. However teh flags still get set, and teh CPU will execute them once interrupts are re-enabled (which is when you exit your ISR)

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abcminiuser,

Sorry - my bad. I've been looking the gcc backend for avr and assumed ISR used the "interrupt" attribute (reenables interrupt).

Somewhere along the line I learned to use SIGNAL and never bothered with ISR or INTERRUPT.

Why would one want to use INTERRUPT at all anyway? (just want to understand the applications for it, not trying to troll or anything)

- kwr

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Why would one want to use INTERRUPT at all anyway? (just want to understand the applications for it, not trying to troll or anything)

It's a perfectly valid question. The INTERRUPT macro (or my enhanced ISR macro with the ISR_NOBLOCK modifier) allows for nested interrupts. Those can be useful for creating low-priority and high priority interrupts - for example, my app's LCD routine is interruptible but the serial receive ISR isn't.

It has its uses, when used in well thought out situations.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have a lok in this thread (german though) , use babelfish
http://www.mikrocontroller.net/t...

And this program , might give a hint (the sentence dateianhang in german means : "Attached file")
http://www.mikrocontroller.net/a...

remember to put avr in front of signal.h and interrupt.h like this , dont know what peter does with his headerfiles

/Bingo