Lecture: 12
Objective: How to measure time inteverals of pin events using the capture subsystem. This include the configuration of the subsystem and assocaited timers.
Code: lec12.c

Timer Capture

We have now examined two important components of the timer subsystem, the 16-bit counter and compare modules. The compare module looks for a match between TMRx and a value stored in CCPx. We now introduce a timer capability that allows you to capture the timer when a prescribed event occurs on the associated pin. This is the capture feature and is schematically represented in the figure below.

The timer subsystem, adapted from Figure 14-1 on page 174 of the PIC18(L)F2X/4XK22 Data Sheet

Capture Subsystem

The capture subsystem captures the value of TMRx when some prescribed event occurs on the associated pin. Let's start our discussion with the pin itself. Each capture/compare module is associated with a single pin given in the following table:
CCP module Pin
CCP1 RC2
CCP2 RC1 (or RB3)
CCP3 RB5 (or RC6)
CCP4 RB0
CCP5 RA4
In order to configure the capture function of the capture/compare subsystem, we need to configure the Mode Select bits in the CCPx control register.
CCPxM Configuration
0b0100 Capture on every falling edge
0b0101 Capture on every rising edge
0b0110 Capture on every 4th falling edge
0b0111 Capture on every 16th falling edge
The assignment of timer TMRx to Capture/Compare channel CCPx is accomplished with the CCP timer selection control register 0 (page 200 of the PIC18(L)F2X/4XK22 Data Sheet) called CCPTMRS0.
CxTSEL Timer
0b00 CCPx module uses TMR1
0b01 CCPx module uses TMR3
0b10 CCPx module uses TMR5
0b11 Reserved
This means that if you are using the CCP1 module and set CCP1M = 0b0100; and C1TSEL=0b00; then the every falling edge (transition from logic 1 to logic 0) will cause the current TMR1 value to be stored in CCP1.

In addition, when configuring the capture/compare subsystem in the capture mode, the associated pin should be configured as an input.

To see how these concepts can be applied to the solution of practical problems we will examine a device to determine the RPM of an engine and the second to determine the muzzle velocity of a projectile.

Quadrature Encoder

Imagine we are working in an application that has some moving mechanisms. Our system issues commands to move the mechanism by a finite amount. In many applications, the resulting movement will contain some amount of error. In applications where this uncertiantity is unacceptable, we need some feedback mechanism that tells the us how much the system actually moved. One popular feedback mechanism is a quadrature encoder or quad encoder for short. A quad encoder is a 2-channel sensor that provides directional as well as positional feedback. In other words, a quad-encoder tells you which direction the mechanism moved and by how much. A mechanical quad encoder is easily built from an a specially etched copper disk and a pair of contacts forming a pair of normally open switches shown in the yellow box in the schematic below. A pair of 10kΩ resistors pulls the switch outputs high. The internal mechanical operation of a mechanical quad encoder produces a lot of switch bouncing which is surpressed in this circuit with a pair of low-pass filters (formed by a 10kΩ and 0.01µF) in front of the signal output.

The 2 channels are frequenty called A and B. Both A and B are 50% duty cycle square waves. Each period of A or B corrsponds to some known amount of movement of the mechanism. The sqaure waves on channels A and B have the same frequency but are out-of-phase by 90°. The channel which has its positive edge 90° before the other channel's positive edge is said to lead. The image below shows two examples of the channels leading each other.

Taken from National Semiconductors "How Do I Use a Quadrature Encoder with My Data Acquisition Board?"

If each pulse on a channel represents a known amount of movement, then the speed of the mechanism is proportional to the number of pulses per unit time. More pulses in a unit of time means the mechanism is moving faster. Fitting more pulses in a unit of time means that the period of the pulses must be shorter. Thus, if we can measure the duration of the pulses, we can determine the speed of the mechanism.

