1.3.5 IOC Without a Timer

Table 1-9. IOC without Timer Code Calculations
Modules Limit High Resolution
IOC 4.194s 2.75 μs

This method is similar to the interrupt-on-change with a timer, with the exception that it uses the system clock to count, and not a timer.

OVERVIEW

This provides a “cheap” method in determining the width of a pulse. The user must wait for a rising edge to be detected and then increment a register until a second rising interrupt is detected. This measures the period. A rising edge, and then subsequent falling edge measurement, will be saved and then subtracted from the period to get the pulse width.

SETUP

Steps to measure the period:

  1. Configure one of the IOC pins to interrupt on rising edge (IOCBP)
  2. Set the pin as a digital input
  3. Set up any variable so that it will count ‘T’ (Figure   2) without overflowing
  4. Start incrementing the temporary variable (period_count)
  5. When the IOC flag is set, clear it and save the count variable into a temporary variable (temp1)
  6. Continue incrementing count variable
  7. When the interrupt flag is set again, clear it and save the count variable into another temporary variable (temp2)
  8. Period is now:
    Period = temp2 - temp1

IOC without Timer Period Setup and Operation Code

Configure IOC Pins (Step 1)
    IOCBP = 0x20;                    // Sets Interrupt on rising edge of RB5

Input Pin Setup (Step 2)
    TRISBbits.TRISB5 = HIGH;         // Set RB5 as a digital input

uint24_t period_count = 0;    // Set up a variable to count the period (Step 3)
       
while(!IOCBFbits.IOCBF5){            // Wait for IOC flag to set (Step 4)
    period_count = period_count + 1; // Increment period_count (Step 4)
}                             
IOCBFbits.IOCBF5 = 0;                // Clear IOC flag (Step 5)
temp1 = period_count;     // Save period_count value into temp1 (Step 5)
while(!IOCBFbits.IOCBF5){            // Wait for IOC flag to set (Step 6)
    period_count = period_count + 1; // Increment period_count (Step 6)
}
IOCBFbits.IOCBF5 = 0;                // Clear IOC flag (Step 7)
temp2 = period_count;     // Save period_count value into temp2 (Step 7)

Steps to measure the pulse:

  1. Configure one of the IOC pins to interrupt on rising edge (IOCBP)
  2. Set the pin as a digital input
  3. Set up any variable so that it will count ‘W’ (Figure   2) without overflowing
  4. Start incrementing the temporary variable (pulse_count)
  5. When the IOC flag is set, clear it and save the timer into a temporary variable (temp1)
  6. Configure the pin to interrupt on falling edge (IOCBN)
  7. When the interrupt flag is set again, clear it and save the count variable into another temporary variable (temp2)
  8. Pulse width is now:
    MeasuredPulse = temp2 - temp1;
    while(MeasuredPulse>Period) MeasuredPulse -= Period;

IOC without Timer Pulse Setup and Operation Code


Configure IOC Pins (Step 1)
    IOCBP = 0x20;                    // Sets Interrupt on rising edge of RB5

Input Pin Setup (Step 2)
    TRISBbits.TRISB5 = HIGH;         // Set RB5 as a digital input

uint24_t pulse_count = 0;     // Set up a variable to count the pulse (Step 3)
       
while(!IOCBFbits.IOCBF5){            // Wait for IOC flag to set (Step 4)
    pulse_count = pulse_count + 1;   // Increment pulse_count (Step 4)
}                             
IOCBFbits.IOCBF5 = 0;                // Clear IOC flag (Step 5)
temp1 = pulse_count;     // Save pulse_count value into temp1 (Step 5)

Configure IOC Pins (Step 6)
    IOCBP = 0x00;                    // clear Interrupt on rising edge of RB5
    IOCBN = 0x20;                    // Set Interrupt on falling edge of RB5

while(!IOCBFbits.IOCBF5){            // Wait for IOC flag to set (Step 6)
    pulse_count = pulse_count + 1;   // Increment pulse_count (Step 6)
}
IOCBFbits.IOCBF5 = 0;                // Clear IOC flag (Step 7)
temp2 = period_count;     // Save period_count value into temp2 (Step 7)

LIMITATIONS

Since this implementation is in C, there is a greater number of instructions needed compared to an assembly routine. The snippet in Disassembly of Two Lines of C Code is what is required to check if a pin is high and increment a variable if it is. Notice the amount of instructions required for just a couple of statements.

Disassembly of Two Lines of C Code


33:     while(!IOCBFbits.IOCBF5){     
        // Wait for the the RB5 IOC Flag to be triggered       
  055B     2D66     GOTO 0x566
  0566     017D     MOVLB 0x3D
  0567     1E9D     BTFSS IOCBF, 0x5 
  0568     2D6A     GOTO 0x56A
  0569     2D6B     GOTO 0x56B
  056A     2D5C     GOTO 0x55C
34:     pulse_count = pulse_count + 1;  
        // While the RB5 IOC Flag is low, increment the pulse_count
  055C     3001     MOVLW 0x1
  055D     0140     MOVLB 0x0
  055E     074F     ADDWF pulse_count, W
  055F     00CF     MOVWF pulse_count
  0560     3000     MOVLW 0x0 
  0561     3D50     ADDWFC 0x50, W
  0562     00D0     MOVWF 0x50
  0563     3000     MOVLW 0x0 
  0564     3D51     ADDWFC 0x51, W
  0565     00D1     MOVWF 0x51
From this, it can be inferred that the number of instructions to complete just two lines in C can be cumbersome. The approximate delay to increment ‘count’ on each instruction cycle is 20 instructions clocks, or rather 5 μs, if FOSC == 16MHz. If the pulse occurred and the ‘count’ register contains a value of 12, then the pulse width is then:
Pulse Width = count*delay*InstructionTimer
Pulse Width = 12*20* 1/ (16MHz/4) = 60μs