Quadrature encoder for the O

The 20MHz mega644 should have no problem keeping up with 3000 interrupts per second.

Pin-change interrupt registers are detailed on page 62 of the mega644’s datasheet. Port A contains pins PCINT0 (PA0) through PCINT7 (PA7), port B contains pins PCINT8 (PB0) through PCINT15 (PB7), port C contains pins PCINT16 (PC0) through PCINT23 (PC7), and port D contains pins PCINT24 (PD0) through PCINT31 (PD7). The PCICR register is used to enable an entire port of pin-change interrupts (setting the PCIE0 bit of PCICR enables pin-change interrupts on port A, for example). The PCMSKx registers let you select which port pins can generate a pin-change interrupt. The following code will enable pin-change interrupts on pins PD3 (PCINT27) and PD7 (PCINT31):

DDRD &= ~(1 << PD3) & ~(1 << PD7); // make PD3 and PD7 inputs
PCMSK3 |= (1 << PCINT27) | (1 << PCINT31); // set pin-change interrupt mask for desired pins
PCICR |= 1 << PCIE3; // enable pin change interrupt for masked pins of port D
sei(); // set global interrupt enable

Now whenever the input on pin PD3 or PD7 changes value, the PCIF3 bit of the PCIFR register will be set and a PCINT3_vect() interrupt will be triggered. This by itself isn’t good enough, however, because you don’t know which pin changed and whether the change was from low to high or from high to low.

The following example shows how you can figure this out (I’ve set it up for pins PA0 - PA3, which you could use as quadrature inputs from your two motors):

unsigned char pinA;  // global for storing state of PINA

void init()
{
    DDRA &= 0xF0;   // make PA0 - PA3 inputs
    PCMSK0 |= 0x0F;    // set pin-change interrupt mask for desired pins
    PCICR |= 1 << PCIE0;    // enable pin change interrupt for masked pins of port A
    pina = PINA;    // save initial state of port A pins
    sei();    // set global interrupt enable
}


void PCINT0_vect()
{
    unsigned char newPinA = PINA;    // get new state of port A pins
    unsigned char changedBits = pinA ^ newPinA;    // if pin has changed, the corresponding changedBits bit will be set
    pinA = newPinA;    // save the new state of the pins

    unsigned char i;
    for (i = 0; i < (1 << 4); i <<= 1)
    {
        if (changedBits & i)
        {
            if (pinA & i)
            {
                // handle pin PAx change from low to high
            }
            else
            {
                // handle pin PAx change from high to low
            }
        }
    }
}

I haven’t tried compiling or testing any of this, but I think it should work.

- Ben