Was passiert, wenn ich eine ungültige PIN-Nummer verwende?


9

Verwandt mit: Was passiert, wenn ein Laufzeitfehler vorliegt?

Diese Frage ähnelt der obigen, ist jedoch eine alternative Situation:

int pin = 999;
pinMode(pin, OUTPUT);
digitalWrite(pin, HIGH);

Was würde in diesem Fall passieren? Der Compiler könnte es abfangen, aber wenn Sie eine Zufallszahl verwenden würden, würde die IDE es abfangen?

Antworten:


9

Der Compiler erkennt keinen Fehler und der Code wird kompiliert und ausgeführt. Um zu sehen, was passiert, müssen wir die Magie hinter den Kulissen erforschen. Für eine Zusammenfassung springen Sie zum Ende.


Die zweite Zeile in Ihrem Code ist, wo die Magie passieren wird und wo wir uns konzentrieren müssen.

pinMode(pin, OUTPUT);

Der pinModefür diese Diskussion relevante Teil ist:

void pinMode(uint8_t pin, uint8_t mode) 
{

    uint8_t bit = digitalPinToBitMask(pin); //The first instance where pin is used
    uint8_t port = digitalPinToPort(pin);

    if (port == NOT_A_PIN) return;

//Do something
}

(Die vollständige Implementierung finden Sie in wiring_digital.c )

Hier digitalPinToBitMaskscheint also pinein Zwischenbit zu berechnen. Weiter erforschen, digitalPinToBitMaskist ein Makro definiert, in Arduino.hdessen Definition dieser Einzeiler ist:

#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )

Dieser seltsam aussehende Einzeiler erledigt eine sehr einfache Aufgabe. Es indiziert das P- te Element im Array digital_pin_to_bit_mask_PGMund gibt es zurück. Dieses Array digital_pin_to_bit_mask_PGMist in pins_arduino.hoder in der Pin-Map für die jeweilige verwendete Karte definiert .

const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
    _BV(0), /* 0, port D */
    _BV(1),
    _BV(2),
    _BV(3),
    _BV(4),
    _BV(5),
    _BV(6),
    _BV(7),
...
};

Dieses Array enthält insgesamt 20 Elemente, daher haben wir kein Glück. 999 indiziert einen Speicherort im Flash-Speicher außerhalb dieses Arrays, was zu einem unvorhersehbaren Verhalten führt. Oder wird es?

Wir haben noch eine andere Verteidigungslinie gegen die Laufzeitanarchie. Es ist die nächste Zeile der Funktion pinMode:

uint8_t port = digitalPinToPort(pin);

digitalPinToPortführt uns auf einem ähnlichen Weg. Es wird zusammen mit als Makro definiert digitalPinToBitMask. Seine Definition lautet:

#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )

Nun indizieren wir das P- te Element, digital_pin_to_port_PGMdessen Array in der Pin-Map definiert ist:

const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
    PD, /* 0 */
    PD,
    ....
    PC,
    PC,
};

Dieses Array enthält 20 Elemente, sodass 999 wieder außerhalb des Bereichs liegt. Wiederum liest dieser Befehl einen Wert aus dem Flash-Speicher und gibt ihn zurück, dessen Wert wir nicht sicher sein können. Dies wird von nun an wieder zu unvorhersehbarem Verhalten führen.

Es gibt noch eine letzte Verteidigungslinie. Das ist das ifEinchecken pinModedes Rückgabewerts von digitalPinToPort:

if (port == NOT_A_PIN) return;

NOT_A_PINist definiert als 0 in Arduino.h. Wenn also das zurückgegebene Byte von digitalPinToPortzufällig Null ist, pinModeschlägt dies stillschweigend fehl und kehrt zurück.

pinModeKann uns auf keinen Fall vor Anarchie retten. 999 ist dazu bestimmt, zum Untergang zu führen.


TL; DR, der Code wird ausgeführt und das Ergebnis ist unvorhersehbar. Höchstwahrscheinlich wird kein Pin auf gesetzt und OUTPUTfällt digitalWriteaus. Wenn Sie außergewöhnlich viel Pech haben, wird möglicherweise ein zufälliger Pin auf gesetzt OUTPUTund auf digitalWritegesetzt HIGH.


Es ist interessant, dass es keine Grenzen gibt. digitalWrite ist sowieso so langsam und sperrig, dass es nicht umständlich wäre, Kompilierungs- oder Laufzeitprüfungen durchzuführen.
Cybergibbons

Wenn sich alle Arduino-Pins in einem zusammenhängenden Bereich befinden, können sie dann nicht den Port ersetzen == keine Pin-Prüfung durch eine Pin> BOARD_MAX_PIN-Prüfung, wobei der maximale Pin der Karte in einer Header-Datei definiert ist, die auf einem ifdef basiert, das die Karte erkennt?
EternityForest

Sie vergessen, dass 999 nicht in a dargestellt werden kann, uint8_tsodass es zuerst durch den aufrufenden Code in 231 konvertiert wird pinMode. Das Endergebnis ist das gleiche: pinModeund digitalWritehat ein unvorhersehbares Verhalten und kann zufällige Teile des Speichers blockieren, wenn Sie sie mit einem schlechten Pin-Argument aufrufen.
David Grayson

3

In den Standardbibliotheken gibt es Makros zum Konvertieren von Pins in Ports, die bei der Montage verwendet werden. Hier sind sie für den Uno von Arduino 1.0.5:

#define digitalPinToPCICR(p)    (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0))
#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1))
#define digitalPinToPCMSK(p)    (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0))))
#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14)))

Es gibt noch mehr, aber ich werde sie hier nicht zeigen.

Ich glaube, Ihr Programm würde 14 von 999 abziehen, was für das Brogramm immer noch zu groß wäre. Es würde dann versuchen, auf das 985. Element des digital_pn_to_bit_mask_PGMArrays zu verweisen , das nur 20 Elemente enthält. Dies würde höchstwahrscheinlich dazu führen, dass das Arduino durch Zeigen auf eine zufällige Stelle im Programm verschraubt wird.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.