Tuesday, 6 March 2018

Multi Channel Receiver Signals using Pin Change Interrupts - Reading Four Channels Simultaneously

The main Logic is :
1.Calculate PWM Starting Value during Raising Edge
 2.When Falling Edge Detected Calculate Width

/*
   Author : Kunchala Anil
   Email : anilkunchlaece@gmail.com
   Date : 6 Mar 2018
   Pin Change Interrupts - Single Rx Channel i.e Single PWM Wave
  PCMSKx - Pin Change Mask Register
  PCMSK0 - portB (D8-D13) (PCINT0  - PCINT6)
  PCMSK1 - portC (A0-A5)  (PCINT8  - PCINT14)
  PCMSK2 - portD (D0-D7)  (PCINT16 - PCINT23)
  PCICR -  Pin Change Interrupt Control Register
    PCIE0 - Pin Change Interrupt Enable 0 - Port B (D8-D13)
    PCIE1 - Pin Change Interrupt Enable 1 - Port C (A0-A5)
    PCIE2 - Pin Change Interrupt Enable 2 - Port D (D0-D7)
*/

/*#############################
  Rx Connections
  Ch1 = D8 PCINT0
  Ch2 = D9 PCINT1
  Ch3 = D10 PCINT2
  Ch4 = D11 PCINT3
*/
#define DEBUG // comment it out to disable the debug mode

volatile boolean recvPCInt = false; //to know interrupt status
volatile int portValue;

//used to store the pwm duration
volatile unsigned long pwmDuration[4];
volatile unsigned long pwmStart[4];
unsigned long pwmEnd[4];

//pinDeclaration for Rx
const byte rxCh[] = {8, 9, 10, 11};
const byte noOfChannels = sizeof(rxCh);

//portStatus
volatile int prevPortState[] = {0, 0, 0, 0};
volatile int presentPortState[4];

//Interrupt Service Routine will fire when for PinChange in PortB
ISR(PCINT0_vect) {
  recvPCInt = true;
  for (int ch = 0; ch < noOfChannels ; ch++) {
    presentPortState[ch] = digitalRead(rxCh[ch]);
  }//end of for loop

  for (int c = 0; c < noOfChannels ; c++) {
    if (prevPortState[c] == 0 & presentPortState[c] == 1) {
      //if previous state is 0 and present state is 1 (Raising Edge) then take the time stamp
      pwmStart[c] = micros();
      prevPortState[c] = 1; //update the prevPort State
    } else if (prevPortState[c] == 1 & presentPortState[c] == 0) {
      //if previous state is 1 and present state is 0 (Falling Edge) then calculate the width based on the change
      pwmDuration[c] = micros() - pwmStart[c];
      prevPortState[c] = 0; //update Present PortState
    }
  }//end of for loop
  //portValue = PINB & 0x0f;//we are only intrested in first four bits
}

void setup() {
  cli(); //Clear all interrupts
  PCICR |= 1 << PCIE0; //Enable port B Registers i.e D8-D13
  PCMSK0 |= (1 << PCINT0) | (1 << PCINT1) | (1 << PCINT2) | (1 << PCINT3);// Pin8,9,10,11
  sei(); //enable all interrupts

#ifdef DEBUG
  Serial.begin(9600);
  Serial.println("DEBUG mode Enabled");
#endif

  for (int ch = 0 ; ch < noOfChannels; ch++) {
    pinMode(rxCh[ch], INPUT_PULLUP); //make pin input with pullup enabled
  }//end of for loop

}//end of setup

void checkForRxPulseWidths() {
  for (int i = 0; i < noOfChannels ; i++ ) {
#ifdef DEBUG
    Serial.print("ch => ");
    Serial.print(i);
    Serial.print(" pulseWidth ");
    Serial.println(pwmDuration[i]);
#endif
  }
}

void loop() {
  if (recvPCInt == true) {
    checkForRxPulseWidths();
    recvPCInt = false;
  }//end of if
}//end of loop



No comments:

Post a Comment