Combining external & timer interrupts

Hi all!

I am fairly new to the principle of timer interrupts, maybe someone can help me out! I am trying to program an Arduino that can read a PPM signal, check for some conditions, adapt the signal if necessary and generate a new PPM signal. So far I've been able to read the signal using an external interrupt (counting the channel widths using timer/counter1) and generating a signal using a timer interrupt in CTC mode, but in separate programs.

I am wondering if it is possible to combine these two programs, meaning that the reading interrupt is triggered on pin input CHANGE, while at the same time keep another timer counting for generating the signal. I tried using two timer/counter1 and timer/counter2 simultaneously but so far no good results.

I spend last day searching but can't find any similar projects, so any help would be greatly appreciated!

Please please read the advice about how to post to this forum....

Sorry, and thanks for the tip! If you referring to code, below you can find the separate programs I use.

For generating PPM signal:

// declare constants
const int PPM_OUT = 5;         // ppm out pin number
const int NUM_CHAN = 8;         // number of channels
const int PPM_PULSE = 500;      // set pulse length to 500 us
const int PPM_FRAME = 22500;    // set frame length

// declare variables
int ppm_out[NUM_CHAN] = {1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500};

// setup code running once
void setup() {  
  
  // initializing timer 1
  cli();                        // disable global interrupts
  TCCR1A = 0;                   // set register to 0 (timer/counter control register)
  TCCR1B = 0;                   // set register to 0  
  OCR1A = 0;                    // compare match register
  TCCR1B |= (1 << WGM12);       // enable CTC mode 
  TCCR1B |= (1 << CS11);        // choose clock bits for prescaler 
//  TCCR1B |= (1 << CS10);        // choose clock bits for prescaler  (CS10 & CS12 for 1024, CS11 for 8, seet table AVR)
  TIMSK1 |= (1 << OCIE1A);      // enable timer compare interrupt timer/counter interrupt mask register
  sei();                        // enable global interrupts

  pinMode(PPM_OUT, OUTPUT);     // set ppm output pin  
  Serial.begin(9600);           // initialize serial communication
   
}

// main code for running repeatedly
void loop() {
}

//delay(60);
  
  
// interrupt service routine
ISR(TIMER1_COMPA_vect) {
  static boolean state = true;

  TCNT1 = 0;

  if(state) {                     // check if pulse
    digitalWrite(PPM_OUT, HIGH);  // set output high
    OCR1A = PPM_PULSE * 2;        // set compare time 
    state = false;                // change state
  }
  else {                          
    static byte chan_cur;         // current channel variable
    static unsigned int total;    // remaining frame length
    state = true;                 // state
    digitalWrite(PPM_OUT, LOW);   // start low     
    
    if (chan_cur >= NUM_CHAN) {          // check if new burst started
      chan_cur = 0;                      // reset current channel number
      total = total + PPM_PULSE;         // add pulse to total time
      OCR1A = (PPM_FRAME - total) * 2;   // set compare match register to required synchro blank time
      total = 0;                         // reset total time
    }
    else {                                          // write pulse width
      OCR1A = (ppm_out[chan_cur] - PPM_PULSE) * 2;  // set compare match register to channel width
      total = total + ppm_out[chan_cur];            // add to total time
      chan_cur++;                                   // increment channel
    }    
  }
}

For reading PPM:

// declare constants
const int PPM_IN = 3;  // ppm pin number (2 or 3 for interrupts)
const int NUM_CHAN = 8;  // number of channels

// declare variables
int channel[NUM_CHAN];  // array to store interval lengths
int pulse;    // array to store pulse lengths

// setup code running once
void setup() {  
  Serial.begin(9600);  // open serial communication
  pinMode(PPM_IN, INPUT);  // set input pin  
  attachInterrupt(PPM_IN-2, read_ppm, CHANGE);
  cli();
  TCCR1A = 0;  //reset timer1
  TCCR1B = 0;
  TCCR1B |= (1 << CS11);  //set timer1 to increment every 0,5 us
  sei();
}

// main code for running repeatedly
void loop() {
  }    
  Serial.println("");
  //  delay(60);
}
void read_ppm() {
  //  static unsigned int pulse;
  static unsigned long counter;
  static byte k;

  counter = TCNT1;
  TCNT1 = 0;

//  while(k<NUM_CHAN){

    if(counter<1020) {            // pulse
      pulse = counter;
    }
    else if (counter > 3820) {    // synchro
      k = 0;
    }
    else {                        // 
      channel[k] = (counter + pulse)/2;
        k++;
  }
}

Timers: Gammon Forum : Electronics : Microprocessors : Timers and counters

Interrupts: Gammon Forum : Electronics : Microprocessors : Interrupts

Thanks, this is really helpful. I've been able to combine timer/counter1 and timer/counter2 in one program and it seems to be working correctly. I am using the Arduino Duemilanove which only has three timers. Now I need an extra timer to build-in an ultrasonic sensor (NewPing library uses timer/counter2), but from what I understood it is not advisable to mess with timer/counter0, is that correct? Thanks again for the articles, they were really clearing things up for me!

Without seeing your current code it is hard to comment.

You can use Timer 0 if you don't mind losing access to delay(), millis(), micros() etc.