Vraag:
Wat gebeurt er als ik een ongeldige pincode gebruik?
Anonymous Penguin
2014-02-17 21:26:30 UTC
view on stackexchange narkive permalink

Gerelateerd aan: Wat gebeurt er als er een runtime-fout is?

Deze vraag is vergelijkbaar met de bovenstaande, maar dit is een alternatieve situatie:

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

Wat zou er in dit geval gebeuren? De compiler kan het onderscheppen, maar als je een willekeurig nummer zou gebruiken, zou de IDE het dan opvangen?

Twee antwoorden:
#1
+9
asheeshr
2014-02-17 22:48:05 UTC
view on stackexchange narkive permalink

De compiler zal geen enkele fout detecteren en de code zal compileren en uitvoeren. Om te zien wat er gebeurt, moeten we de magie achter de schermen verkennen. Voor een samenvatting, ga naar het einde.


De tweede regel in je code is waar de magie zal gebeuren en dat is waar we ons op moeten concentreren.

  pinMode (pin, OUTPUT);  

Het gedeelte van pinMode dat relevant is voor deze discussie is:

  void pinMode (uint8_t pin, uint8_t mode) {uint8_t bit = digitalPinToBitMask (pin); // De eerste instantie waar pin wordt gebruikt uint8_t port = digitalPinToPort (pin); if (port == NOT_A_PIN) return; // Doe iets}  

(De volledige implementatie is te vinden in bedrading_digital.c)

Dus hier lijkt digitalPinToBitMask pin te gebruiken om een ​​tussenbit te berekenen. Verder onderzoekend, digitalPinToBitMask is een macro gedefinieerd in Arduino.h waarvan de definitie deze one-liner is:

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

Deze raar uitziende voering doet een heel eenvoudige taak. Het indexeert het P de -element in de array digital_pin_to_bit_mask_PGM en geeft het terug. Deze array digital_pin_to_bit_mask_PGM wordt gedefinieerd in pins_arduino.h of de pin-map voor het specifieke bord dat wordt gebruikt.

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

Deze array heeft in totaal 20 elementen, dus we hebben pech. 999 indexeert een geheugenlocatie in het flash-geheugen buiten deze array, wat leidt tot onvoorspelbaar gedrag. Of zal het?

We hebben nog een andere verdedigingslinie tegen runtime-anarchie. Het is de volgende regel van de functie pinMode:

  uint8_t port = digitalPinToPort (pin);  

digitalPinToPort leidt ons op een vergelijkbaar pad. Het wordt gedefinieerd als een macro samen met digitalPinToBitMask . De definitie is:

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

Nu indexeren we de P het element van digital_pin_to_port_PGM wat een array is die is gedefinieerd in de pin-map:

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

Deze array bevat 20 elementen, dus 999 is weer buiten bereik. Nogmaals, deze opdracht leest en retourneert een waarde uit het flash-geheugen waarvan we de waarde niet zeker weten. Dit zal vanaf nu weer leiden tot onvoorspelbaar gedrag.

Er is nog een laatste verdedigingslinie. Dat is de if check in pinMode op de retourwaarde van digitalPinToPort:

  if (port == NOT_A_PIN) return;  

NOT_A_PIN is gedefinieerd als 0 in Arduino.h . Dus als de geretourneerde byte van digitalPinToPort toevallig nul is, zal pinMode stilletjes mislukken en terugkeren.

In elk geval kan pinMode ons niet van anarchie redden. 999 is voorbestemd om te resulteren in ondergang.


TL; DR, de code wordt uitgevoerd en het resultaat hiervan zal onvoorspelbaar zijn. Hoogstwaarschijnlijk wordt er geen pincode ingesteld naar OUTPUT , en digitalWrite zal mislukken. Als je buitengewoon veel pech hebt, kan een willekeurige pincode worden ingesteld op OUTPUT en digitalWrite kan deze worden ingesteld op HIGH .

Het is interessant dat er geen grenzen worden gecontroleerd. digitalWrite is sowieso zo traag en omvangrijk dat het niet onhandig zou zijn om compilatietijd of tijdcontroles in te voeren.
Als alle Arduino-pinnen zich in een aaneengesloten bereik bevinden, kunnen ze dan de poort niet vervangen == geen pincontrole door een pincode> BOARD_MAX_PIN-controle, waarbij de maximale pin van het bord is gedefinieerd in een of ander headerbestand op basis van een ifdef die het bord detecteert?
U vergeet dat 999 niet kan worden weergegeven in een `uint8_t`, dus het zou eerst worden geconverteerd naar 231 door de code die` pinMode` aanroept. Het eindresultaat is hetzelfde: `pinMode` en` digitalWrite` zullen onvoorspelbaar gedrag vertonen en kunnen willekeurige delen van het geheugen verstoppen als je ze aanroept met een slecht pin-argument.
#2
+4
TheDoctor
2014-02-17 21:50:12 UTC
view on stackexchange narkive permalink

In de standaardbibliotheken zijn er macro's die zijn ontworpen om pinnen om te zetten in poorten die bij de montage worden gebruikt. Hier zijn ze voor de Uno van Arduino 1.0.5:

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

Er zijn er meer, maar ik zal ze hier niet laten zien.

Ik denk dat je programma 14 zou aftrekken van 999, wat nog steeds te groot zou zijn voor het brogram. Het zou dan proberen te verwijzen naar het 985e element van de digital_pn_to_bit_mask_PGM -array, die slechts 20 elementen bevat. Dit zou hoogstwaarschijnlijk de Arduino verpesten door naar een willekeurige plek in het programma te wijzen.



Deze Q&A is automatisch vertaald vanuit de Engelse taal.De originele inhoud is beschikbaar op stackexchange, waarvoor we bedanken voor de cc by-sa 3.0-licentie waaronder het wordt gedistribueerd.
Loading...