Lets measure the speed of a DC motor that we will use in our next lab, Polou micro metal gearmotor. This motor is connected to the Pololu Wheel Encoder. I did some experiments driving the motor with different duty cycle waveforms and looked at the duration of the pulses coming from the wheel encoder to get the data in the table below. Note, I only looked at channel A; I didn't care about the direction of the wheels rotation.
Duty Cycle Encoder Pulse Width
0x30 31.0 ms
0x60 19.1 ms
0x90 12.8 ms
0xC0 9.7 ms
0xF0 8.0 ms
Let's assume that these encoder pulses are coming into RC2, write a program that outputs the number of timer counts of the pulses.

The first thing that we need to do is to determine the timer prescaler. Since the longest pulse that we intend to measure is 31 ms long, we should use a 1:8 prescler because the its maximum period is 32.8 ms.

The idea that I have for the code is to stick it in an infinite loop so that it measures the pulse durations forever. My code will first look for a positive edge on RC2, record the start time, and then look for a negative edge and record the end time of the pulse.
    int16 start, end;

    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.T1CKPS = 0b11;    // 1:8 prescale
    T1CONbits.TMR1ON = 1;       // Turn on timer 1

    for(;;) {
    	CCP1CONbits.CCP1M = 0b0101;	// Capture on rising edge on RC2
	PIR1bits.CCP1IF = 0;            // CCPR1 register when a falling 
        while (PIR1bits.CCP1IF == 0);   // edge of RC2 is detected
        start = CCPR1;		

    
    	CCP1CONbits.CCP1M = 0b0100;	// Capture on falling edge on RC2
	PIR1bits.CCP1IF = 0;            // CCPR1 register when a falling 
        while (PIR1bits.CCP1IF == 0);   // edge of RC2 is detected
        end = CCPR1;		// 

	// speed = calculateSpeed(end - start);

    } 

Test your understanding

You can find the solutions embedded in the "source code" for this web page by right mouse clicking on this web page and selecting "view source". The solutions are in HTML comments.
  1. Complete the speed calculation for the wheel. That is, given the number of 8:1 prescaled timer counts for a single pulse from a 12 spoke 43mm diameter wheel. Note that there are 12 spokes so there are 12 logic 1 pulses per wheel rotation.
  2. Muzzle Velocity
    You are working on an Electromagnetic railgun and need an accurate method of determining the muzzle velocity. To accomplish this goal you setup a speed trap consisting of a pair of sensors placed 1 meter apart. The projectile, when fired, passes by the first sensor sending a logic 1 pulse to PT0 and then passes by the second sensor a short while later producing a logic 1 pulse on PT1. The railgun is anticipated to have a muzzle velocity of 2,400 m/s. Your tasks are to:
    1. Use a 1:1 prescaler, determine the number of counts between a projectile moving between the two sensors at the anticipated velocity.
    2. Write a code snippet that records the number of timer counts for the projectile to move between the two sensors. Use the capture subsystem.
    3. Write an equation that relates the number of timer counts to the projectile velocity.
  3. RPM measurement
    Most modern car engines use computers to monitor and control almost every major function in an engine. Among the most important is the timing of the spark which ignites the gas-air mixture inside a cylinder. If the spark occurs too early, the explosion inside the cylinders will collide with the upward moving piston causing the engine to "knock". If the spark occurs too late, the expanding gasses from the explosion will not fully impart their energy into the piston causing the engine to hesitate. The timing of the spark is determined in large part by the Hall-effect camshaft position sensor. A small magnet is embedded in the crankshaft that rotates in time with the moving pistons. A Hall-effect sensor placed next to the crankshaft nominally outputs logic 0, buts outputs a brief logic 1 pulse every time the magnet passes by. These pulses are fed into the engine control unit (ECU) which is running a PIC. It's your job to write a program which calculates the RPM for a crankshaft that rotates somewhere between 800 (lowest RPM before the engine stalls) and 10,000 RPMs (when the rev-limiter kicks). Your PIC is attached to the camshaft position sensor through RC2. Your tasks are to:
    1. Determine the clock speed and prescaler necessary to measure engine RPMs.
    2. Write a code snippet to measure the number of timer counts required for the camshaft to make a single rotation.
    3. Write an equation relating timer counts to RPMs.