INT1. Perfect! Listing 2 shows all that needs to be done to
capture these pulses from the motor.
Note that I am using both interrupt lines to capture
each phase of the encoder, and that I count each rising
edge. This gives me 360 tics per revolution which is
pretty decent. However, if I had two motors — which is
quite reasonable — then I’d want to use an interrupt for
each motor. In this case, I would not capture the second
phase — only the first for each motor. This reduces my
resolution to 180 tics per revolution, or two degrees per
tic. Still not too bad. Look at ISR(INT0_vect). You see that
I set the motor direction by looking at the logic level of
the second quadrature phase. Let’s discuss that a little. In
Figure 6, I show the phase relationship between the two
quadrature encoder outputs. By examining these pulse
trains, you can see how easy it is to determine the motor
direction.
ISR(INT0_vect) is triggered at point A in Figure 6; at
the same time the ISR looks at the other quadrature line to
determine the direction of the wheel turn. At point B,
ISR(INT1_vect) is triggered and the tic count is incremented
again. To get perfect symmetry in the wheel encoder count,
we really should trigger at the falling edge of the pulse
after point A; where I trigger it now is off by 0.5 degrees.
}
It still works pretty well, however.
How do we know the direction? Look at the two sets
of pulse trains in Figure 6. When going forward, the INT0
ISR triggers at point A. At this time, we look at the other
phase and see that it is logic low. We’ll call this forward.
When we look at the reverse pulse train pair, we see that at
}
LISTING 2. Motor encoder ISRs.
/*
Deal with interrupt modified variables.
*/
//phase encoder counts (one rotation=180
// or 360 tics)
volatile uint16_t pTics;
// What is the measured direction?
volatile uint8_t direction;
/*
Deal with the quadrature encoders as IRQs.
INT0 counts phase 1 encoder rising edges
*/
ISR(INT0_vect)
{
pTics++;
direction = PHASE2;
// FWD if low,
// REV if high
/*
Yup, the other phase rising transitions.
*/
ISR(INT1_vect)
{
pTics++;
LISTING 3. Main() loop.
/*
* This code exercises the LEGO servo motor
* and its encoders
*/
int main(void)
{
//Initialize the board and stdio
initialize();
fileDef = fdevopen(def_putc, def_getc);
MotorsStop(); // turn off for now
pTics = 0;
pTics = 0;
MotorsGo(100,100);
while(pTics < 1000)
;
MotorsStop();
pTics = 0;
MotorsGo(-100,-100);
while(pTics < 1000)
;
MotorsGo(100,100);
//Just to hit the “brakes”
waitms(100);
MotorsStop();
printf(“Waiting 10 seconds to
time out\n\r”);
waitms(10000);
/*
Go forward and back the same distance
to see how the encoders work. I am using
5cm diameter wheels giving a 15.71cm
rollout (circumference). Going 1000 tics,
when we count a tic every 1 degree means
1000/360 = 2.78 revolutions. 2.78 times
15.71 = 43.6cm distance traveled.
}
We hit it dead on.
}
*/
/*
Now let’s just twiddle the motors back
and forth to see the direction changes.
*/
while(1)
{
//Blink an LED on this port
// to show we’re running
PORTBbits.b5 = ~PORTBbits.b5;
waitms(1000);
printf(“dir= %d speed = %d\n\r”,
direction, pTics);
SERVO 07.2009
17