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. 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