Lecture: | 17 |
Objective: | Provide more examples of how interrupts
can provide a low-level software interface to hardware.
|
Interrupt Challenges
Here are a pair of challenges that will help you develop your
understanding of interrupts.
One wheel rotation
Your robot has DC motor driving a wheel which you want to rotate exactly once.
To help with this task, the wheel's rotation is tracked by an encoder that
pulses 12 times for each rotation of the wheel. The motor drive signal is
connected to RC1. When RC1 equals 1, the motor (and wheel) turn.
When RC1 equals 0, the motor (and wheel) are stopped.
Because main is preoccupied with other tasks, you need to write
an ISR that keeps track of the wheel's position. In particular you
need to write an ISR that stops the motor when the wheel has made one
complete rotation.
To accomplish this, you decide to route the pulses into
RC2 and use the associated CCP1 capture interrupt to stop the
motor when it has made one complete rotation. Note, we will be using the
capture mode, not to measure the duration of the pulses, but just to
call the ISR when a positive edge of a pulse is detected.
You use the following code in your initPIC(); function to
configure the CCP1 capture to interrupt on positive edges
of the RC2 pin.
void initPIC(void) {
TRISCbits.RC1 = 0; // Make pin RC1 (motor control) and output
TRISCbits.RC2 = 1; // Make pin RC2 an input
CCP1CONbits.CCP1M = 0b0101; // Enable the capture channel 1 on rising edge
CCPTMRS0bits.C1TSEL = 0b00; // Associate TMR1 with CCP1
T1CONbits.TMR1ON = 1; // Turn on timer 1
PIR1bits.CCP1IF = 0; // Clear the CCP1 flag
PIE1bits.CCP1IE = 1; // Enable CCP1 interupts
INCONbits.PIE = 1; // Enable perhipheral interrupts
INCONbits.GIE = 1; // Enable global interrupts
} // end initPIC
This initialization code ensures that the ISR is called every time a
positive edge arrives on pin RC2.
While there are several ways to go about accomplishing this goal,
your team has decided on the following approach. Main will decide
when to start the wheel turning by setting
RC1 = 1;
and by setting a global flag
called
motorMode. When the motor completes
a single rotation, the ISR will turn the motor off by setting RC1 = 0;
#define MOTOR_ON 1
#define MOTOR_OFF 0
uint8_t motorMode = MOTOR_OFF;
void main(void) {
initPIC();
for (;;) {
// lots of important stuff
LATCbits.LATC1 = 1; // Start motor turning
motorMode = MOTOR_ON; // Set flag for ISR
while(motorMode == MOTOR_ON); // The ISR will clear the motorMode
// flag after one rotation
} // end infinite loop
} // end main
When the ISR has counted 12 positive edges the ISR will set RC1=0;
and clear the global flag called
motorMode.
//*****************************************************************
//*****************************************************************
void high_priority interrupt pulse_isr(void) {
static uint8_t motorPulseCount = 0;
if (motorMode == MOTOR_ON) {
motorPulseCount += 1;
if (motorPulseCount == 12) {
motorMode = MOTOR_OFF;
motorPulseCount = 0;
LATCbits.LATC1 = 0;
} // end if
}
PIF1bits.CCP1IF = 0;
} // end isr
You should note that the static variable motorPulseCount keeps
track of the number of pulses and shuts down the motor when a
single rotation has been made.
Wheel rotations
Now that you have the idea of how to get one rotation, let's add
some more functionality.
- main will write to a global
variable numRotations the number of
wheel rotations it wants completed. The number of wheel rotations
will always be less than or equal to 200.
- main will set the global flag motorMode.
- main will set RC1 to turn the motor on.
The ISR will count the rotations, decrementing
numRotations after each wheel rotation.
When the number of rotations reaches 0, the ISR should stop the
wheel and clear the global flag
motorMode.
//*****************************************************************
//*****************************************************************
void high_priority interrupt pulse_isr(void) {
static uint8_t motorPulseCount = 0;
if (motorMode == MOTOR_ON) {
motorPulseCount += 1;
if (motorPulseCount == 12) {
numRotations -= 1;
motorPulseCount = 0;
if (numRotations == 0) {
motorMode = MOTOR_OFF;
LATCbits.LATC1 = 0;
} // end if completed all the rotations
} // end if completed one more rotation
} // end if the wheel is turning
PIF1bits.CCP1IF = 0;
} // end isr