AVR-Interrupt „Interferenz“

Ich arbeite derzeit daran, Signale von einer RC-Fernbedienung zu empfangen. Ich habe die Pins A8 bis A15 auf meinem Arduino Mega Board verwendet.

Die Ports und Interrupts werden mit Hilfe dieses Codes eingerichtet:

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

Dann habe ich einen Interrupt eingerichtet, der den unterbrochenen Pin findet und den Impuls timet.

// 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];
}
}

Das funktioniert wirklich gut, außer für den Teil, wenn ich insgesamt 4 oder mehr Pins verbinde.

Beispiel:
A8: Funktioniert einwandfrei
A8 bis A9: Funktioniert einwandfrei
A8 bis A10: Funktioniert einwandfrei
A8 bis A11: A9 und A11 funktionieren einwandfrei, A10 registriert keine Eingabe, A8 springt von normalen Werten (1000-2000) auf Werte, die hochspringen sind ungefähr 17000.

Meine Vermutung ist, dass es etwas mit der Maskierung und Erkennung des Pins von dort zu tun haben könnte, aber ich habe das ganze allmächtige Internet durchsucht und es hat mir keine klare Antwort gegeben.

Antworten (1)

Ich sehe drei Probleme mit Ihrem Code:

Variable Volatilität und Umfang

Die folgenden Variablen werden beschädigt, da Sie sie nur in der ISR definieren. Aber Sie möchten ihren Wert eindeutig zwischen Interrupts behalten. Machen Sie die folgenden Variablen volatileund definieren Sie sie global, nicht in der ISR:

  • uint8_t lastState;
  • uint32_t startTime[8];

Genaues Timing

Führen Sie zeitkritischen Code so schnell wie möglich aus, nachdem der Interrupt aufgetreten ist. Lesen Sie micros()zu Beginn der ISR in eine temporäre Variable, damit der gesamte Bedingungscode das Timing nicht beeinflusst. Weisen Sie dann die temporäre Variable zu, startTime[changedPin]sobald Ihr Code entschieden hat, wo sie abgelegt werden soll.

Gleichzeitige Kanten

Beachten Sie, dass Ihr Code nicht mit gleichzeitigen PIN-Änderungen zurechtkommt, die höchste PIN hat Vorrang. Wenn diese Stifte dann keine gleichzeitig fallenden Flanken haben, wird das Timing für den Stift mit der niedrigsten Nummer fehlerhaft sein.

Vielen Dank für die sehr informative und lehrreiche Antwort. Ich werde Ihre Änderungen innerhalb weniger Stunden testen und sie dann akzeptieren, wenn sie funktionieren.