Điều gì sẽ xảy ra khi tôi sử dụng số pin không hợp lệ?


9

Liên quan đến: Điều gì xảy ra nếu có lỗi thời gian chạy?

Câu hỏi này tương tự như câu hỏi trên, tuy nhiên đây là một tình huống thay thế:

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

Điều gì sẽ xảy ra trong trường hợp này? Trình biên dịch có thể bắt được nó nhưng nếu bạn sử dụng một số ngẫu nhiên thì IDE có bắt được không?

Câu trả lời:


9

Trình biên dịch sẽ không phát hiện bất kỳ lỗi nào và mã sẽ biên dịch và thực thi. Do đó, để xem những gì xảy ra chúng ta cần khám phá phép thuật đằng sau hậu trường. Để tóm tắt, bỏ qua để kết thúc.


Dòng thứ hai trong mã của bạn là nơi phép màu sẽ xảy ra và đó là nơi chúng ta cần tập trung.

pinMode(pin, OUTPUT);

Phần pinModecó liên quan đến cuộc thảo luận này là:

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
}

(Việc thực hiện đầy đủ có thể được tìm thấy trong Wired_digital.c )

Vì vậy, ở đây, digitalPinToBitMaskdường như đang sử dụng pinđể tính toán một bit trung gian. Khám phá thêm, digitalPinToBitMasklà một macro được định nghĩa trong Arduino.hđó định nghĩa của nó là một lớp lót:

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

Điều này trông lạ lùng một lót làm một nhiệm vụ rất đơn giản. Nó lập chỉ mục phần tử thứ P trong mảng digital_pin_to_bit_mask_PGMvà trả về nó. Mảng digital_pin_to_bit_mask_PGMnày được xác định trong pins_arduino.hhoặc sơ đồ pin cho bảng cụ thể đang được sử dụng.

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

Mảng này có tổng cộng 20 yếu tố, vì vậy chúng tôi không gặp may. 999 sẽ lập chỉ mục một vị trí bộ nhớ trong bộ nhớ flash bên ngoài mảng này, do đó dẫn đến hành vi không thể đoán trước. Hay nó sẽ?

Chúng tôi vẫn có một tuyến phòng thủ chống lại tình trạng hỗn loạn thời gian chạy. Đây là dòng tiếp theo của chức năng pinMode:

uint8_t port = digitalPinToPort(pin);

digitalPinToPortđưa chúng ta theo một con đường tương tự. Nó được định nghĩa là một macro cùng với digitalPinToBitMask. Định nghĩa của nó là:

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

Bây giờ, chúng tôi lập chỉ mục phần tử thứ P digital_pin_to_port_PGMlà một mảng được xác định trong sơ đồ pin:

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

Mảng này chứa 20 phần tử, vì vậy 999 lại nằm ngoài phạm vi. Một lần nữa, lệnh này đọc và trả về một giá trị từ bộ nhớ flash có giá trị mà chúng ta không thể chắc chắn. Điều này một lần nữa sẽ dẫn đến hành vi không thể đoán trước từ đây.

Vẫn còn một tuyến phòng thủ cuối cùng. Đó là ifkiểm tra pinModegiá trị trả về của digitalPinToPort:

if (port == NOT_A_PIN) return;

NOT_A_PINđược định nghĩa là 0 in Arduino.h. Vì vậy, nếu byte trả về từ digitalPinToPortxảy ra bằng 0, thì pinModesẽ âm thầm thất bại và trả về.

Trong mọi trường hợp, pinModekhông thể cứu chúng tôi khỏi tình trạng hỗn loạn. 999 được định sẵn để dẫn đến kết cục.


TL; DR, mã sẽ thực thi và kết quả của việc này sẽ không thể đoán trước. Nhiều khả năng, sẽ không có pin nào được đặt thành OUTPUTdigitalWritesẽ thất bại. Nếu bạn vô cùng xui xẻo, thì một chốt ngẫu nhiên có thể được đặt thành OUTPUTdigitalWritecó thể được đặt thành HIGH.


Thật thú vị khi không có giới hạn kiểm tra. DigitalWrite dù sao cũng rất chậm và cồng kềnh, sẽ không khó để đưa vào thời gian biên dịch hoặc chạy kiểm tra thời gian.
Cyberg Ribbon

Nếu tất cả các chân arduino nằm trong một phạm vi liền kề, thì chúng không thể thay thế cổng == không phải là kiểm tra chân bằng kiểm tra pin> BOARD_MAX_PIN, trong đó pin tối đa của bảng được xác định trong một số tệp tiêu đề dựa trên một số ifdef phát hiện bảng?
EternityForest

Bạn đang quên rằng 999 không thể được biểu diễn trong một uint8_tvì vậy trước tiên nó sẽ được chuyển đổi thành 231 bằng cách gọi mã pinMode. Kết quả cuối cùng là như nhau: pinModedigitalWritesẽ có hành vi không thể đoán trước và có thể ghi đè lên các phần ngẫu nhiên của bộ nhớ nếu bạn gọi chúng bằng một đối số pin xấu.
David Grayson

3

Trong các thư viện tiêu chuẩn, có các macro được thiết kế để chuyển đổi chân thành cổng, được sử dụng trong lắp ráp. Ở đây họ dành cho Uno từ 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)))

Có nhiều hơn, nhưng tôi sẽ không hiển thị chúng ở đây.

Tôi tin rằng chương trình của bạn sẽ trừ 14 từ 999, vẫn còn quá lớn cho chương trình. Sau đó, nó sẽ cố gắng trỏ đến phần tử thứ 985 của digital_pn_to_bit_mask_PGMmảng, chỉ chứa 20 phần tử. Điều này rất có thể sẽ kết thúc việc làm hỏng Arduino bằng cách chỉ ra một điểm ngẫu nhiên trong progmem.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.