Multiple PWM signal reading on Arduino Mega 2560

Dear Sirs,

I’m new in the Arduino world, and I would need, for data acquisition, to read PWM data coming from a R/C receiver (very classical problem) on my Arduino MEGA 2560.

After few hours on Google, the best code I found to do it is:

I tried it, and it run perfectly…!!

However, I would need to read 4 different channels, so I tried to modify the code (see just bellow) to be able to read another channel in the same time.
The code read PIN2 at its origin, and I tried to read PIN3 in the same time.

But this code is still able to read PWM signals on PIN2, but not in PIN3.

Would someone have any idea of the problem??

Thanks in advance for your help,

Best Regards,

Stéphane

// Reading servos with interrupts
// For an Arduino Mega
// Scott Harris January 2010
//
// This work is licensed under the Creative Commons Attribution-Share Alike 3.0 United States License.
// To view a copy of this license, visit Creative Commons — Attribution-ShareAlike 3.0 United States — CC BY-SA 3.0 US

volatile long servo0; // servo value
volatile long count0; // temporary variable for servo1

volatile long servo1; // servo value
volatile long count1; // temporary variable for servo1

// PIN 2
// #define int0 (PINE & 0b00010000) // Faster than digitalRead
#define int0 (PINE & 0x10)

// PIN 3
// #define int0 (PINE & 0b00100000)
#define int1 (PINE & 0x20)

void handleInterrupt()
{
if(int0)
count0=micros(); // we got a positive edge
else
servo0=micros()-count0; // Negative edge: get pulsewidth

if(int1)
count1=micros(); // we got a positive edge
else
servo1=micros()-count1; // Negative edge: get pulsewidth
}

void setup()
{
Serial.begin(9600);

pinMode(2,INPUT);
pinMode(3,INPUT);

attachInterrupt(0,handleInterrupt,CHANGE); // Catch up and down
}

void loop()
{
delay(10);
Serial.println(servo0,DEC); // Pulsewidth in microseconds
Serial.println(servo1,DEC); // Pulsewidth in microseconds
}

For pin D3 you need to attachInterrupt (1, blah blah) not zero.
eg.

attachInterrupt(0, handleInterrupt_D2, CHANGE); // Catch up and down   
attachInterrupt(1, handleInterrupt_D3, CHANGE); // Catch up and down

Hi,
Your missing several important points most of which are covered here -

As your using a Mega, you do not need to use the pinchangeint library as you have enough external interrupts already, but you still need to pay attention to shared variable access, could benefit from using bit flags to signal new values are available rather than outputting data whether it has changed or not etc etc.

I am planning a new post showing finished code and standalone hardware that runs in my RC Car based on this code with some additionals to any errors that might occur.

Duane B

rcarduino.blogspot.com

@DuaneB:

attachInterrupt is for external interrupts, not pin change interrupts.

Hi,
Yes, I know, I was referring to the post I linked where I am using an UNO which has only two external interrupts and so I am using the pinchangeint library to get acccess to additional interrupts.

Also from my blog - RCArduino: Need More Interrupts To Read More RC Channels ?

Rakma74,
Your Mega has more external interrupts than my UNO so you can use attachInterrupt and do not need to use the pcintchange library which provides those of use using UNO's with access to upto 20 additional interrupts. The principles and code are the same for both boards so I suggest you do read the post I linked originally and again below, you can imply drop the PCintChange:: before attachInterrupt, everything else remains the same.

Duane B.

rcarduino.blogspot.com

Dear Sirs,

Thank you so much for your answers, you saved my life (^_^)!
Now, I can read 2 R/C channels in the same time (I just have to extend to 4 r/C channels, and I’ll be happy!).

In fact, I implemented the solution of Nick Gammon (see code bellow).
Also, thank you DuaneB, I’ll try your approach to improve my beginning knowledge of the board!!

Best Regards,

Stéphane

// Reading servos with interrupts
// For an Arduino Mega
// Scott Harris January 2010
//
// This work is licensed under the Creative Commons Attribution-Share Alike 3.0 United States License.
// To view a copy of this license, visit Creative Commons — Attribution-ShareAlike 3.0 United States — CC BY-SA 3.0 US

volatile long servo0; // servo value
volatile long count0; // temporary variable for servo1

volatile long servo1; // servo value
volatile long count1; // temporary variable for servo1

// PIN 2
// #define int0 (PINE & 0b00010000) // Faster than digitalRead
#define int0 (PINE & 0x10)

// PIN 3
// #define int0 (PINE & 0b00100000)
#define int1 (PINE & 0x20)

void handleInterrupt_P2()
{
if(int0)
count0=micros(); // we got a positive edge
else
servo0=micros()-count0; // Negative edge: get pulsewidth
}

void handleInterrupt_P3()
{
if(int1)
count1=micros(); // we got a positive edge
else
servo1=micros()-count1; // Negative edge: get pulsewidth
}

void setup()
{
Serial.begin(9600);

pinMode(2,INPUT);
pinMode(3,INPUT);

attachInterrupt(0,handleInterrupt_P2,CHANGE); // Catch up and down
attachInterrupt(1,handleInterrupt_P3,CHANGE); // Catch up and down
}

