จะเกิดอะไรขึ้นเมื่อฉันใช้หมายเลขพินไม่ถูกต้อง


9

ที่เกี่ยวข้องกับ: จะเกิดอะไรขึ้นหากมีข้อผิดพลาดรันไทม์?

คำถามนี้คล้ายกับคำถามข้างต้นอย่างไรก็ตามนี่เป็นสถานการณ์อื่น:

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

จะเกิดอะไรขึ้นในกรณีนี้? คอมไพเลอร์อาจจับได้ แต่ถ้าคุณใช้หมายเลขสุ่มไอดีจะจับมันได้หรือไม่

คำตอบ:


9

คอมไพเลอร์จะไม่ตรวจพบข้อผิดพลาดใด ๆ และรหัสจะรวบรวมและดำเนินการ ดังนั้นเพื่อดูว่าเกิดอะไรขึ้นเราต้องสำรวจเวทย์มนตร์เบื้องหลัง สำหรับการสรุปข้ามไปสิ้นสุด


บรรทัดที่สองในรหัสของคุณคือสิ่งที่เวทมนตร์จะเกิดขึ้นและนั่นคือสิ่งที่เราต้องมุ่งเน้น

pinMode(pin, OUTPUT);

ส่วนที่pinModeเกี่ยวข้องกับการสนทนานี้คือ:

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
}

(การติดตั้งที่สมบูรณ์สามารถพบได้ในwiring_digital.c )

ดังนั้นที่นี่digitalPinToBitMaskดูเหมือนจะใช้pinในการคำนวณบิตกลาง การสำรวจเพิ่มเติมdigitalPinToBitMaskเป็นมาโครที่นิยามไว้Arduino.hโดยคำจำกัดความของคำย่อคือ:

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

สายการบินเดียวที่ดูประหลาดนี้ใช้งานง่ายมาก มันดัชนีพีTHองค์ประกอบในอาร์เรย์digital_pin_to_bit_mask_PGMและผลตอบแทนมัน อาเรย์นี้digital_pin_to_bit_mask_PGMถูกกำหนดในpins_arduino.hหรือแผนที่พินสำหรับบอร์ดเฉพาะที่ใช้

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

อาร์เรย์นี้มีทั้งหมด 20 องค์ประกอบดังนั้นเราจึงไม่โชคดี 999 จะจัดทำดัชนีตำแหน่งหน่วยความจำในหน่วยความจำแฟลชนอกอาเรย์นี้จึงนำไปสู่พฤติกรรมที่ไม่สามารถคาดการณ์ได้ หรือจะ

เรายังคงมีแนวป้องกันอีกอันสำหรับการต่อต้านอนาธิปไตย มันเป็นบรรทัดถัดไปของฟังก์ชั่นpinMode:

uint8_t port = digitalPinToPort(pin);

digitalPinToPortพาเราไปในเส้นทางที่คล้ายกัน digitalPinToBitMaskมันถูกกำหนดให้เป็นแมโครพร้อมกับ คำจำกัดความของมันคือ:

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

ตอนนี้เราจัดทำดัชนี P THองค์ประกอบของdigital_pin_to_port_PGMซึ่งเป็นอาร์เรย์ที่กำหนดไว้ในแผนที่หมุด:

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

อาร์เรย์นี้มี 20 องค์ประกอบดังนั้น 999 จึงอยู่นอกช่วงอีกครั้ง อีกครั้งคำสั่งนี้อ่านและส่งคืนค่าจากหน่วยความจำแฟลชซึ่งมีค่าที่เราไม่แน่ใจ สิ่งนี้จะนำไปสู่พฤติกรรมที่คาดเดาไม่ได้จากที่นี่เป็นต้นไป

ยังคงมีหนึ่งบรรทัดสุดท้ายของการป้องกัน นั่นคือการifเช็คอินpinModeเกี่ยวกับค่าส่งคืนของdigitalPinToPort:

if (port == NOT_A_PIN) return;

NOT_A_PINถูกกำหนดให้เป็น 0 Arduino.hใน ดังนั้นถ้าไบต์ที่ส่งคืนจากที่digitalPinToPortเกิดขึ้นเป็นศูนย์แล้วpinModeจะล้มเหลวและกลับมาเงียบ ๆ

ไม่ว่าในกรณีใดก็ตามpinModeไม่สามารถช่วยเราให้พ้นจากความโกลาหลได้ 999 ถูกกำหนดให้ส่งผลให้เกิดการลงโทษ


TL; DR, โค้ดจะทำงานและผลลัพธ์ของสิ่งนี้จะไม่สามารถคาดเดาได้ เป็นไปได้มากว่าจะไม่มีการตั้งค่าพินOUTPUTและdigitalWriteจะล้มเหลว หากคุณเกิดขึ้นจะมีโชคร้ายล้ำแล้วขาสุ่มอาจได้รับการตั้งค่าให้OUTPUTและอาจจะตั้งค่าให้digitalWriteHIGH


มันน่าสนใจไม่มีการตรวจสอบขอบเขต digitalWrite นั้นช้าและใหญ่อยู่ดีมันจะไม่แปลกที่จะใส่ในการรวบรวมเวลาหรือการตรวจสอบเวลาทำงาน
Cybergibbons

ถ้าอาร์ดิโนพินทั้งหมดอยู่ในช่วงที่ต่อเนื่องกันพวกเขาจะไม่สามารถแทนที่พอร์ต == ไม่ใช่การตรวจสอบพินด้วยการตรวจสอบพิน> BOARD_MAX_PIN การตรวจสอบซึ่งมีการกำหนดพินสูงสุดของบอร์ดในไฟล์ส่วนหัวบางไฟล์
EternityForest

คุณจะลืมว่า 999 ไม่สามารถเป็นตัวแทนในuint8_tจึงจะแรกถูกแปลงเป็น 231 pinModeโดยการเรียกรหัส ผลลัพธ์ที่ได้จะเหมือนกัน: pinModeและdigitalWriteจะมีพฤติกรรมที่คาดเดาไม่ได้และอาจปิดบังส่วนหน่วยความจำแบบสุ่มถ้าคุณเรียกพวกเขาด้วยอาร์กิวเมนต์พินที่ไม่ดี
David Grayson

3

ในไลบรารีมาตรฐานมีมาโครที่ออกแบบมาสำหรับการแปลงพินเป็นพอร์ตซึ่งใช้ในการประกอบ ที่นี่มีไว้สำหรับ Uno จาก 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)))

มีมากขึ้น แต่ฉันจะไม่แสดงที่นี่

ฉันเชื่อว่าโปรแกรมของคุณจะลบ 14 จาก 999 ซึ่งจะยังใหญ่เกินไปสำหรับ brogram จากนั้นจะพยายามชี้ไปที่องค์ประกอบ 985 ของdigital_pn_to_bit_mask_PGMอาร์เรย์ซึ่งมีเพียง 20 องค์ประกอบ เรื่องนี้น่าจะจบลงด้วยการขัน Arduino โดยชี้ไปที่จุดสุ่มในโปรแกรม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.