rot_enc_trace.c - Demonstrates use of an ISR trace buffer for capturing the states of a rotary encoder.ΒΆ

#include "pic24_all.h"

#define TMAX 16
volatile uint8_t au8_tbuff[TMAX];
volatile uint8_t u8_tcnt = 0;
volatile uint8_t u8_startTrace = 0;

//clips cntr between 0 and max
uint8_t processRotaryData(volatile uint8_t u8_curr, volatile uint8_t u8_last,
                          volatile uint8_t *cntr, volatile uint8_t max) {
  int8_t delta = 0;
  if (u8_startTrace && (u8_tcnt != TMAX)) {
    au8_tbuff[u8_tcnt] = u8_curr;
    u8_tcnt++;
  }
  switch (u8_curr) {
    case 0:
      if (u8_last == 1) delta = 1;
      else if (u8_last == 2) delta = -1;
      break;
    case 1:
      if (u8_last == 3) delta = 1;
      else if (u8_last == 0) delta = -1;
      break;
    case 2:
      if (u8_last == 0) delta = 1;
      else if (u8_last == 3) delta = -1;
      break;
    case 3:
      if (u8_last == 2) delta = 1;
      else if (u8_last == 1) delta = -1;
      break;
    default:
      break;
  }
  if (delta == 0) return(1); //error, illegal state
  //clip and update.
  if (( *cntr == 0 && delta == -1)
      || (*cntr == max && delta == 1)) return(0); //at limit
  (*cntr) = (*cntr) + delta;
  return 0;
}

#define ROT1_RAW _RB13
#define ROT0_RAW _RB12
#define GET_ROT_STATE() ((ROT1_RAW << 1) | ROT0_RAW)

/// ROT1 configuration
inline void CONFIG_ROTENC()  {
  CONFIG_RB13_AS_DIG_INPUT();
  ENABLE_RB13_PULLUP();           //enable the pullup
  CONFIG_RB12_AS_DIG_INPUT();
  ENABLE_RB12_PULLUP();           //enable the pullup
  DELAY_US(1);                   //wait for pullups to settle
}

#define ROT_MAX  32            //arbitrary limit

volatile uint8_t u8_valueROT = 0;
volatile uint8_t u8_lastvalueROT = 0;
volatile uint8_t u8_errROT = 0;
volatile uint8_t u8_cntrROT = 0;

//Interrupt Service Routine for Timer3
void _ISRFAST _T3Interrupt (void) {
  u8_valueROT = GET_ROT_STATE(); //a value between 0 & 3
  if (u8_lastvalueROT != u8_valueROT) {
    u8_errROT = processRotaryData(u8_valueROT, u8_lastvalueROT, &u8_cntrROT, ROT_MAX);
    u8_lastvalueROT = u8_valueROT;
  }
  _T3IF = 0;                 //clear the timer interrupt bit
}


#define ISR_PERIOD     15                // in ms
void  configTimer3(void) {
  //ensure that Timer2,3 configured as separate timers.
  T2CONbits.T32 = 0;     // 32-bit mode off
  //T3CON set like this for documentation purposes.
  //could be replaced by T3CON = 0x0020
  T3CON = T3_OFF | T3_IDLE_CON | T3_GATE_OFF
          | T3_SOURCE_INT
          | T3_PS_1_64 ;  //results in T3CON= 0x0020
  PR3 = msToU16Ticks (ISR_PERIOD, getTimerPrescale(T3CONbits)) - 1;
  TMR3  = 0;                       //clear timer3 value
  _T3IF = 0;                       //clear interrupt flag
  _T3IP = 1;                       //choose a priority
  _T3IE = 1;                       //enable the interrupt
  T3CONbits.TON = 1;               //turn on the timer
}

int main (void) {
  uint8_t u8_i;
  configBasic(HELLO_MSG);
  /** PIO config ******/
  CONFIG_ROTENC();
  DELAY_US(1);       //wait for pullups to settle
  u8_valueROT = GET_ROT_STATE();
  u8_lastvalueROT = u8_valueROT;
  /** Configure the Timer */
  configTimer3();
  while (1) {
    u8_startTrace = 1;
    if (u8_tcnt == TMAX) {
      u8_startTrace = 0;
      for (u8_i = 0; u8_i < TMAX; u8_i++) {
        outUint8(au8_tbuff[u8_i]);
        outString("\n");
      }
      u8_tcnt = 0;
    }
    doHeartbeat();     //ensure that we are alive
  } // end while (1)
}