Прерывание вызовов по умолчанию с помощью приемника RC
Я написал процедуру обработки прерывания (ISR) на плате Arduino UNO, подключенной к моему радиоприёмнику. Приёмник получает команды через подвесы моего передатчика и выполняет ISR при каждом перемещении подвесов.
Я ожидал, что обработчик прерываний НЕ будет вызван/выполнен, если я НЕ буду трогать подвесы. Даже если подвесы не трогать, обработчик прерываний вызывается/выполняется. Что на самом деле вызывает прерывания, которые постоянно вызывают обработчик прерываний?
//
// СХЕМА ТЕСТИРОВАНИЯ КОМАНД С РАДИОУПРАВЛЕНИЯ FLYSKY FS-i6X
//
// Определить переменные для номеров каналов
//
#define CHA1 0 // CHA1 равен 0 (Канал 1 управляет ROLL)
#define CHA2 1 // CHA2 равен 1 (Канал 2 управляет PITCH)
#define CHA3 2 // CHA3 равен 2 (Канал 3 управляет ГАЗОМ/ДРОССЕЛЬНОЙ ЗАСЛОНКОЙ)
#define CHA4 3 // CHA4 равен 3 (Канал 4 управляет YAW)
//
// Глобальные переменные
//
volatile unsigned int pwmLength[4]; // Длительность импульсов ШИМ на каналах приемника
volatile unsigned int interruptTime; // Время, используемое в процедуре обработки прерываний (ISR) для определения начала ЛЮБОГО прерывания.
// Это время, когда мы входим в процедуру ISR В ЛЮБОЙ момент, когда срабатывает прерывание.
volatile unsigned int pwmSignalStart[4]; // Массив времен начала сигналов ШИМ на каждом из каналов приемника
volatile byte chaPreviousState[4]; // Массив состояний (ВЫСОКИЙ или НИЗКИЙ) каждого из каналов приема ДО возникновения прерывания.
// Уровни цифрового контакта могут быть ВЫСОКИМ (HIGH) или НИЗКИМ (LOW). При чтении или записи на цифровой контакт
// для вывода можно задать только два возможных значения: HIGH и LOW. Это одно и то же
// как истина и ложь, а также 1 и 0.
//
// Объявление прототипов функций, используемых в программе.
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void selectInterruptSources(); // функция для настройки контактов, которые вызывают прерывание
void showFlyskyPwmLength(); // функция для отображения в Serial Monitor длительности сигналов ШИМ, полученных через RC-приемник.
//
// НАСТРАИВАТЬ()
//
void setup(){
// Установить скорость передачи данных в битах в секунду (бод)
Serial.begin(115200,SERIAL_8N1);
// Выбор выводов, используемых в качестве источников прерываний
selectInterruptSources();
}
//
// ПЕТЛЯ()
//
void loop(){
delay(250);
showFlyskyPwmLength();
}
//
// Эта функция манипулирует регистрами PCICR и PCMSK0, чтобы позволить цифровым контактам/терминалам вызывать прерывания
//
void selectInterruptSources(){
PCICR |= (1 << PCIE0); // сжатая запись PCICR = PCICR | (1 << PCIE0); Следовательно, 0-й бит PCICR устанавливается в 1
PCMSK0 |= (1 << PCINT0); // Переменная PCINT0 в iom328p.h определена как равная 0. Также PCINT0 — это бит 0 регистра PCMSK0,
// поэтому нам нужно переключить его в состояние «1», чтобы иметь возможность получать прерывание при изменении состояния
// происходит на «цифровом выводе 8». Итак, 1 << PCINT0 сдвигает число 1 влево на 0. Затем выполняется побитовая операция
// PCMSK0 = PCMSK0 | (1 << PCINT0) устанавливает бит 0 PCMSK0 в 1.
PCMSK0 |= (1 << PCINT1); // Переменная PCINT1 в iom328p.h определена как равная 1. Также PCINT1 — это бит 1 регистра PCMSK0,
// поэтому нам нужно переключить его в состояние «1», чтобы иметь возможность получать прерывание при изменении состояния
// происходит на «цифровом выводе 9». Итак, 1 << PCINT1 сдвигает число 1 влево на 1. Затем выполняется побитовая операция
// PCMSK0 = PCMSK0 | (1 << PCINT1) устанавливает бит 1 PCMSK0 в 1.
PCMSK0 |= (1 << PCINT2); // Переменная PCINT2 в iom328p.h определена как равная 2. Также PCINT2 — это бит 2 регистра PCMSK0,
// поэтому нам нужно переключить его в состояние «1», чтобы иметь возможность получать прерывание при изменении состояния
// происходит на «цифровом выводе 10». Итак, 1 << PCINT2 сдвигает число 1 влево на 2. Затем выполняется побитовая операция
// PCMSK0 = PCMSK0 | (1 << PCINT2) устанавливает бит 2 PCMSK0 в 1.
PCMSK0 |= (1 << PCINT3); // Переменная PCINT3 в iom328p.h определена как равная 3. Также PCINT3 — это бит 3 регистра PCMSK0,
// поэтому нам нужно переключить его в состояние «1», чтобы иметь возможность получать прерывание при изменении состояния
// происходит на «цифровом выводе 11». Итак, 1 << PCINT3 сдвигает число 1 влево на 3. Затем выполняется побитовая операция
// PCMSK0 = PCMSK0 | (1 << PCINT3) устанавливает бит 3 PCMSK0 в 1.
}
ISR(PCINT0_vect) {
//
// Канал 1 приемника FS-iA10B подключен к контакту/терминалу 8
//
interruptTime = micros(); // Начинает отсчет времени с момента срабатывания прерывания
if (PINB & B00000001){ // Проверяем, вызвал ли вывод 8 прерывание, т. е. если вывод 8 имеет высокий уровень, проверяем, нарастающий или спадающий фронт
if (chaPreviousState[CHA1] == LOW) { // Здесь мы проверяем, было ли предыдущее состояние контакта 8 «LOW», что означает, что контакт 8 сделал
// передний фронт, т.е. перешел от 0 к 1. Итак, мы устанавливаем состояние контакта 8 в ВЫСОКИЙ уровень, и
// это становится предыдущим состоянием для следующего срабатывания прерывания
chaPreviousState[CHA1] = HIGH;
pwmSignalStart[CHA1] = interruptTime; // Записываем время возникновения этого нарастающего фронта
}
// Альтернативно, если вывод 8 имеет уровень LOW, а предыдущее состояние вывода 8 — HIGH
} else if (chaPreviousState[CHA1] == HIGH) { // Предыдущее состояние было HIGH, вывод 8 перешел из «1» в «0», падающий фронт
chaPreviousState[CHA1] = LOW; // Предыдущее состояние для следующего срабатывания прерывания устанавливается в LOW
// Теперь мы можем вычислить длительность импульса ШИМ
pwmLength[CHA1] = interruptTime - pwmSignalStart[CHA1];
}
//
// Канал 2 приемника FS-iA10B подключен к контакту/терминалу 9
//
if (PINB & B00000010){ // Проверяем, вызвал ли вывод 9 прерывание, т. е. если вывод 9 имеет высокий уровень, проверяем, нарастающий или нисходящий фронт
if (chaPreviousState[CHA2] == LOW) { // Здесь мы проверяем, было ли предыдущее состояние контакта 9 «LOW», что означает, что контакт 9 сделал
// передний фронт, т.е. перешел от 0 к 1. Итак, мы устанавливаем состояние контакта 9 в ВЫСОКИЙ уровень, и
// это становится предыдущим состоянием для следующего срабатывания прерывания
chaPreviousState[CHA2] = HIGH;
pwmSignalStart[CHA2] = interruptTime; // Записываем время возникновения этого нарастающего фронта
}
// Альтернативно, если вывод 9 имеет уровень LOW, а предыдущее состояние вывода 9 — HIGH
} else if (chaPreviousState[CHA2] == HIGH) { // Предыдущее состояние было HIGH, вывод 9 перешел из «1» в «0», падающий фронт
chaPreviousState[CHA2] = LOW; // Предыдущее состояние для следующего срабатывания прерывания устанавливается в LOW
// Теперь мы можем вычислить длительность импульса ШИМ
pwmLength[CHA2] = interruptTime - pwmSignalStart[CHA2];
}
//
// Канал 3 приемника FS-iA10B подключен к контакту/терминалу 10
//
if (PINB & B00000100){ // Проверяем, вызвал ли вывод 10 прерывание, т. е. если вывод 10 имеет высокий уровень, проверяем, передний или задний фронт
if (chaPreviousState[CHA3] == LOW) { // Здесь мы проверяем, было ли предыдущее состояние контакта 10 «LOW», что означает, что контакт 10 сделал
// передний фронт, т.е. перешел от 0 к 1. Итак, мы устанавливаем состояние контакта 10 в ВЫСОКИЙ уровень, и
// это становится предыдущим состоянием для следующего срабатывания прерывания
chaPreviousState[CHA3] = HIGH;
pwmSignalStart[CHA3] = interruptTime; // Записываем время возникновения этого нарастающего фронта
}
// Альтернативно, если вывод 10 имеет уровень LOW, а предыдущее состояние вывода 10 — HIGH
} else if (chaPreviousState[CHA3] == HIGH) { // Предыдущее состояние было HIGH, вывод 10 перешел из «1» в «0», падающий фронт
chaPreviousState[CHA3] = LOW; // Предыдущее состояние для следующего срабатывания прерывания устанавливается в LOW
// Теперь мы можем вычислить длительность импульса ШИМ
pwmLength[CHA3] = interruptTime - pwmSignalStart[CHA3];
}
//
// Канал 4 приемника FS-iA10B подключен к контакту/терминалу 11
//
if (PINB & B00001000){ // Проверяем, вызвал ли вывод 11 прерывание, т. е. если вывод 11 имеет высокий уровень, проверяем, передний или задний фронт
if (chaPreviousState[CHA4] == LOW) { // Здесь мы проверяем, было ли предыдущее состояние контакта 11 «LOW», что означает, что контакт 11 сделал
// передний фронт, т.е. перешел от 0 к 1. Итак, мы устанавливаем состояние контакта 11 на ВЫСОКИЙ, и
// это становится предыдущим состоянием для следующего срабатывания прерывания
chaPreviousState[CHA4] = HIGH;
pwmSignalStart[CHA4] = interruptTime; // Записываем время возникновения этого нарастающего фронта
}
// Альтернативно, если вывод 11 имеет уровень LOW, а предыдущее состояние вывода 11 — HIGH
} else if (chaPreviousState[CHA4] == HIGH) { // Предыдущее состояние было HIGH, вывод 11 перешел из «1» в «0», падающий фронт
chaPreviousState[CHA4] = LOW; // Предыдущее состояние для следующего срабатывания прерывания устанавливается в LOW
// Теперь мы можем вычислить длительность импульса ШИМ
pwmLength[CHA4] = interruptTime - pwmSignalStart[CHA4];
}
}
//
// Выводит на последовательный монитор длительность/длину импульсов, полученных с каналов 8, 9, 10, 11 через радиоприемник
//
void showFlyskyPwmLength() {
Serial.print("Roll PWM Length: ");
Serial.print(pwmLength[CHA1]);
Serial.print("\u00B5s"); // Кодовая точка Unicode \u00B5 для микробуквы "s"
Serial.print(" -> Pitch PWM Length: ");
Serial.print(pwmLength[CHA2]);
Serial.print("\u00B5s"); // Кодовая точка Unicode \u00B5 для микробуквы "s"
Serial.print(" -> Gas PWM Length: ");
Serial.print(pwmLength[CHA3]);
Serial.print("\u00B5s"); // Кодовая точка Unicode \u00B5 для микробуквы "s"
Serial.print(" -> Yaw PWM Length: ");
Serial.print(pwmLength[CHA4]);
Serial.print("\u00B5s"); // Кодовая точка Unicode \u00B5 для микробуквы "s"
Serial.println("");
}

