Fråga:
Vad händer när jag använder ett ogiltigt PIN-nummer?
Anonymous Penguin
2014-02-17 21:26:30 UTC
view on stackexchange narkive permalink

Relaterat till: Vad händer om det finns ett runtime-fel?

Den här frågan liknar den ovan, men det här är en alternativ situation:

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

Vad skulle hända i det här fallet? Kompilatorn kan fånga det men om du använde ett slumpmässigt tal skulle IDE fånga det?

Två svar:
#1
+9
asheeshr
2014-02-17 22:48:05 UTC
view on stackexchange narkive permalink

Kompilatorn upptäcker inte något fel och koden kompileras och körs. För att se vad som händer måste vi därför utforska magin bakom kulisserna. För en sammanfattning, hoppa till slutet.


Den andra raden i din kod är där magin kommer att hända och det är där vi behöver fokusera.

  pinMode (pin, OUTPUT);  

Den del av pinMode som är relevant för denna diskussion är:

  void pinMode (uint8_t pin, uint8_t mode) {uint8_t bit = digitalPinToBitMask (pin); // Den första instansen där stift används uint8_t port = digitalPinToPort (stift); if (port == NOT_A_PIN) return; // Gör något}  

(Den fullständiga implementeringen finns i wiring_digital.c)

Så här verkar digitalPinToBitMask använda pin för att beräkna en mellanliggande bit. Utforska vidare, digitalPinToBitMask är ett makro definierat i Arduino.h vars definition är detta enfodral:

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

Denna konstiga liner gör en mycket enkel uppgift. Den indexerar P th -elementet i matrisen digital_pin_to_bit_mask_PGM och returnerar den. Denna matris digital_pin_to_bit_mask_PGM definieras i pins_arduino.h eller pin-kartan för det specifika kortet som används.

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

Denna matris har totalt 20 element, så vi har tur. 999 kommer att indexera en minnesplats i flashminnet utanför denna array, vilket leder till oförutsägbart beteende. Eller kommer det?

Vi har fortfarande ett nytt försvar mot runtime-anarki. Det är nästa rad i funktionen pinMode :

  uint8_t port = digitalPinToPort (pin);  

digitalPinToPort tar oss längs en liknande väg. Det definieras som ett makro tillsammans med digitalPinToBitMask . Dess definition är:

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

Nu indexerar vi P det elementet i digital_pin_to_port_PGM som är en array definierad i pin-kartan:

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

Denna matris innehåller 20 element, så 999 är återigen utom räckhåll. Återigen läser detta kommando och returnerar ett värde från flashminnet vars värde vi inte kan vara säkra på. Detta kommer igen att leda till oförutsägbart beteende härifrån.

Det finns fortfarande en sista försvarslinje. Det är om kryssa i pinMode på returvärdet av digitalPinToPort :

  om (port == NOT_A_PIN) return;  

NOT_A_PIN definieras som 0 i Arduino.h . Så om den returnerade byten från digitalPinToPort råkar vara noll, kommer pinMode tyst att misslyckas och återvända.

I vilket fall som helst kan pinMode inte rädda oss från anarki. 999 är avsedd att leda till undergång.


TL; DR, koden kommer att köras och resultatet av detta blir oförutsägbart. Troligtvis kommer ingen stift att ställas in till OUTPUT och digitalWrite misslyckas. Om du råkar ha exceptionellt otur kan en slumpmässig stift bli inställd på UTGÅNG och digitalWrite kan sätta den till HÖG .

Det är intressant att det inte finns några begränsningar. digitalWrite är ändå så långsam och skrymmande att det inte skulle vara besvärligt att lägga in antingen kompileringstid eller körtidskontroller.
Om alla arduino-stift ligger i ett sammanhängande intervall, kunde de inte ersätta porten == inte en stiftkontroll med en stift> BOARD_MAX_PIN-kontroll, där kortets maximala stift definieras i någon rubrikfil baserat på någon ifdef som upptäcker kortet?
Du glömmer att 999 inte kan representeras i en 'uint8_t' så den skulle först konverteras till 231 av koden som kallar 'pinMode'. Slutresultatet är detsamma: "pinMode" och "digitalWrite" kommer att ha oförutsägbart beteende och kan stänga slumpmässiga delar av minnet om du kallar dem med ett dåligt pin-argument.
#2
+4
TheDoctor
2014-02-17 21:50:12 UTC
view on stackexchange narkive permalink

I standardbiblioteken finns det makron som är utformade för att konvertera stift till portar som används vid montering. Här är de för Uno från Arduino 1.0.5:

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

Det finns fler, men jag kommer inte att visa dem här.

Jag tror att ditt program skulle subtrahera 14 från 999, vilket fortfarande skulle vara för stort för brogrammet. Det skulle sedan försöka peka på det 985: e elementet i digital_pn_to_bit_mask_PGM -matrisen, som bara innehåller 20 element. Detta skulle sannolikt sluta skruva Arduino genom att peka på en slumpmässig plats i progmem.



Denna fråga och svar översattes automatiskt från det engelska språket.Det ursprungliga innehållet finns tillgängligt på stackexchange, vilket vi tackar för cc by-sa 3.0-licensen som det distribueras under.
Loading...