incap_32bit_switch_pulse_measure.c - Uses IC1,IC2 in cascade mode to measure pulse widthΒΆ

Measures the pulse width of pushbutton switching using IC1,IC2 in cascade mode. Timer 2 is used as the clock source, and pulse width is assume to not exceed the 32-bit range of cascade mode. This example only runs on dsPIC33E/PIC24E families. This example assumes a debounced switch. To configure this example to run with an external 8 MHz crystal for for a FCY=40MHz, define the C preprocessor macro: CLOCK_CONFIG=PRIPLL_8MHzCrystal_40MHzFCY and have an external crysal + 2 capacitors on the OSC1/OSC2 pins. Typical crystal accuracy for through hole is +/-20 pmm, so for a 100000 us pulse width measurement this is +/- 2 us.

 
#include "pic24_all.h"
#include <stdio.h>

#if (! (defined(__dsPIC33E__) || defined(__PIC24E__)))
# warning "This example only works with the dsPIC33E/PIC24E families"
int main(void) {
  return 0;
}
#else
typedef enum  {
  STATE_WAIT_FOR_FALL_EDGE = 0,
  STATE_WAIT_FOR_RISE_EDGE,
} ICSTATE;

ICSTATE e_isrICState = STATE_WAIT_FOR_FALL_EDGE;
volatile uint8_t u8_captureFlag = 0;
volatile union32 u32_lastCapture;
volatile union32 u32_thisCapture;
volatile uint32_t u32_pulseWidth;

void _ISRFAST _IC1Interrupt() {
  _IC1IF = 0;
  u32_thisCapture.u16.ls16 = IC1BUF;  //read LSW
  u32_thisCapture.u16.ms16 = IC2BUF;  //read MSW
  switch (e_isrICState) {
    case STATE_WAIT_FOR_FALL_EDGE:
      if (u8_captureFlag == 0) {
        u32_lastCapture = u32_thisCapture;
        e_isrICState = STATE_WAIT_FOR_RISE_EDGE;
      }
      break;
    case STATE_WAIT_FOR_RISE_EDGE:
      u32_pulseWidth = u32_thisCapture.u32 - u32_lastCapture.u32;  //get delta ticks
      u32_pulseWidth = ticksToUs(u32_pulseWidth,getTimerPrescale(T2CONbits)); //convert to microseconds
      u8_captureFlag = 1;
      e_isrICState = STATE_WAIT_FOR_FALL_EDGE;
      break;
    default:
      e_isrICState = STATE_WAIT_FOR_FALL_EDGE;
  }
}

/// Switch1 configuration
inline void CONFIG_SW1()  {
  CONFIG_RB13_AS_DIG_INPUT();     //use RB13 for switch input
  ENABLE_RB13_PULLUP();           //enable the pull-up
  DELAY_US(1);            //delay for pull-up
}



void configInputCapture(void) {
  CONFIG_IC1_TO_RP(RB13_RP);      //map IC1 to RB13
  CONFIG_IC2_TO_RP(RB13_RP);      //map IC2 to RB13
  //first, config the MSW (EVEN) module IC2 - configuration order matters!
  IC2CON1 = IC_TIMER2_SRC |     //Timer2 source
            IC_EVERY_EDGE;      //Capture every edge
  //cascade on, sync mode, no timer sync, just use clock source
  IC2CON2 = IC_IC32_ON| IC_SYNC_MODE | IC_SYNCSEL_NOSYNC;
  //now config LSW (ODD) module IC1
  IC1CON1 = IC_TIMER2_SRC |     //Timer2 source
            IC_INT_1CAPTURE |   //Interrupt every capture
            IC_EVERY_EDGE;      //Capture every edge
  //cascade on, sync mode, no timer sync, just use clock source
  IC1CON2 = IC_IC32_ON| IC_SYNC_MODE | IC_SYNCSEL_NOSYNC;
  _IC1IF = 0;
  _IC1IP = 2;   //higher than Timer2 so that Timer2 does not interrupt IC1
  _IC1IE = 1;   //enable
}

void  configTimer2(void) {
  T2CON = T2_OFF | T2_IDLE_CON | T2_GATE_OFF
          | T2_32BIT_MODE_OFF
          | T2_SOURCE_INT
          | T2_PS_1_8 ;  //1 tick = 0.2 us at FCY=40 MHz
  PR2 = 0xFFFF;                    //maximum period
  TMR2  = 0;                       //clear timer2 value
  _T2IP = 0;                       //interrupt disabled
  _T2IE = 0;                       //interrupt disabled
  T2CONbits.TON = 1;               //turn on the timer
}

int main (void) {
  configBasic(HELLO_MSG);
  CONFIG_SW1();    //use RB13
  configInputCapture();
  configTimer2();

  while (1) {
    outString("Press button...");
    while (!u8_captureFlag) doHeartbeat();
    printf(" %ld us\n",u32_pulseWidth);
    u8_captureFlag = 0;
  }
}
#endif