@AlexA, 👍-1
Обсуждение1 ответ
RC-приемник обычно выдает один импульс на канал каждые 20 мс, Независимо от того, касаетесь ли вы кнопок управления или нет, длина импульсов зависит от положения органов управления. Таким образом, вам придется засекать время полученные импульсы на Arduino, чтобы узнать, какие элементы управления находятся делаю на передатчике.
можно использовать аппаратный декодер... https://github.com/chiefenne/ATTINY85-RC-Receiver-Decoder, @jsotola
«Вам придётся синхронизировать полученные импульсы на Arduino, чтобы знать, что происходит с элементами управления передатчика». Как можно синхронизировать полученные импульсы на Arduino?, @AlexA
@AlexA: с помощью [micros()](https://docs.arduino.cc/language-reference/en/functions/time/micros/)., @Edgar Bonet
- Прерывание ардуино при смене контакта
- Как прервать функцию цикла и перезапустить ее?
- Есть ли лучший способ объединить оператор if с ISR?
- Изменчивая переменная не обновляется с таймера ISR
- ISR для очень быстрых процессов, обнаружен странный код. Влияет ли ISR на поведение таймера?
- Arduino использует задержку в I2C ReceiveEvent
- Умеренно точный осциллограф на Arduino Uno R3
- Почему сопротивление между выводом ввода-вывода и землей падает, когда Arduino не питается
на вопросы нельзя ответить, пока вы не сообщите нам, какие сигналы используются в соединениях и какой код вы используете... также вопрос не будет касаться Arduino, пока вы не добавите эту информацию в свой вопрос, @jsotola