I've written an ISR routine using an Arduino UNO wired to my RC receiver. The receiver gets orders through the gimbals in my transmitter and executes the ISR every time the gimbals are moved. However, I was expecting that the ISR would NOT be called/executed if I did NOT touch the gimbals. However, this is NOT the case. Even when the gimbals are left untouched, the ISR is called/executed. I was wondering what is actually triggering interrupts that keep calling the ISR?? Would it have anything to do with the volatile variables that I use to be able to trigger interrupts?? Thanks for any help. AA
Hi @AlexA What sort of RC receiver is it? How is it wired to your board i.e. which pins on Arduino to which pins receiver?
In most cases of that problem, it is noise on the wire connected to the interrupt pin.
Floating interrupt inputs do that. Did you connect all the grounds?
For help on this forum, please read and follow the instructions in the "How to get the best out of this forum" post, linked at that head of every forum category.
In this case, be sure to post a schematic diagram of the system, with all parts, pins and connections clearly labeled.
As @jremington requested post an annotated schematic and include all parts. Also note all power sources and leads over 25cm/10" in length,
Sorry if I did not follow instructions.
Flysky iA10B is the receiver. Channel 1 of receiver wired to pin 8. Channel 2 of receiver wired to pin 9. Channel 3 of receiver wired to pin 10. Channel 4 of receiver wired to pin 11. (-) of Channel 1 in receiver connected to GND on Arduino. (+) in Channel 1 in receiver connected to 5V on Arduino. Here is a photo.
Hope this is clearer.
BTW, all leads are longer than 25cm.
The receiver will be sending pulses through continuously, not just on stick movement. Have you considered using the ibus serial protocol from the receiver connected to board uarts?
Do you have a reference I can read to help me do that??
I changed all wires to 6" in length, no difference in behavior.
Unfortunately, this is way out my league... Thank you kindly for the suggestion.
It's really not that difficult, and happy to help if you change your mind. If you want to continue with wiring to the servo output pins then have a look at pulseIn https://docs.arduino.cc/language-reference/en/functions/advanced-io/pulseIn/ rather than use interrupts.
Thanks again, I'll see how I can use this function. Can I ask you later if I need help??
Absolutely, but replies will not always be this prompt.
That's ok, thanks!
I can practically guarantee that your time would be better spent coming to grips with using a library purpose-built to decode the FlySky PPM signal than trying to understand and get your own interrupt-based code to work.
I notice you did not post any code. It is possible that your issue could get some better attention if you would.
But srsly, the library is vastly superior to hand doing this with interrupts or with pukseIn().
There are examples, you should be able to get this one running without bothering your brain all that much:
Using the data it can snag out of the PPM signal in your own code woukd be the challenging part, but only a minor challenge but again easier to say just how if you… post the code you ar working at the moment.
a7
Here is the code:
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// SKETCH TO TEST COMMANDS FROM FLYSKY FS-i6X RADIO CONTROL
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// Define variables for channel numbers
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define CHA1 0 // CHA1 equals 0 (Channel 1 controls ROLL)
#define CHA2 1 // CHA2 equals 1 (Channel 2 controls PITCH)
#define CHA3 2 // CHA3 equals 2 (Channel 3 controls GAS/THROTTLE)
#define CHA4 3 // CHA4 equals 3 (Channel 4 controls YAW)
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// Global variables
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
volatile unsigned int pwmLength[4]; // PWM pulse durations on the receiver channels
volatile unsigned int interruptTime; // Time used in interrupt service routine (ISR) to identify beginning of ANY interrupt.
// This is the time when we enter the ISR routine ANY time an interrupt is triggered.
volatile unsigned int pwmSignalStart[4]; // Array of start times of PWM signals at each of the receiver channels
volatile byte chaPreviousState[4]; // Array of states (HIGH or LOW) of each of the reception channels BEFORE an interrupt occurs.
// Pin Levels in a digital pin can be HIGH or LOW. When reading or writing to a digital pin
// there are only two possible values a pin can be-set-to: HIGH and LOW. These are the same
// as true and false, as well as 1 and 0.
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// Declaration of the prototypes of the functions used in the program. When using the Arduino IDE, this declaration is not
// strictly necessary becasuse the IDE does this declaration for you. However, it's a good progamming practice (GPM) to follow.
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void selectInterruptSources(); // function to configure the pins that trigger an interrupt
void showFlyskyPwmLength(); // function to displays in Serial Monitor durations of the PWM signals received via the RC receiver.
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// SETUP()
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void setup(){
// Set data rate in bits per second (baud) for serial data transmission. For communicating with Serial Monitor (SM),
// make sure to use one of the baud rates listed in the menu at the bottom right corner of the SM screen.
Serial.begin(115200,SERIAL_8N1);
// Selection of pins used as interrupt sources
selectInterruptSources();
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// LOOP()
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void loop(){
delay(250);
showFlyskyPwmLength();
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// This function manipulates registers PCICR and PCMSK0 so as to allow digital pins/terminals to trigger interrupts
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void selectInterruptSources(){
PCICR |= (1 << PCIE0); // condensed writing of PCICR = PCICR | (1 << PCIE0); Hence, 0-bit of PCICR set to 1
PCMSK0 |= (1 << PCINT0); // Variable PCINT0 in iom328p.h is defined as equal to 0. Also, PCINT0 is bit 0 of register PCMSK0,
// so we need to toggle it to "1" in order to be able to receive an interrupt when a change of state
// occurs at "digital pin 8". So, 1 << PCINT0 left-shifts number 1 by 0. Then, the bitwise operation
// PCMSK0 = PCMSK0 | (1 << PCINT0) sets bit 0 of PCMSK0 to 1.
PCMSK0 |= (1 << PCINT1); // Variable PCINT1 in iom328p.h is defined as equal to 1. Also, PCINT1 is bit 1 of register PCMSK0,
// so we need to toggle it to "1" in order to be able to receive an interrupt when a change of state
// occurs at "digital pin 9". So, 1 << PCINT1 left-shifts number 1 by 1. Then, the bitwise operation
// PCMSK0 = PCMSK0 | (1 << PCINT1) sets bit 1 of PCMSK0 to 1.
PCMSK0 |= (1 << PCINT2); // Variable PCINT2 in iom328p.h is defined as equal to 2. Also, PCINT2 is bit 2 of register PCMSK0,
// so we need to toggle it to "1" in order to be able to receive an interrupt when a change of state
// occurs at "digital pin 10". So, 1 << PCINT2 left-shifts number 1 by 2. Then, the bitwise operation
// PCMSK0 = PCMSK0 | (1 << PCINT2) sets bit 2 of PCMSK0 to 1.
PCMSK0 |= (1 << PCINT3); // Variable PCINT3 in iom328p.h is defined as equal to 3. Also, PCINT3 is bit 3 of register PCMSK0,
// so we need to toggle it to "1" in order to be able to receive an interrupt when a change of state
// occurs at "digital pin 11". So, 1 << PCINT3 left-shifts number 1 by 3. Then, the bitwise operation
// PCMSK0 = PCMSK0 | (1 << PCINT3) sets bit 3 of PCMSK0 to 1.
}
ISR(PCINT0_vect) {
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// Channel 1 of FS-iA10B receiver is connected to pin/terminal 8
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
interruptTime = micros(); // Starts computing time from the time an interrupt is triggered
if (PINB & B00000001){ // Check if pin 8 triggered interrupt, i.e., if pin 8 is HIGH, check if rising edge or falling edge
if (chaPreviousState[CHA1] == LOW) { // Here we test if the previous state of pin 8 was "LOW", which means pin 8 made
// a rising edge, i.e., went from 0 to 1. So, we set the state of pin 8 to HIGH, and
// this becomes the previous state for next time an interrupt is triggered
chaPreviousState[CHA1] = HIGH;
pwmSignalStart[CHA1] = interruptTime; // Record the time this rising edge occurs
}
// Alternatively, if pin 8 is LOW and the previous state of pin 8 is HIGH
} else if (chaPreviousState[CHA1] == HIGH) { // Previous state was HIGH, pin 8 went from "1" to "0", a falling edge
chaPreviousState[CHA1] = LOW; // Previous state for next time interrupt is triggered is set to LOW
// We can now compute the PWM pulse length
pwmLength[CHA1] = interruptTime - pwmSignalStart[CHA1];
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// Channel 2 of FS-iA10B receiver is connected to pin/terminal 9
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
if (PINB & B00000010){ // Check if pin 9 triggered interrupt, i.e., if pin 9 is HIGH, check if rising edge or falling edge
if (chaPreviousState[CHA2] == LOW) { // Here we test if the previous state of pin 9 was "LOW", which means pin 9 made
// a rising edge, i.e., went from 0 to 1. So, we set the state of pin 9 to HIGH, and
// this becomes the previous state for next time an interrupt is triggered
chaPreviousState[CHA2] = HIGH;
pwmSignalStart[CHA2] = interruptTime; // Record the time this rising edge occurs
}
// Alternatively, if pin 9 is LOW and the previous state of pin 9 is HIGH
} else if (chaPreviousState[CHA2] == HIGH) { // Previous state was HIGH, pin 9 went from "1" to "0", a falling edge
chaPreviousState[CHA2] = LOW; // Previous state for next time interrupt is triggered is set to LOW
// We can now compute the PWM pulse length
pwmLength[CHA2] = interruptTime - pwmSignalStart[CHA2];
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// Channel 3 of FS-iA10B receiver is connected to pin/terminal 10
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
if (PINB & B00000100){ // Check if pin 10 triggered interrupt, i.e., if pin 10 is HIGH, check if rising edge or falling edge
if (chaPreviousState[CHA3] == LOW) { // Here we test if the previous state of pin 10 was "LOW", which means pin 10 made
// a rising edge, i.e., went from 0 to 1. So, we set the state of pin 10 to HIGH, and
// this becomes the previous state for next time an interrupt is triggered
chaPreviousState[CHA3] = HIGH;
pwmSignalStart[CHA3] = interruptTime; // Record the time this rising edge occurs
}
// Alternatively, if pin 10 is LOW and the previous state of pin 10 is HIGH
} else if (chaPreviousState[CHA3] == HIGH) { // Previous state was HIGH, pin 10 went from "1" to "0", a falling edge
chaPreviousState[CHA3] = LOW; // Previous state for next time interrupt is triggered is set to LOW
// We can now compute the PWM pulse length
pwmLength[CHA3] = interruptTime - pwmSignalStart[CHA3];
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// Channel 4 of FS-iA10B receiver is connected to pin/terminal 11
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
if (PINB & B00001000){ // Check if pin 11 triggered interrupt, i.e., if pin 11 is HIGH, check if rising edge or falling edge
if (chaPreviousState[CHA4] == LOW) { // Here we test if the previous state of pin 11 was "LOW", which means pin 11 made
// a rising edge, i.e., went from 0 to 1. So, we set the state of pin 11 to HIGH, and
// this becomes the previous state for next time an interrupt is triggered
chaPreviousState[CHA4] = HIGH;
pwmSignalStart[CHA4] = interruptTime; // Record the time this rising edge occurs
}
// Alternatively, if pin 11 is LOW and the previous state of pin 11 is HIGH
} else if (chaPreviousState[CHA4] == HIGH) { // Previous state was HIGH, pin 11 went from "1" to "0", a falling edge
chaPreviousState[CHA4] = LOW; // Previous state for next time interrupt is triggered is set to LOW
// We can now compute the PWM pulse length
pwmLength[CHA4] = interruptTime - pwmSignalStart[CHA4];
}
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// Prints to serial monitor the pulse durations/lengths received from channels 8, 9, 10, 11 via the radio receiver
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void showFlyskyPwmLength() {
Serial.print("Roll PWM Length: ");
Serial.print(pwmLength[CHA1]);
Serial.print("\u00B5s"); // Unicode code point \u00B5 for micro plus letter "s"
Serial.print(" -> Pitch PWM Length: ");
Serial.print(pwmLength[CHA2]);
Serial.print("\u00B5s"); // Unicode code point \u00B5 for micro plus letter "s"
Serial.print(" -> Gas PWM Length: ");
Serial.print(pwmLength[CHA3]);
Serial.print("\u00B5s"); // Unicode code point \u00B5 for micro plus letter "s"
Serial.print(" -> Yaw PWM Length: ");
Serial.print(pwmLength[CHA4]);
Serial.print("\u00B5s"); // Unicode code point \u00B5 for micro plus letter "s"
Serial.println("");
}
I just posted the code.
This was explained and you haven't actually said the code doesn't work. Post some of the output.
I would try eliminating the delay in you loop() function, and cut way back on the amount of printing in your report and see what differences it makes.
But I think the N PWM signals may be confusing things. Chop both the ISR and the report down to just one channel and see if you can get just one channel working.
The code looks fairly sophisticated. You have the skillz to write an ISR to read and decode the PPM stream. One input line to watch…
And…
sry, sry sry, the library mentioned is actually for the Ibus serial protocol! This makes switching to it even more compelling… it does not involve measuring pulse length, it provides true digital communication for a much better end-to-end fidelity. Again one input line.
Unless you have a special desire to write this yourself, just fold your tent and use the (or a, there are others) library.
a7