avr-chat
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [avr-chat] Using Rotary Encoders...


From: Larry Barello
Subject: RE: [avr-chat] Using Rotary Encoders...
Date: Tue, 20 Sep 2005 22:42:16 -0700

One suggestion: Trigger on both the rising and falling edge of the A line
(or B) and use your logic to increment/decrement the counter.

The problem you are having is that at the threshold of a 0->1 transition,
you can have the output bounce up and down simply due to mechanical jitter.
Your software is a bit too simple in that it only considers the up
transition, so when there is mechanical jitter around a threshold rather
than counting up/down/up it just counts up, up (the B line never changes)

Using both edges is simple: On the positive edge, change the edge sense in
MCUCR (or wherever it is).  You can conditionally jump to the positive and
negative edge code based upon that same bit in the I/O register.  SO, your
code just bounces between one and the other.


-----------
Larry Barello
www.barello.net



-----------
Larry Barello
www.barello.net


| -----Original Message-----
| From: address@hidden [mailto:avr-chat-
| address@hidden On Behalf Of Vincent Trouilliez
| Sent: Tuesday, September 20, 2005 10:01 PM
| To: avr-chat
| Subject: [avr-chat] Using Rotary Encoders...
| 
| Hi gents,
| 
| 
| I would like your opinions/experiences about using rotary encoders. I
| have planned on using one for my project, so ordered one to experiment
| with (never used them before).
| It's a mechanical one, with the usual 2-bit gray code output.
| 
| I was expecting loads of bounces, but got only a few glitches, so was
| impressed by the quality of the unit despite the affordable price (under
| 6 Euros). Wanting to get rid of these few glitches and make it perfect,
| I used a timer to allow 50ms for bounces to go away, plenty enough
| according to the datasheet which stated 5ms max, and my observations on
| the scope showing that pulses were mostly about 10 to 15ms wide max,
| under normal conditions (ie, not turning it too slowly). So, 15+5 = 20,
| 50ms should cover any amount of bouncing.
| 
| However this is where the problem start : even with this huge delay, I
| still get these glitches. Sometimes it will count 2 pulses instead of
| one, or the count won't move, or it will decrement instead of
| increment...
| 
| So since I have zero experience with these things, I don't really know
| what to think:
| 
| 
| 1) The encoder works perfectly most of the time, and the glitches appear
| even when I am turning the shaft slowly, one step at a time. So the
| encoder must be okay, and my software has a bug.
| 
| 2) The other way around : my programme is so simple, it can't go wrong,
| and since the encoder has mechanical contacts, it's most likely at
| fault, you get what you pay for, go fork out the cash for an optical
| encoder.
| 
| 3) The program is fine, the encoder "should" be glitch free, but you
| just happen to have a faulty unit (I noticed that the shaft has too much
| radial play to my taste, but then what do I know... ), just get another
| one and you will be fine.
| 
| 
| I pasted the relevant bits of my program below. I wired channel B on
| INT0 and set it to trigger on a rising edge. Then in the ISR I increment
| or decrement the counter, depending on the logic level of channel A
| (going CW or CCW).
| That worked fine (bar the random glitches). Then I added the 50ms delay
| to see if that would improve things, but no :o(
| I turn an LED on when the pulse/rising edge has been detected, and I
| turn it off once the 50ms delay has elapsed. This produces a short flash
| which I can about see. I just noticed, however, that whenever a glitch
| happens, I get a BIG flash from the LED ! Now what does that mean, I
| don't know exactly, but at least it gives me something to work on...
| 
| 
| Any ideas/comments, are most welcome :-)
| 
| 
| --
| Vince
| 
| 
| SIGNAL (SIG_INTERRUPT0)
| {
| 
|       PORTD = 0xFF;           //turn LED on when the pulse has been
| detected
|       if ( PIND & _BV(PD6) )  //if Channel A is high
|               encoder_count++;        //then the knob has been turned
clockwise
|       else
|               encoder_count--;        //if not... then must have been CCW
!! ;-)
| 
|       GICR &= 0xBF;           // disable encoder interrupt to avoid
| counting bounces
|       TCNT0 = 0;              //reset debounce timer
|       TIMSK |= _BV( OCIE0 );  //enable timer interrupt
| 
| }
| 
| SIGNAL (SIG_OUTPUT_COMPARE0)
| {
| 
|       PORTD = 0x00;   //50ms debounce delay is over, turn LED off
|       TIMSK &= ! _BV( OCIE0 );        //disable timer interrupt
|       GICR |= _BV( INT0 );    //enable encoder interrupt again
| 
| }
| 
| 
| void ioinit (void) {
| 
|       DDRD    = 0x20; //outputs : PD5 (LED), Inputs : PD6 (Encoder 'A'
| channel)
|       //set up timer0
|       OCR0    = 50;   // about 50ms delay
|       TCCR0   = 0x1D; // compare mode mode, prescaler = 1024
|       //set interrupts
|       GICR    = 0x40; //enable INT0 interrupt (Encoder 'B' channel).
|       MCUCR   = 0x03; //set INTO to trigger on rising edge
|       sei();          //enable global interrupts
| }
| 
| int main (void){
| 
|       ioinit ();
|       lcd_init();
| 
|       while(TRUE){
| 
|               lcd_goto_rc(1,1);       //print counter value in top left
corner of
| the LCD
| 
|               GICR &= ~( _BV( INT0 ) ); //disable INT0 interrupt while
| reading counter contents
|               dot_two(encoder_count); // display counter content on the
LCD
|               GICR |= ( _BV( INT0 ) ); //re-enable interrupt
| 
|               _delay_ms(100); //simulate a busy main loop
| 
|       }
| 
| }
| 
| 
| 
| _______________________________________________
| AVR-chat mailing list
| address@hidden
| http://lists.nongnu.org/mailman/listinfo/avr-chat






reply via email to

[Prev in Thread] Current Thread [Next in Thread]