Kompilator nie wykryje żadnego błędu, a kod zostanie skompilowany i wykonany. Dlatego, aby zobaczyć, co się stanie, musimy odkryć magię zakulisową. Aby podsumować, przejdź do końca.
Druga linia w twoim kodzie to miejsce magii i tam musimy się skupić.
pinMode(pin, OUTPUT);
Część pinMode
istotna dla tej dyskusji to:
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
}
(Pełną implementację można znaleźć w wiring_digital.c )
digitalPinToBitMask
Wydaje się , że tutaj używa się pin
do obliczenia bitu pośredniego. Dalsza eksploracja digitalPinToBitMask
to zdefiniowane makro, Arduino.h
którego definicją jest ten jednoliniowy:
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
Ta dziwnie wyglądająca jedna wkładka wykonuje bardzo proste zadanie. Indeksuje Pty element w tablicy digital_pin_to_bit_mask_PGM
i zwraca go. Ta tablica digital_pin_to_bit_mask_PGM
jest zdefiniowana w pins_arduino.h
lub mapie pinów dla używanej konkretnej płytki.
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),
...
};
Ta tablica ma w sumie 20 elementów, więc nie mamy szczęścia. 999 zindeksuje miejsce w pamięci flash poza tą tablicą, co prowadzi do nieprzewidzianych zachowań. Czy to będzie?
Nadal mamy inną linię obrony przed anarchią środowiska uruchomieniowego. Jest to następny wiersz funkcji pinMode
:
uint8_t port = digitalPinToPort(pin);
digitalPinToPort
prowadzi nas podobną ścieżką. Jest on definiowany jako makro wraz z digitalPinToBitMask
. Jego definicja to:
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
Teraz indeksujemy Pty element, digital_pin_to_port_PGM
którego tablica jest zdefiniowana w mapie pinów:
const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
PD, /* 0 */
PD,
....
PC,
PC,
};
Ta tablica zawiera 20 elementów, więc 999 znów jest poza zasięgiem. Ponownie to polecenie odczytuje i zwraca wartość z pamięci flash, której wartości nie możemy być pewni. To znów doprowadzi do nieprzewidzianych zachowań.
Jest jeszcze jedna ostatnia linia obrony. To jest if
sprawdzenie pinMode
wartości zwracanej digitalPinToPort
:
if (port == NOT_A_PIN) return;
NOT_A_PIN
jest zdefiniowany jako 0 cali Arduino.h
. Tak więc, jeśli zwracany bajt z digitalPinToPort
ma wartość zero, wówczas pinMode
po cichu zawiedzie i zwróci.
W każdym razie pinMode
nie może nas ocalić od anarchii. 999 ma doprowadzić do zguby.
TL; DR, kod zostanie wykonany, a jego wynik będzie nieprzewidywalny. Najprawdopodobniej żaden pin nie zostanie ustawiony na OUTPUT
i digitalWrite
zawiedzie. Jeśli zdarzy ci się wyjątkowo niefortunnie, wtedy losowy pin może zostać ustawiony na OUTPUT
, i digitalWrite
może to ustawić HIGH
.
uint8_t
tak, że najpierw zostanie przekonwertowane na 231 przez wywołanie kodupinMode
. Wynik końcowy jest taki sam:pinMode
idigitalWrite
będzie mieć nieprzewidywalne zachowanie i może sprać losowe części pamięci, jeśli nazywają je ze złym pin argument.W bibliotekach standardowych znajdują się makra przeznaczone do konwersji pinów na porty, które są używane w asemblerze. Tutaj są dla Uno z Arduino 1.0.5:
Jest ich więcej, ale nie pokażę ich tutaj.
Wierzę, że twój program odejmie 14 od 999, co wciąż byłoby zbyt duże dla brogramu. Następnie próbowałby wskazać 985. element
digital_pn_to_bit_mask_PGM
tablicy, który zawiera tylko 20 elementów. Najprawdopodobniej doprowadziłoby to do spieprzenia Arduino, wskazując losowe miejsce w programie.źródło