Lecture: 16
Objective: Build an ISR that measure pulse durations.

Interrupts

Capture Interrupt Exercise

Given:
An encoder connected to RC2 generates logic 1 pulses between 5 ms and 30ms in duration. You need to know the duration of these pulses (in terms of timer counts). Unfortunately, your processor already has a lot of other things it is doing so the decision was made to use an interrupt service routine to measure the length of the pulses and store the most recent pulse duration in a global variable pulseDuration. In addition, in order to let main know when a new pulse has been measured by the ISR, the ISR will set the global variable newPulseDuration to 1.

Solution
Let's start by taking a broad view of the problem and our approach to finding a solution. The figure below shows a pulse on RC2 and some of the actions that we need to take.

Since we are interested in the value of TMR1 at both the beginning and ending of the pulse, we need to configure the capture subsystem to detect both the rising and falling edges of the pulse. Unfortunatly, we cannot do this with a single setting, so will have to switch between detecting positive edges at the start of the pulse with CCP1CONbits.CCP2M = 0b0101; and detecting negative edges at the end of the pulse with CCP1CONbits.CCP2M = 0b0100; When the edge occurs two things wil loccur; the current TMR1 will be store in CCP1 and the edge will cause the PIR1bits.CCP1F flag to be set. When interrupts are enabled, setting CCP1F will cause the ISR to run.

Since the ISR can be called on either the rising and falling edges of RC1, the ISR should test the value of RC2 to determine if it had been called on a rising or falling edge. If the ISR reads RC2 as a logic 1, then the ISR was activated by a positive edge. Note that the ISR does require a small but finite amount of time to be called and to start running. This is more than enough time for RC2 to stabalize to logic 1 by the time that we read its value inside the ISR.

On the positive edge we should store CCP1 as the start time of the pulse. There are two other things that need to be done, the first is to configure the capture module to look for a negative edge by setting CCP1CONbits.CCP2M = 0b0100; and clearing the CCP1IF flag. After doing these two things, so the ISR should exit. Note that we want to store the start timer count until the next ISR invocation on the falling edge of the pulse, so we need to store the start time in the ISR as a static variable.

On the negative edge of the pulse, the ISR will read a logic 0 on RC2 (because the ISR takes a small amount of time to start running the code). The difference between CCP1 and the start time represents the pulse duration and the ISR should write a new value to this global variable. In addition, the ISR should set the new pulse duration flag so that main knows that the ISR has computed a new value. Main is welcome to later clear this flag if it wants to be alerted to any new subsequent pulse duration values.

Now, let's follow the outline presented in an earlier lecture to develop our solution. In order to use interrupts in your programs you will need the following 6 components somewhere in your program.
  1. Configure hardware to operate as needed
  2. Configure hardware to generate an interrupt signal
We can handle the first two tasks inside the initPIC() function. There are three pieces of hardware that need configured: