nur so als idee: man hat ja zwischen den servopulsen mengen an zeit, in denen kann man vorberechnen:

Code:
struct {
  uint8_t portb, portc, portd;
  uint16_t next_intr;
} timings[18];
also für jeden interrupt-zeitpunkt bereits vorberechnet haben, welche bitmuster auf welchen ports ausgegeben gehören, und welcher wert als nächster in den timer gehört.

damit läßt sich der code in der ISR ziemlich reduzieren:

Code:
ISR(TIMER1_COMP_vect) {
  PORTB = timings[cur_timer].portb;
  PORTC = timings[cur_timer].portc;
  PORTD = timings[cur_timer].portd;
  OCR1 = timings[cur_timer++].next_intr;
}
da da keine conditionals drin sind, weiß man genau, wieviele zyklen die ISR braucht, und kann beim aufbauen der timer-tabelle berücksichtigen, ob genug zeitabstand zwischen 2 werten ist oder man die besser zusammenfasst.