Cosa succederà quando utilizzo un numero PIN non valido?


9

Relativo a: Cosa succede se si verifica un errore di runtime?

Questa domanda è simile a quella sopra, tuttavia questa è una situazione alternativa:

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

Cosa succederebbe in questo caso? Il compilatore potrebbe prenderlo, ma se si usasse un numero casuale, l'IDE lo catturerebbe?

Risposte:


9

Il compilatore non rileverà alcun errore e il codice verrà compilato ed eseguito. Quindi, per vedere cosa succede dobbiamo esplorare la magia dietro le quinte. Per un riepilogo, saltare alla fine.


La seconda riga del tuo codice è dove accadrà la magia ed è qui che dobbiamo concentrarci.

pinMode(pin, OUTPUT);

La parte pinModerilevante per questa discussione è:

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
}

(L'implementazione completa è disponibile in cablaggio_digital.c )

Quindi, qui, digitalPinToBitMasksembra che stia usando pinper calcolare un bit intermedio. Esplorando ulteriormente, digitalPinToBitMaskè una macro definita nella Arduino.hcui definizione è questo one-liner:

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

Questa fodera dall'aspetto strano fa un compito molto semplice. Indicizza l' elemento P th nell'array digital_pin_to_bit_mask_PGMe lo restituisce. Questo array digital_pin_to_bit_mask_PGMè definito nella pins_arduino.hpin map per la scheda specifica utilizzata.

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),
...
};

Questo array ha 20 elementi in totale, quindi siamo sfortunati. 999 indicizzerà una posizione di memoria nella memoria flash al di fuori di questo array, portando a comportamenti imprevedibili. O lo sarà?

Abbiamo ancora un'altra linea di difesa contro l'anarchia di runtime. È la riga successiva della funzione pinMode:

uint8_t port = digitalPinToPort(pin);

digitalPinToPortci porta lungo un percorso simile. È definito come una macro insieme a digitalPinToBitMask. La sua definizione è:

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

Ora, indicizziamo l' elemento P th di digital_pin_to_port_PGMcui è un array definito nella pin map:

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

Questo array contiene 20 elementi, quindi 999 è di nuovo fuori portata. Ancora una volta, questo comando legge e restituisce un valore dalla memoria flash di cui non possiamo essere certi. Questo porterà di nuovo a comportamenti imprevedibili da qui in poi.

C'è ancora un'ultima linea di difesa. Questo è il ifcheck-in pinModesul valore di ritorno di digitalPinToPort:

if (port == NOT_A_PIN) return;

NOT_A_PINè definito come 0 pollici Arduino.h. Quindi, se il byte restituito da digitalPinToPortrisulta essere zero, allora pinModefallirà silenziosamente e tornerà.

In ogni caso, pinModenon possiamo salvarci dall'anarchia. 999 è destinato a provocare il destino.


TL; DR, il codice verrà eseguito e il risultato sarà imprevedibile. Molto probabilmente, nessun pin verrà impostato OUTPUTe digitalWritenon riuscirà. Se ti capita di avere sfortuna eccezionalmente, un pin casuale può essere impostato su OUTPUTe digitalWritepuò impostarlo su HIGH.


È interessante che non ci siano limiti di controllo. digitalWrite è comunque così lento e voluminoso che non sarebbe scomodo inserire controlli di tempo di compilazione o di esecuzione.
Cybergibbons,

Se tutti i pin arduino si trovano in un intervallo contiguo, allora non potrebbero sostituire la porta == non un controllo pin con un pin> BOARD_MAX_PIN check, dove il pin max della scheda è definito in un file di intestazione basato su alcuni ifdef che rileva la scheda?
EternityForest,

Stai dimenticando che 999 non può essere rappresentato in a, uint8_tquindi verrà prima convertito in 231 dalla chiamata in codice pinMode. Il risultato finale è lo stesso: pinModee digitalWriteavrà un comportamento imprevedibile e potrebbe clobber parti casuali della memoria se li chiami con un argomento cattiva pin.
David Grayson,

3

Nelle librerie standard, ci sono macro progettate per convertire i pin in porte, che vengono utilizzate in assembly. Eccoli per Uno di 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)))

Ce ne sono altri, ma non li mostrerò qui.

Credo che il tuo programma sottrarrebbe 14 dal 999, che sarebbe comunque troppo grande per il diagramma. Proverebbe quindi a puntare al 985 ° elemento digital_pn_to_bit_mask_PGMdell'array, che contiene solo 20 elementi. Molto probabilmente questo finirebbe per rovinare l'Arduino indicando un punto casuale nel progmem.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.