I found my code written for some variant of the ATmega128. This was written for wheel encoders on a small robot so the signals are changing pretty fast. It also counts +4 for a complete transition. It counts each transition as + or - 1 depending on direction. This will need to be rethought for panel encoders but the idea is right. The interrupt handlers are pretty short!
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <ctype.h>
#include "defines.h"
volatile int8_t RightWheelState = 0;
volatile int32_t RightWheelCount = 0;
volatile int8_t LeftWheelState = 0;
volatile int32_t LeftWheelCount = 0;
volatile uint8_t urx;
volatile uint8_t urx_recv;
/* Quadrature Encoder Scheme
*
* There are two pairs of quadrature signals, one for each wheel.
* The right wheel is on EXINT4 (PE4) and EXINT5 (PE5)
* The left wheel is on EXINT6 (PE6) and EXINT7 (PE7)
* Each encoder has two outputs A & B. For convenience, A is considered the MSB
* while B is considered the LSB.
*/
const int32_t EncoderB[] = {+1,-1,-1,+1};
const int32_t EncoderA[] = {-1,+1,+1,-1};
SIGNAL(SIG_INTERRUPT4) // encoder B for right wheel
{
EICRB ^= 0x01; // toggle the edge bit
RightWheelState ^= 0x01;
RightWheelCount += EncoderB[RightWheelState];
}
SIGNAL(SIG_INTERRUPT5) // encoder A for right wheel
{
EICRB ^= 0x04;
RightWheelState ^= 0x02;
RightWheelCount += EncoderA[RightWheelState];
}
SIGNAL(SIG_INTERRUPT6) // encoder B for left wheel
{
EICRB ^= 0x10;
LeftWheelState ^= 0x01;
LeftWheelCount += EncoderB[LeftWheelState];
}
SIGNAL(SIG_INTERRUPT7) // encoder A for left wheel
{
EICRB ^= 0x40;
LeftWheelState ^= 0x02;
LeftWheelCount += EncoderA[LeftWheelState];
}
void IOInit(void)
{
UBRR0H = 0;
UBRR0L = BAUD;
UCSR0B = _BV(RXEN) | _BV(TXEN) | _BV(RXCIE);
}
static int uart_putchar(char c, FILE * stream)
{
if (c == '\n')
uart_putchar('\r', stream);
while (! (UCSR0A & _BV(UDRE)))
;
UDR0 = c;
return c;
}
SIGNAL(SIG_UART0_RECV)
{
uint8_t s;
s = UCSR0A;
urx = UDR0;
if (bit_is_clear(s, FE))
urx_recv = 1;
}
void QuadInit(void)
{
LeftWheelState = (PORTE & 0xC0) >> 6;
RightWheelState = (PORTE & 0x30) >> 4;
EICRB = 0xff; // enable rising edge triggering on INT4..7
EICRB ^= (LeftWheelState & 0x02) << 5; // if a signal is already set
EICRB ^= (LeftWheelState & 0x01) << 4; // set the interrupt to falling edge
EICRB ^= (RightWheelState & 0x02) << 1;
EICRB ^= (RightWheelState & 0x01);
EIMSK = 0xf0; // enable these 4 interrupts
}
int main(void)
{
IOInit();
QuadInit();
sei();
fdevopen(uart_putchar, NULL);
printf("Hello World\n");
while (1) {
printf("LWS =%2d LWC =%6ld RWS =%2d RWC =%6ld\n",
LeftWheelState, LeftWheelCount, RightWheelState, RightWheelCount);
}
}
[/font]