無効なピン番号を使用するとどうなりますか?


9

関連: 実行時エラーがあるとどうなりますか?

この質問は上記のものと似ていますが、これは別の状況です。

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

この場合はどうなりますか?コンパイラはそれをキャッチするかもしれませんが、乱数を使用した場合、IDEはそれをキャッチしますか?

回答:


9

コンパイラはエラーを検出せず、コードはコンパイルおよび実行されます。したがって、何が起こるかを確認するには、舞台裏の魔法を探る必要があります。概要については、最後までスキップしてください。


コードの2行目は、魔法が発生する場所であり、そこに焦点を当てる必要があります。

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にあります

したがって、ここでdigitalPinToBitMaskpin、中間ビットの計算に使用しているようです。さらに探索するのdigitalPinToBitMaskは、Arduino.h次の1行で定義されているマクロです。

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

この奇妙に見える1つのライナーは非常に単純なタスクを実行します。配列のP 番目の要素にインデックスを付けて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 番目の要素にインデックスを付け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、コードが実行され、これの結果は予測できません。ほとんどの場合、ピンはに設定されずOUTPUTdigitalWrite失敗します。非常に運が悪い場合、ランダムなピンがに設定されOUTPUT、にdigitalWrite設定される場合がありHIGHます。


境界チェックがないのは興味深いことです。とにかくdigitalWriteは非常に遅くてかさばるので、コンパイル時チェックと実行時チェックのどちらを行うのも厄介ではありません。
サイバーギボンズ2014

すべてのarduinoピンが隣接する範囲にある場合、port == notピンチェックをpin> BOARD_MAX_PINチェックに置き換えることができませんでした。ボード最大ピンは、ボードを検出するifdefに基づくヘッダーファイルで定義されていますか?
EternityForest

999はaで表すことができないuint8_tので、最初にコード呼び出しによって231に変換されることを忘れていますpinMode。最終的な結果は同じですpinModeし、digitalWrite予期しない動作を持つことになりますし、あなたが悪いのピン引数でそれらを呼び出す場合は、メモリのランダムな部分を壊しことができます。
David Grayson

3

標準ライブラリには、ピンをポートに変換するために設計されたマクロがあり、アセンブリで使用されます。ここにArduino 1.0.5のUno用があります:

#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)))

他にもありますが、ここでは表示しません。

あなたのプログラムは999から14を引くと思いますが、それでもbrogramには大きすぎます。次に、digital_pn_to_bit_mask_PGM配列の985番目の要素(20個の要素しか含まない)をポイントしようとします。これはおそらく、progmem内のランダムなスポットを指すことによってArduinoをねじ込むことになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.