Arduinoの入出力と通信

はじめに

Arduinoに接続した機器から情報を読み取ったり、機器の制御を行うための基本となる、入出力と通信の方法についての説明です。

入出力と通信の種類

入出力

Arduinoでは、以下の入出力を行うことができます。Arduinoの機種によりできるもの、できないものがあります。利用できる場合でも利用できるピンの数が異なることもあります。

入出力の種類 説明 Uno Due ESP32
デジタル入力 ピンに接続した機器が出力するデジタル値を読み取る。
デジタル出力 ピンに接続した機器にデジタル値を書き出す。
アナログ入力 ピンに接続した機器が出力するアナログ値(電圧)を読み取る。
アナログ出力(PWM出力) ピンに接続した機器にアナログ値(PWM)を書き出す。
アナログ出力(DAC出力) ピンに接続した機器にアナログ値(電圧)を書き出す。 - ✔ / -

Arduino UNOには、デジタル入出力ピンは14本(PWM出力できるのはこのうち6本)、アナログ入力ピンは6本付いています。また、アナログ入力ピンはデジタル入出力ピンとしても利用可能です。

Arduino Dueには、デジタル入出力ピンは54本(PWM出力できるのはこのうち12本)、アナログ入力ピンは12本ついています。また、アナログ出力ピンが2本あります。アナログ入力ピン・アナログ出力ピンはデジタル入出力ピンとしても利用可能です。

ESP-32のチップでは、34本のGPIOピンがあります。ただし、いくつかのピンが使えないので注意が必要です。アナログ入力(ADC)はGPIOピンのうち18本で可能です。なお、前記は、ESP-WROOM-32の状況です。ESP32-S2やESP32-C3では異なります。

アナログ出力(PWM出力)は、PWMによる疑似的なアナログ出力です。アナログ出力(PWM出力)は、デジタル入出力ピンを利用します。Arduino Dueでは、DAC0とDAC1の2つのピンで、ESP-WROOM-32では、GPIO25とGPIO26の2つのピンで、本物のアナログ出力を行うことができます。

ESP-WROOM-32も、アナログ出力もサポートしています。Arduino core for the ESP32, ESP32-S2 and ESP32-C3 v2.0.1からはanalogWrite()もサポートしています(LEDCを利用しています)。それ以外に、analogWrite()相当の機能として、LEDC/Sigma Delta/DACといった機能が利用可能です。ただし、DACはチップによっては利用できないようです。

Arduinoボード デジタル入出力(PWM出力) アナログ入力 アナログ出力(DAC)
Arduino Uno 14本(PWM出力6本) 6本 0本
Arduino Due 54本(PWM出力12本) 12本 2本
ESP-32 34本 18本 2本
ESP-32-S2 43本 20本 2本
ESP-32-C3 22本 6本 -

参考

通信

上記の基本的な入出力に加えて、Arduino本体では以下に示すシリアル通信もサポートしています。

シリアル通信の種類 説明 Uno Due ESP32
UART 非同期シリアル通信
I2C 同期シリアル通信(2線式)
SPI 同期シリアル通信(4線式)

参考

割り込み

それ以外にも、ハードウェアを追加することで、EthernetやXBeeなどにより通信を行うことができます。また、ESP-WROOM-32は、WiFiチップを内蔵しているため、本体だけでWi-Fiを利用することができます。

入出力とは少し違いますが、ピンの入力状態の変化を検出して、関数を呼び出すこともできます。これを割り込みと言い、この時呼び出される関数を割り込みハンドラや割り込みサービスルーチンと呼びます。割り込みの種類は、ピンの入力状態の変化だけではなく、タイマによる割り込みなども存在します。

i
このページに記載しているコードは、断片なので、これだけでは動作しません。

入出力

デジタルとアナログそれぞれで入力と出力を行うことができます。

デジタル入力

ピンに接続した機器が出力するデジタル値を読み取ります。

