В настоящее время я работаю над получением сигналов от пульта дистанционного управления. Я использовал контакты с A8 по A15 на своей плате Arduino Mega.
Порты и прерывания настраиваются с помощью этого кода:
DDRK = 0b00000000; // Set port A8-A15 to input
PCICR |= (1<<PCIE2); // Enable interrupt on PCMSK2 containing receiver pins
PORTK = 0b11111111;
PCMSK2 = 0b11111111; // Enable all interrupts on receiver pins
Затем я настроил прерывание, которое находит прерванный контакт и измеряет время импульса.
// Interrupts whenever a signal is received.
ISR(PCINT2_vect) {
static uint32_t startTime[8];
static uint8_t lastState;
uint8_t mask;
uint8_t changedPin;
mask = PINK ^ lastState;
lastState = PINK;
if(mask & (1 << 0)) changedPin = 0;
if(mask & (1 << 1)) changedPin = 1;
if(mask & (1 << 2)) changedPin = 2;
if(mask & (1 << 3)) changedPin = 3;
if(mask & (1 << 4)) changedPin = 4;
if(mask & (1 << 5)) changedPin = 5;
if(mask & (1 << 6)) changedPin = 6;
if(mask & (1 << 7)) changedPin = 7;
// Check if the changed pin is high
if(lastState & (1 << changedPin)) {
// Start counting if it is
startTime[changedPin] = micros();
} else {
// Save if it has gone down again
rcValue[changedPin] = micros() - startTime[changedPin];
}
}
На самом деле это работает очень хорошо, за исключением той части, когда я подключаю в общей сложности 4 или более контактов.
Пример:
A8: Работает нормально
A8–A9: Работает нормально
A8–A10: Работает нормально
A8–A11: A9 и A11 работают нормально, A10 не регистрирует никаких входных данных, A8 подскакивает от нормальных значений (1000–2000) до значений, которые около 17000р.
Я предполагаю, что это может иметь какое-то отношение к маскировке и обнаружению булавки оттуда, но я искал по всему всемогущему Интернету, и он не дал мне четкого ответа.
Я вижу три проблемы с вашим кодом:
Переменная волатильность и масштаб
Переменные ниже будут повреждены из-за того, что вы определяете их только в ISR. Но вы явно хотите сохранить их значение между прерываниями. Создайте следующие переменные volatile
и определите их глобально, а не в ISR:
uint8_t lastState;
uint32_t startTime[8];
Точное время
Запустите критический по времени код как можно скорее после возникновения прерывания. Считайте micros()
во временную переменную в начале ISR, чтобы весь условный код не влиял на время. Затем назначьте временную переменную, startTime[changedPin]
как только ваш код решит, куда ее поместить.
Одновременные края
Обратите внимание, что ваш код не справляется с одновременным изменением контактов, старший контакт будет иметь приоритет. Затем, когда эти выводы не имеют одновременных падающих фронтов, синхронизация для вывода с наименьшим номером будет повреждена.
Борен