digitalRead()

概要

digitalRead()は、指定したピンがHIGHなのかLOWなのかを返します。指定したピンのポートに対応するレジスタのビットの値が1であればHIGH、0であればLOWです。

レジスタは、PORTBとPORTC、PORTDの3種類あります。それぞれのレジスタはArduino Unoのピンと以下のように対応しています。Axはアナログピン、Dxはデジタルピンです。初期値は0(LOW)です。

PORTB
ビット76543210
ピン--D13D12D11D10D9D8
PORTC
ビット76543210
ピン--A5A4A3A2A1A0
PORTD
ビット76543210
ピンD7D6D5D4D3D2D1D0

Arduinoのピン番号からATmega328Pのレジスタに変換する大まかな手順は以下の通りです。

digitalRead()は、入力したピン番号が、どのポートレジスタのどのビットに対応するかを求め、そのビットが0のときはLOW、1のときはHIGHを返すプログラムです。

digitalRead()のリファレンスはこちらをご覧ください。

ソースコード

digitalRead()は、hardware/arduino/avr/cores/arduino/wiring_digital.c に定義されています。以下に全ソースコードを示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
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;
}

入力はpinで、uint8_t型の変数です。ピンの状態により、HIGHもしくはLOWを返します。

まず、pinに対応するタイマを求めます。ATmega328Pのデジタルピンの中には、タイマに対応しているピンがあります。これは、PWM出力に利用されています。

3
        uint8_t timer = digitalPinToTimer(pin);

digitalPinToTimer()は、hardware/arduino/avr/cores/arduino/Arduino.h で定義しているマクロです。ピンがタイマに対応している場合はタイマ名が返ってきます。対応していない場合は、NOT_ON_TIMERが返ってきます。

次に、pinに対応するビットマスクを求めます。

4
        uint8_t bit = digitalPinToBitMask(pin);

digitalPinToBitMask()は、hardware/arduino/avr/cores/arduino/Arduino.h で定義しているマクロで、上の表で示した各ピンに対応するビットを1にした値が返ってきます。例えば、pinに13を指定すると、(DDRBの)D13に対応するビット5を1にした、0b00100000 という値が返ってきます。

次に、pinに対応するポートを求めます。

5
        uint8_t port = digitalPinToPort(pin);

digitalPinToPort()も、hardware/arduino/avr/cores/arduino/Arduino.h で定義しているマクロで、ピンに対応するポートを返却します。ピン番号が0から7のときはPD、8から13のときはPB、14(A0)から19(A5)のときはPCという値を返却します。PBとPC、PDは、hardware/arduino/variants/standard/pins_arduino.hで、それぞれ2と3、4と定義されています。pinが13のときはPBが返ってきます。

返ってきたportがNOT_A_PINであれば、この関数はLOWを返します。

7
        if (port == NOT_A_PIN) return LOW;

Arduino Unoでは、(入力値が正しい場合は)digitalPinToPort()はNOT_A_PINを返すことはありません。入力値が間違っている場合は、配列の範囲外を参照することになり、動作は未定義です。つまり、引数を間違えてはいけません。

ピンがタイマに対応している場合は、PWM出力を停止します。

 9
10
11
        // 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);

turnOffPWM()は、hardware/arduino/avr/cores/arduino/wiring_digital.cに定義されている関数で、指定したタイマを停止します。

その後、portをレジスタに変換し、bitとの論理積をとり、0以外であればHIGH、0であればLOWを返します。

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

portInputRegister()は、hardware/arduino/avr/cores/arduino/Arduino.hで定義しているマクロです。portをレジスタのアドレスに変換します。入力した値により、PINB・PINC・PINDのいずれかが返ってきます。portがPBのときはPINBが返ってきます。

ポートはアドレスなので、そのアドレスの内容を取得するために、*をつけて値を参照します。

最後に、bitとの論理積をとり、0以外であればHIGH、0であればLOWを返します。

バージョン

Arduino AVR Boards 1.8.6

最終更新日

March 21, 2023

inserted by FC2 system