digitalRead()を用いて、ピンの状態(ピンに接続している外部機器の状態)が0(LOW)か1(HIGH)かを知ることができます。デフォルトでは、デジタルピンは入力用に設定されているため、特に準備することなくデジタル入力に利用することができます。ただし、プログラムのわかりやすさを考慮すると、メモリがひっ迫するなどの理由がない限りは、適切に記述するのがいいと思います。

!
外部機器が出力する値をLOW/HIGHと判断する電圧の範囲は、チップによって異なります。異なる電圧の外部機器を接続する際は、適切にレベル変換を行う必要があります。さもないと、Arduinoや外部機器の故障の原因となります。

出力用に設定したデジタルピンを入力用に(再)設定するためには、pinMode()を使用します。digitalRead()の使用例を以下に示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const int digitalPin = 3;
int val = 0;
 
pinMode(digitalPin, INPUT);     // digitalPin(3番ピン)を入力モードに設定する。
val = digitalRead(digitalPin);  // digitalPinの状態を読み取る。valには、HIGHもしくはLOWが代入される。

if (val == HIGH) {
  // HIGHのときの処理
} else {
  // HIGHではないときの(= LOWのときの)処理
}

上記のプログラムでは、pinMode()でデジタルピンの3番を入力モードにしています。digitalRead()を実行した後、デジタルピンの3番の状態に応じて、valにHIGHもしくはLOWが代入されます。これにより、例えば、ピンに接続したスイッチが押されているのかなどを知ることができます。

digitalRead()以外にも、shiftIn()pulseIn()を使ってデジタルピンから入力することもできます。

デジタル出力

ピンに接続した機器にデジタル値を書き出します。

digitalWrite()を用いてピンを0(LOW)か1(HIGH)に設定することができます。デフォルトでは、デジタルピンは入力用に設定されているため、出力に用いる際には、pinMode()を利用して設定を変更しておく必要があります。digitalWrite()の使用例を以下に示します。

1
2
pinMode(LED_BUILTIN, OUTPUT);     // LED_BUILTINを出力モードに設定する。
digitalWrite(LED_BUILTIN, HIGH);  // LED_BUILTINにHIGHを出力する。

上記のプログラムで、LED_BUILTIN(内蔵LEDが接続されているピン。Arduino Unoの場合は13番ピン)にHIGHを出力します。LED_BUILTINにはボード上のLEDが接続されているので、LEDが光ります。

digitalWrite()以外にも、shiftOut()を使ってデジタルピンに出力することもできます。

!
デジタル出力で取り出せる電流はあまり大きくはないので、接続する機器によっては、適切に外部電源を利用する必要があります。定格容量を超えるとArduinoが壊れる可能性があります。

アナログ入力

ピンに接続した機器が出力するアナログ値(電圧)を読み取ります。

analogRead()を用いて、アナログピンにかかっている電圧を知ることができます。知ることができるのは、Arduino Unoの場合、0から参照電圧の1024分の1023倍までの電圧で、この関数は0から1023の数値を返却します。0が0Vに、1024が参照電圧に相当します(が、返却されるのは1023までです)。以下のグラフは、参照電圧が5Vの場合のanalogRead()の戻り値と実際の電圧との関係を示しています。

以下に、analogRead()の使い方を示します。

1
2
3
4
const int analogPin = A0;
int val = 0;

val = analogRead(analogPin);  // analogPinの電圧を取得する。

これにより、valにアナログピンの0番の値が代入されます。

この値を実際の電圧に変換するためには、参照電圧を用いて計算します。求める電圧をV、analogRead()の返り値をval、参照電圧をVrefとすると、以下のように表すことができます。analogRead()の返り値が0のとき0V、1024のとき参照電圧となります(ただしanalogRead()の返り値の最大値は精度が10ビットの場合は、1023です)。

$$V = \frac{val \cdot V_{ref}}{1024.0}$$

実際にプログラムを書く際には、型に注意してください。上記の例では、Vをfloat型やdouble型、valとVrefをint型の変数として宣言しているときに、1024.0ではなく、1024を使ってしまうと、右辺の結果が左辺の型とは関係なく、int型になってしまい、小数点以下が切り捨てられてしまいます。

