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.
I was expecting that the ISR would NOT be called/executed if I did NOT touch the gimbals. Even when the gimbals are left untouched, the ISR is called/executed. What is actually triggering interrupts that keep calling the ISR??
//
// 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.
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
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)
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("");
}
-
2the questions is not answerable until you tell us what are the signals at the connections and what code you are using ... also the question is not about the arduino until you add that info to your questionjsotola– jsotola2025年02月25日 20:04:44 +00:00Commented Feb 25 at 20:04
1 Answer 1
An RC receiver typically outputs one pulse per channel every 20 ms, whether you touch the controls or not. The length of the pulses depend on the position of the controls. Thus, you will have to time the received pulses on the Arduino in order to know what the controls are doing on the transmitter.
-
a hardware decoder could be used ... github.com/chiefenne/ATTINY85-RC-Receiver-Decoderjsotola– jsotola2025年02月25日 21:01:40 +00:00Commented Feb 25 at 21:01
-
"you will have to time the received pulses on the Arduino in order to know what the controls are doing on the transmitter." How can I time the received pulses on the Arduino??AlexA– AlexA2025年02月25日 21:05:21 +00:00Commented Feb 25 at 21:05
-
@AlexA: with
micros()
.Edgar Bonet– Edgar Bonet2025年02月25日 21:34:33 +00:00Commented Feb 25 at 21:34