void loop()
{
delay(10);
// Serial.println(servo0,DEC); // Pulsewidth in microseconds
Serial.println(servo1,DEC); // Pulsewidth in microseconds
}

Hi,

Do please read the link, this code below is a car crash waiting to happen as is the code you copied from the post you linked -

void loop() 
 { 
  delay(10); 
  Serial.println(servo0,DEC); // Pulsewidth in microseconds
  Serial.println(servo1,DEC); // Pulsewidth in microseconds 
 }

When you use servo0 and servo1 in a real world application they will be all over the place.

I use my code in 40km/h RC Race car which is why I protect my shared variable access.

Duane B

rcarduino.blogspot.com

Hello !!

This is me again, a little bit sad...
I tried to extend to 4 PWM channels, but it does not work for the third and forth channel...
Would you have any idea ?

Thanks in advance and Best Regards,

Stéphane

 // Reading servos with interrupts  
 // For an Arduino Mega  
 // Scott Harris January 2010  
 //  
 // This work is licensed under the Creative Commons Attribution-Share Alike 3.0 United States License.   
 // To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/us/   

 volatile long servo0; // servo value  
 volatile long count0; // temporary variable for servo0  

 volatile long servo1; // servo value  
 volatile long count1; // temporary variable for servo1

 volatile long servo2; // servo value  
 volatile long count2; // temporary variable for servo2  

 volatile long servo3; // servo value  
 volatile long count3; // temporary variable for servo3
 
 // PIN 2   
 #define int0 (PINE & 0x10)

 // PIN 3
 #define int1 (PINE & 0x20)

 // PIN 18   
 #define int2 (PIND & 0b00001000)

 // PIN 19
 #define int3 (PIND & 0b00000100)

 void handleInterrupt_P2()  
 {  
  if(int0)  
    count0=micros(); // we got a positive edge  
  else  
   servo0=micros()-count0; // Negative edge: get pulsewidth  
 }
 
 void handleInterrupt_P3()  
 {  
  if(int1)  
    count1=micros(); // we got a positive edge  
  else  
   servo1=micros()-count1; // Negative edge: get pulsewidth  
 }  

 void handleInterrupt_P18()  
 {  
  if(int2)  
    count2=micros(); // we got a positive edge  
  else  
   servo2=micros()-count2; // Negative edge: get pulsewidth  
 } 
 
  void handleInterrupt_P19()  
 {  
  if(int3)  
    count3=micros(); // we got a positive edge  
  else  
   servo3=micros()-count3; // Negative edge: get pulsewidth  
 } 
 
 void setup()  
 {  
  Serial.begin(9600);  
  
  pinMode(2,INPUT);  
  pinMode(3,INPUT);    
  pinMode(18,INPUT); 
  pinMode(19,INPUT); 
  
  attachInterrupt(0,handleInterrupt_P2,CHANGE); // Catch up and down   
  attachInterrupt(1,handleInterrupt_P3,CHANGE); // Catch up and down   
  attachInterrupt(2,handleInterrupt_P18,CHANGE); // Catch up and down   
  attachInterrupt(3,handleInterrupt_P19,CHANGE); // Catch up and down   

 }  

 void loop()  
 {  
  delay(10);  
  // Serial.println(servo0,DEC); // Pulsewidth in microseconds
  // Serial.println(servo1,DEC); // Pulsewidth in microseconds  
  Serial.println(servo2,DEC); // Pulsewidth in microseconds  
  // Serial.println(servo3,DEC); // Pulsewidth in microseconds  
 }

@ DuaneB

Surely, I read you link !!
Just that the code seems a little bit more complicate, and since I only got my Arduino board yesterday, I'm really a newcomer !!
I tried to compile it, where can I get the library which is missing ?

Best Regards,

Stéphane

Hi,

It's the pinchangeint library, you don't need it on a mega, so remove the include statement and change PCintPort:: before each of the attachInterrupts

You will also need to change the pin numbers, look for the comments 'assign your channel pins' and 'assign your out pins' the channel pins should be updated to whatever pins your channels are connected to from your receiver, the out pins are you channel output pins if you want to drive servos or electronic speed controllers, again update these to whatever pins you have your devices connected to.

Duane B

Dear DuaneB,

I "Finally" succeeded in running both codes (Yours and the other one), thank you !!!

The problems come from the 'attachInterrupt' numbers assignment...
The following worked with my board, I don't really know why, but anyway, this is the only funtion I needed from this board, so, I'm happy (^_^)

  // PIN 2
  attachInterrupt(0,handleInterrupt_P2,CHANGE); // Catch up and down    
  
  // PIN 3
  attachInterrupt(1,handleInterrupt_P3,CHANGE); // Catch up and down   
  
  // PIN 18
  attachInterrupt(5,handleInterrupt_P18,CHANGE); // Catch up and down   
  
  // PIN 19
  attachInterrupt(4,handleInterrupt_P19,CHANGE); // Catch up and down

Thanks for all !!

Best Regards,

Stéphane

Thank you so much!
This really works!!