Apa yang akan terjadi ketika saya menggunakan nomor pin yang tidak valid?

9

Terkait dengan: Apa yang terjadi jika ada kesalahan runtime?

Pertanyaan ini mirip dengan yang di atas, namun ini adalah situasi alternatif:

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

Apa yang akan terjadi dalam contoh ini? Kompilator mungkin menangkapnya tetapi jika Anda menggunakan nomor acak apakah IDE akan menangkapnya?

Penguin Anonim
sumber

Jawaban:

9

Kompiler tidak akan mendeteksi kesalahan dan kode akan dikompilasi dan dijalankan. Karena itu, untuk melihat apa yang terjadi, kita perlu menjelajahi keajaiban di belakang layar. Untuk ringkasan, lewati hingga selesai.


Baris kedua dalam kode Anda adalah di mana keajaiban akan terjadi dan di situlah kita perlu fokus.

pinMode(pin, OUTPUT);

Bagian yang pinModerelevan dengan diskusi ini adalah:

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
}

(Implementasi lengkap dapat ditemukan di wiring_digital.c )

Jadi, di sini, digitalPinToBitMasktampaknya digunakan pinuntuk menghitung bit menengah. Menjelajahi lebih lanjut, digitalPinToBitMaskadalah makro yang didefinisikan dalam Arduino.hdefinisi yang satu garis ini:

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

Kapal yang terlihat aneh ini melakukan tugas yang sangat sederhana. Ini indeks P th elemen dalam array digital_pin_to_bit_mask_PGMdan kembali itu. Array digital_pin_to_bit_mask_PGMini didefinisikan dalam pins_arduino.hatau pin map untuk papan khusus yang digunakan.

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

Array ini memiliki 20 elemen total, jadi kami kurang beruntung. 999 akan mengindeks lokasi memori dalam memori flash di luar array ini, sehingga mengarah ke perilaku yang tidak terduga. Atau akankah itu?

Kami masih memiliki garis pertahanan lain terhadap anarki runtime. Ini baris fungsi berikutnya pinMode:

uint8_t port = digitalPinToPort(pin);

digitalPinToPortmembawa kita di jalan yang sama. Ini didefinisikan sebagai makro bersama dengan digitalPinToBitMask. Definisinya adalah:

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

Sekarang, kita indeks P th unsur digital_pin_to_port_PGMyang merupakan array didefinisikan dalam peta pin:

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

Array ini mengandung 20 elemen, jadi 999 lagi di luar jangkauan. Sekali lagi, perintah ini membaca dan mengembalikan nilai dari memori flash yang nilainya tidak dapat kita yakini. Ini lagi akan mengarah pada perilaku yang tidak terduga mulai dari sini.

Masih ada satu garis pertahanan terakhir. Itu adalah ifcheck-in pinModeatas nilai pengembalian dari digitalPinToPort:

if (port == NOT_A_PIN) return;

NOT_A_PINdidefinisikan sebagai 0 in Arduino.h. Jadi, jika byte yang dikembalikan dari digitalPinToPortkebetulan menjadi nol, maka pinModediam-diam akan gagal dan kembali.

Bagaimanapun, pinModetidak dapat menyelamatkan kita dari anarki. 999 ditakdirkan untuk menghasilkan malapetaka.


TL; DR, kode akan dieksekusi dan hasilnya tidak dapat diprediksi. Kemungkinan besar, tidak ada pin yang akan disetel OUTPUT, dan digitalWriteakan gagal. Jika Anda mengalami nasib buruk, maka pin acak mungkin diatur ke OUTPUT, dan digitalWritedapat mengaturnya HIGH.

asheeshr
sumber
Sangat menarik tidak ada batas memeriksa. digitalWrite sangat lambat dan tebal, tidak akan canggung untuk memasukkan waktu kompilasi atau menjalankan pemeriksaan waktu.
Cybergibbons
Jika semua pin Arduino berada dalam rentang yang berdekatan, maka mereka tidak dapat menggantikan port == bukan pin periksa dengan pin> BOARD_MAX_PIN memeriksa, di mana pin papan max didefinisikan dalam beberapa file header berdasarkan pada ifdef yang mendeteksi papan?
EternityForest
Anda lupa bahwa 999 tidak dapat diwakili dalam uint8_tsehingga pertama akan dikonversi ke 231 oleh pemanggilan kode pinMode. Hasil akhirnya sama: pinModedan digitalWriteakan memiliki perilaku yang tidak dapat diprediksi dan dapat mengalahkan bagian memori acak jika Anda memanggilnya dengan argumen pin yang buruk.
David Grayson
3

Di perpustakaan standar, ada makro yang dirancang untuk mengubah pin ke port, yang digunakan dalam perakitan. Inilah mereka untuk Uno dari 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)))

Ada lebih banyak, tetapi saya tidak akan menunjukkannya di sini.

Saya yakin program Anda akan mengurangi 14 dari 999, yang masih terlalu besar untuk program ini. Kemudian akan mencoba untuk menunjuk ke elemen 985 dari digital_pn_to_bit_mask_PGMarray, yang hanya berisi 20 elemen. Ini kemungkinan besar akan berakhir mengacaukan Arduino dengan menunjuk ke titik acak dalam progmem.

Dokter
sumber