Que se passe-t-il lorsque j'utilise un code PIN non valide?

9

Lié à: Que se passe-t-il en cas d'erreur d'exécution?

Cette question est similaire à celle ci-dessus, mais il s'agit d'une situation alternative:

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

Que se passerait-il dans ce cas? Le compilateur pourrait l'attraper mais si vous utilisiez un nombre aléatoire, l'IDE le rattraperait-il?

Pingouin anonyme
la source

Réponses:

9

Le compilateur ne détectera aucune erreur et le code se compilera et s'exécutera. Par conséquent, pour voir ce qui se passe, nous devons explorer la magie des coulisses. Pour un résumé, passez à la fin.


La deuxième ligne de votre code est l'endroit où la magie se produira et c'est là que nous devons nous concentrer.

pinMode(pin, OUTPUT);

La partie pinModepertinente de cette discussion est:

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'implémentation complète peut être trouvée dans le câblage_digital.c )

Donc, ici, digitalPinToBitMasksemble utiliser pinpour calculer un bit intermédiaire. En explorant plus loin, digitalPinToBitMaskune macro définie dans Arduino.hla définition de laquelle est cette ligne unique:

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

Cette doublure à l'aspect étrange fait une tâche très simple. Il indexe le P ème élément du tableau digital_pin_to_bit_mask_PGMet le renvoie. Ce tableau digital_pin_to_bit_mask_PGMest défini dans pins_arduino.hou la carte des broches de la carte spécifique utilisée.

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

Ce tableau comprend 20 éléments au total, nous n'avons donc pas de chance. 999 indexera un emplacement de mémoire dans la mémoire flash en dehors de cette baie, conduisant ainsi à un comportement imprévisible. Ou bien?

Nous avons encore une autre ligne de défense contre l'anarchie d'exécution. C'est la prochaine ligne de la fonction pinMode:

uint8_t port = digitalPinToPort(pin);

digitalPinToPortnous emmène sur un chemin similaire. Il est défini comme une macro avec digitalPinToBitMask. Sa définition est:

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

Maintenant, nous indexons l' élément P thdigital_pin_to_port_PGM qui est un tableau défini dans la carte des broches:

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

Ce tableau contient 20 éléments, donc 999 est à nouveau hors de portée. Encore une fois, cette commande lit et renvoie une valeur de la mémoire flash dont nous ne pouvons pas être certains. Cela conduira à nouveau à un comportement imprévisible à partir de maintenant.

Il reste encore une dernière ligne de défense. Il s'agit de l' ifenregistrement de pinModela valeur de retour de digitalPinToPort:

if (port == NOT_A_PIN) return;

NOT_A_PINest défini comme 0 po Arduino.h. Donc, si l'octet retourné de digitalPinToPortse trouve être nul, il pinModeéchouera et reviendra en silence.

En tout cas, pinModene peut pas nous sauver de l'anarchie. Le 999 est destiné à entraîner une perte.


TL; DR, le code s'exécutera et le résultat sera imprévisible. Très probablement, aucune broche ne sera définie OUTPUTet digitalWriteéchouera. Si vous avez une malchance exceptionnelle, une épingle aléatoire peut être définie sur OUTPUTet digitalWritepeut être définie sur HIGH.

asheeshr
la source
Il est intéressant de noter qu'il n'y a pas de vérification des limites. digitalWrite est si lent et encombrant de toute façon, qu'il ne serait pas gênant de mettre en place des vérifications au moment de la compilation ou de l'exécution.
Cybergibbons
Si toutes les broches Arduino sont dans une plage contiguë, alors ne pourraient-elles pas remplacer le port == pas une vérification des broches par une vérification pin> BOARD_MAX_PIN, où la broche max de la carte est définie dans un fichier d'en-tête basé sur un ifdef qui détecte la carte?
EternityForest
Vous oubliez que 999 ne peut pas être représenté dans un uint8_tafin qu'il soit d'abord converti en 231 par l'appel de code pinMode. Le résultat final est le même: pinModeil digitalWriteaura un comportement imprévisible et pourrait encombrer des parties aléatoires de la mémoire si vous les appelez avec un mauvais argument pin.
David Grayson
3

Dans les bibliothèques standard, il existe des macros conçues pour convertir les broches en ports, qui sont utilisées dans l'assemblage. Les voici pour l'Uno d'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)))

Il y en a plus, mais je ne les montrerai pas ici.

Je crois que votre programme soustrait 14 de 999, ce qui serait encore trop gros pour le brogramme. Il essaierait alors de pointer vers le 985e élément du digital_pn_to_bit_mask_PGMtableau, qui ne contient que 20 éléments. Cela finirait très probablement par visser l'Arduino en pointant vers un endroit aléatoire dans le programme.

Le docteur
la source