参照電圧は、analogReference()を用いて、(Arduino UNOの場合)5V、1.1V、外部入力の3種類から選ぶことができます。例えば、参照電圧を5Vに設定したときは、0Vから、約4.995Vまでを測定することができます。

analogRead()の返却値を実際の電圧に変換する別の方法として、map()を使う方法もあります。map()は、小数を扱えないので、電圧を、例えば、ミリボルト単位で表記して、以下のように計算することができます。

1
2
3
int V;

V = map(val, 0, 1024, 0, 5000);

Arduino Dueは、10ビットではなく12ビットの精度を持っています。ただし、デフォルトでは10ビットの精度に抑えられています。analogReadResolution()を利用することで、変換精度を変更することができます。この場合、実際の電圧に変換するには設定した変換精度を用いる必要があります。

i
変換のための数式を見てわかるとおり、analogRead()の出力は、参照電圧に依存するため、高い精度が必要な場合は、電源電圧を正しく測定したうえで、変換を行う必要があります。

アナログ出力

アナログ出力(PWM出力)

ピンに接続した機器にアナログ値(PWM)を書き出します。

Arduino Unoでは、デジタルピンの3番と5番、6番、9番、10番、11番には、PWM出力を行うこともできます。PWMとは、Pulse Width Modulationの省略で、HIGHとLOWとを交互に出力することにより、平均的な電圧を制御するための仕組みです。本当のアナログ出力が必要な場合は、D/A変換回路を利用する必要があります。analogWrite()の中で、指定したデジタルピンを出力モードに変更しているため、初期設定は不要です。

以下の図のように、HIGHをThigh時間、LOWをTlow時間の間隔で繰り返すと、結果として、出力される平均電圧Vは、$V = V0\times T_{high}/(T_{high}+T_{low})$となります。このとき、1周期の時間に対するHIGHの時間の比率 $T_{high}/(T_{high}+T_{low})$ のことを、デューティー比と呼びます。

ArduinoでPWM出力を行うにはanalogWrite()を使います。analogWrite()で指定するデューティー比は、0から255までの整数で、0%が0、100%が255に対応します。以下に、analogWrite()の使用例を示します。

1
2
int ledPin = 9;
analogWrite(ledPin, 200);  // ledPinデューティー比 200/255 で電圧を出力する。

Arduino Dueは、8ビット(255)ではなく12ビット(4095)までの値を設定することができます。ただし、デフォルトで利用できるのは8ビットです。analogWriteResolution()を利用することで、変更することができます。

アナログ出力(DAC出力)

ピンに接続した機器にアナログ値を書き出します。

Arduino Dueでは、DAC0とDAC1に対して、本物のアナログ出力を行うことができます。使い方はPWM出力と同じです。

ESP-WROOM-23では、DAC1とDAC2に対して、dacWrite()を使うことで、アナログ出力を行うことができます。ただし、チップによってはサポートされていないものもあるようです。

通信

Arduinoは、シリアル通信を利用した複数のプロトコルを提供しています。接続する機器が対応しているプロトコルを使い分けることになります。

UART

UARTは、Universal Asynchronous serial Receiver and Transmitterの略で、非同期シリアル通信を行うことができます。各デバイスは、送信(TX)と受信(RX)の2つの信号線を使います。TXとRXを接続することで、データの送受信を行います。通信は非同期に行われます。

Arduinoでは、ハードウェアの機能を利用したHardwareSerialとソフトウェアで実装したSoftwareSerialの2種類が用意されています。

UARTは、送信側と受信側は対等な関係です。

HardwareSerialはArduinoソフトウェアの本体に組み込まれています。Arduino Unoでは、HardwareSerialを利用するためのオブジェクトである「Serial」がデフォルトで定義されており、通信速度を設定するだけで利用できるようになります。

HardwareSerialはハードウェアの機能を利用しているため、特定のピンでしか利用することができません。他のピンでもシリアル通信を行うために、SoftwareSerialが開発されました。

