てきとうなさいと べぇたばん

ArduinoのHIGHとLOWってどこで判断するのだろうか

可変抵抗を挟んでLOWとHIGHの境目(しきい値)を調べているところ。2.26Vではさすがにつかない。 電圧を下げると13番ピンが2.4Vくらいだったらつく。上げてる場合ではつかなかった。 可変抵抗を挟んでLOWとHIGHの境目(しきい値)を調べているところ。2.61Vではついてる。

ArduinoのdigitalRead関数

あれで、ちょっとふとしたことがあった。「HIGH」と「LOW」は通常、VccかGNDかで判断するが、その判断する電圧はどこで判断するのだろうか。

int level = digitalRead(3);

とりあえずソース漁る

Arduinoのソースを漁ってみた。16進数で記述されているがたしかに「HIGH」は1であり、「LOW」は0である。では、digitalRead関数の実装はどうなっているだろう。

https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring_digital.c#L165

int digitalRead(uint8_t pin)
{
    uint8_t timer = digitalPinToTimer(pin);
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);

    if (port == NOT_A_PIN) return LOW;

    // If the pin that support PWM output, we need to turn it off
    // before getting a digital reading.
    if (timer != NOT_ON_TIMER) turnOffPWM(timer);

    if (*portInputRegister(port) & bit) return HIGH;
    return LOW;
}

なるほど。digitalPinToPortとはなんだろうか。とたぐってみるとdefineでのマクロになっていた。

https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/Arduino.h#L169

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

なるほど。pgm_read_byteとはいったいなんぞや。

#define pgm_read_byte(addr) (*(const unsigned char *)(addr))

ということは、digital_pin_to_port_PGMを調べてみると、どうやらピンのアドレスを指定している。

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

これで1か0かを読める、ということか。…とするならばAVRには0か1かしか判断することができないということになる。ソフトウェアの限界だ。ハードウェアであるATmega328Pのデータシートを参照してみよう。

http://www.atmel.com/images/atmel-8271-8-bit-avr-microcontroller-atmega48a-48pa-88a-88pa-168a-168pa-328-328p_datasheet_complete.pdf

「31.8.9 Pin Threshold and Hysteresis」にあるグラフを見てみると、Vccが5Vの時にだいたい2.5Vを少し上回るくらいになっている。

http://www.musashinodenpa.com/arduino/ref/index.php?f=0&pos=1620この内容と大差ないかな。

digitalReadというものは論理的に見て0か1かをみるので、普段はこういうこと気にしないが、ぼくは気になっちゃったので。

参考サイトです。

参考にさせていただきましたありがとうございます。特にスレッショルド・レベル(threshold level)、日本語に訳すと「しきい値」がわかったおかげで分かりました。

http://hongera.sakura.ne.jp/whats_avr.shtml#INPUT

 デジタル回路の1と0の境目をスレッショルド・レベル(threshold level)といいます。日本語だと「しきい値」。このしきい値より上か下かで0か1のどちらかが認識されます。よって、入力に何もつながないで、なんだか分からない電位になっていたのでは困ります。しきい値より上にあるのか下にあるのかわからないからです。しかも、もし端子の電位がたまたましきい値の近くにあったなら、ちょっとしたノイズでしきい値をまたいで電位が上下します。0か1のどっちかに留まっているならまだしも、かってにON,OFFされてはたまったものではありません。よって予め電位をどちらかに引っ張っておくことにします。それがプルアップ(プルダウン)です。AVRではプログラムによって入力を個別にプルアップすることができます。よって外側に余計な回路をつける必要はありません。

あとで実験しようと思います。実験しました。