I am building a quad-copter, the problem is of stability and for better stability lesser sampling time is required. For lesser sampling time I need to have faster loop() function. But the Pulsein() command takes very large time which in turn expands the sampling time. Is there any method to read the rc channels in background and read them from an integer.

  • Why not have a look at some of the open-source ATMEGA-based quadcopter firmwares, at least to examine for ideas? I don't know if you will find some that are based on the Arduino libraries, but you should find some that will run on the hardware. That said, fundamentally you cannot measure pulses faster than they occur, which is typically a repetition rate of only around 50 times a second. You can write code which accomplishes other things while waiting for the pulses, but you can't speed them up unless you change the receiver, for example directly talking to the 2.4 GHz chip. Oct 11 '15 at 21:25

The keyword you are looking for here is interrupt. What is a pulse but a signal that goes from low to high followed by going from high to low, with some period of time between them?

Instead of sitting there waiting for the pulse to arrive then measuring how long it is, which is essentially what pulseIn() does, you need to attach the signal to an interrupt pin. Then you write an interrupt routine that triggers when the signal changes from one level to another which looks to see what the level actually is.

If the signal has risen from low to high then you record the time it happened. If the signal has fallen from high to low then you look what the time is, and subtract the time you remembered from when the signal rose. That difference is then the width of the pulse, which you can store in an integer to read in your main loop.

If you have a number of signals you want to monitor you might want to look into using the pin change interrupt which allows you to use any pin as an interrupt source.

  • While you can use interrupts to allow potentially accomplishing other things while waiting for the pulses, they won't permit an input-based control loop to run at a higher rate than the inputs themselves arrive at - for a legacy PWM output, that is typically in the neighborhood of 50 Hz repetition rate. Of course it is possible to run the on-board stabilization algorithm at some multiple of the radio data rate, if desired. Oct 11 '15 at 23:20
  • @ChrisStratton I think you are misinterpreting the question. When he talks about "sampling" I am assuming (and I think quite rightly) that he is talking about sampling something else - accelerometers maybe - since he says waiting for the pulses slows down the sampling that he is doing, and it's the sampling he needs to do faster, not the reading of the pulses.
    – Majenko
    Oct 11 '15 at 23:22
  • I agree with Majenko here. pulseIn blocks, which is what I gather he is trying to avoid. Using interrupts would help in this situation.
    – Nick Gammon
    Oct 12 '15 at 6:54
  • yes i am using accelerometer, for faster data reading. can i use interupts for all of 6 channels in RC reciever
    – Bilal Ayub
    Oct 12 '15 at 8:16
  • @Majenko I have read your answer and got information from it. but Now the problem i am asking in other quesstion is how to read multiple channels with one interupt. thats the headache now,
    – Bilal Ayub
    Oct 12 '15 at 16:10

You may find my answer to another question – Read RC receiver channels using Interrupt instead of PulseIn – useful. It includes the sketch shown below, which is intended for background timing of four RC channels attached to pins A0-A3. See the other answer for further comments about the code, example output, etc.

/*  rcTiming.ino -- JW, 30 November 2015 -- 
 * Uses pin-change interrupts on A0-A4 to time RC pulses
 * Ref: https://arduino.stackexchange.com/questions/18183/read-rc-receiver-channels-using-interrupt-instead-of-pulsein
#include <Streaming.h>
static   byte rcOld;        // Prev. states of inputs
volatile unsigned long rcRises[4]; // times of prev. rising edges
volatile unsigned long rcTimes[4]; // recent pulse lengths
volatile unsigned int  rcChange=0; // Change-counter

// Be sure to call setup_rcTiming() from setup()
void setup_rcTiming() {
  rcOld = 0;
  pinMode(A0, INPUT);  // pin 14, A0, PC0, for pin-change interrupt
  pinMode(A1, INPUT);  // pin 15, A1, PC1, for pin-change interrupt
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);
  PCMSK1 |= 0x0F;       // Four-bit mask for four channels
  PCIFR  |= 0x02;       // clear pin-change interrupts if any
  PCICR  |= 0x02;       // enable pin-change interrupts
// Define the service routine for PCI vector 1
ISR(PCINT1_vect) {
  byte rcNew = PINC & 15;   // Get low 4 bits, A0-A3
  byte changes = rcNew^rcOld;   // Notice changed bits
  byte channel = 0;
  unsigned long now = micros(); // micros() is ok in int routine
  while (changes) {
    if ((changes & 1)) {  // Did current channel change?
      if ((rcNew & (1<<channel))) { // Check rising edge
        rcRises[channel] = now;     // Is rising edge
      } else {              // Is falling edge
        rcTimes[channel] = now-rcRises[channel];
    changes >>= 1;      // shift out the done bit
  rcOld = rcNew;        // Save new state

void setup() {
  Serial.println("Starting RC Timing Test");

void loop() {
  unsigned long rcT[4]; // copy of recent pulse lengths
  unsigned int rcN;
  if (rcChange) {

    // Data is subject to races if interrupted, so off interrupts
    cli();          // Disable interrupts
    rcN = rcChange;
    rcChange = 0;       // Zero the change counter
    rcT[0] = rcTimes[0];
    rcT[1] = rcTimes[1];
    rcT[2] = rcTimes[2];
    rcT[3] = rcTimes[3];
    sei();          // reenable interrupts

    Serial << "t=" << millis() << " " << rcT[0] << " " << rcT[1]
       << " " << rcT[2] << " " << rcT[3] << " " << rcN << endl;
  sei();            // reenable interrupts

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.