SoftwareSerialはライブラリの形で提供されています。利用するピンが増えますが、HardwareSerialと比べると制約が少しきつくなっています。

UARTの簡単な使い方はこちら

I2C

I2Cは、Inter-Integrated Circuitの略で、SDA(Serial Data)とSCL(Serial Clock)2本の信号線を使って通信する同期型のプロトコルです。TWI(Two Wire serial Interface)と呼ばれることもあります。Arduinoでは、ハードウェアの機能を利用したWireライブラリによって実装されています。

I2Cは、一つのマスターデバイスと一つ以上のスレーブデバイスが通信を行うことができます。Arduinoはマスターになることもスレーブになることもできます。

利用するスレーブデバイスの選択は、スレーブデバイスに付与されたアドレスによって行われます。アドレスの設定は、SDAを通じて行われるため、接続するデバイス数に関係なく、2本の信号線を使います。

i
デバイスに付与されたアドレスでデバイスを制御(選択)するため、同一アドレスのデバイスを複数制御することはできません。

I2Cの簡単な使い方はこちら

SPI

SPIは、Serial Peripheral Interfaceの略で、CISO(Cotoroller In Peripheral Out)、COPI(Controller Out Peripheral In)、SCK(Serial Clock)、CS(Chip Select)の4本の信号線を使って通信する同期型のプロトコルです。Arduinoでは、ハードウェアの機能を利用したSPIライブラリによって実装されています。

SPIは、一つのマスターデバイスと一つ以上のスレーブデバイスが通信を行うことができます。Arduinoはマスターになることはできますが、スレーブになることはできません。正確には、SPIライブラリはマスターには対応していますが、スレーブには対応していません。自身でプログラムすれば、スレーブになることもできます。

利用するスレーブデバイスの選択は、Slave Selectによって行われます。CIPOとCOPI、 SCKは全スレーブデバイスで共有します。Slave Selectは、一つのスレーブデバイスに1本必要となり、スレーブデバイス間での共有はできません。このため、n台のスレーブデバイスを利用するときは、3+n本の信号線が必要となります。

割り込み

ピンの状態の変化に応じて、関数(割り込みハンドラ)を起動することができます。ただし、Arduino Unoでは、2番ピンと3番ピンだけが対応しています。Arduino Dueでは全てのピンが対応しています。

状態の変化として利用できるのは、以下の通りです。

種類 意味 備考
LOW ピンの値がLOWのときに割り込みを発生する。
CHANGE ピンの値が変化したときに割り込みを発生する。
RISING ピンの値がLOWからHIGHに変化したときに割り込みを発生する。
FALLING ピンの値がHIGHからLOWに変化したときに割り込みを発生する。
HIGH ピンの値がHIGHのときに割り込みを発生する。 Arduino Due、Zeroeのみ。

割り込みハンドラの登録には、attachInterrupt()を利用します。登録した割り込みハンドラを削除するには、detachInterrupt()を利用します。

割り込みハンドラとして利用できるのは、戻り値も引数も持たない関数だけです。

また、一つのピンには一つの割り込みハンドラだけを登録することが可能です。例えば、一つのピンにRISING用の割り込みハンドラとFALLING用の割り込みハンドラの二つを登録することはできません(二つ登録すると後から登録した割り込みハンドラが有効となるようです)。

まとめ

Arduinoの入出力操作に利用する関数を簡単にまとめると以下のようになります。

入力 出力
デジタル digitalRead() digitalWrite()
アナログ analogRead() analogWrite()

また、通信を簡単にまとめると以下のようになります。

通信方式 信号線数 同期/非同期 利用方法
UART 2 非同期 HardwareSerial, SoftwareSerial
I2C 2 同期 Wireライブラリ
SPI 4 同期 SPIライブラリ

割り込みは、以下のようになります。

登録 解除
利用関数 attachInterrupt() detachInterrupt()

バージョン

Hardware:Arduino Uno/Arduino Due/ESP-WROOM-32
Software:Arduino 1.8.16/Arduino core for the ESP32 v2.0.1

最終更新日

March 20, 2024

inserted by FC2 system