はじめに
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本体では以下に示すシリアル通信もサポートしています。
参考
割り込み
それ以外にも、ハードウェアを追加することで、EthernetやXBeeなどにより通信を行うことができます。また、ESP-WROOM-32は、WiFiチップを内蔵しているため、本体だけでWi-Fiを利用することができます。
入出力とは少し違いますが、ピンの入力状態の変化を検出して、関数を呼び出すこともできます。これを割り込みと言い、この時呼び出される関数を割り込みハンドラや割り込みサービスルーチンと呼びます。割り込みの種類は、ピンの入力状態の変化だけではなく、タイマによる割り込みなども存在します。
入出力
デジタルとアナログそれぞれで入力と出力を行うことができます。
デジタル入力
ピンに接続した機器が出力するデジタル値を読み取ります。
digitalRead()を用いて、ピンの状態(ピンに接続している外部機器の状態)が0(LOW)か1(HIGH)かを知ることができます。デフォルトでは、デジタルピンは入力用に設定されているため、特に準備することなくデジタル入力に利用することができます。ただし、プログラムのわかりやすさを考慮すると、メモリがひっ迫するなどの理由がない限りは、適切に記述するのがいいと思います。
出力用に設定したデジタルピンを入力用に(再)設定するためには、pinMode()を使用します。digitalRead()の使用例を以下に示します。
|
|
上記のプログラムでは、pinMode()でデジタルピンの3番を入力モードにしています。digitalRead()を実行した後、デジタルピンの3番の状態に応じて、valにHIGHもしくはLOWが代入されます。これにより、例えば、ピンに接続したスイッチが押されているのかなどを知ることができます。
digitalRead()以外にも、shiftIn()やpulseIn()を使ってデジタルピンから入力することもできます。
デジタル出力
ピンに接続した機器にデジタル値を書き出します。
digitalWrite()を用いてピンを0(LOW)か1(HIGH)に設定することができます。デフォルトでは、デジタルピンは入力用に設定されているため、出力に用いる際には、pinMode()を利用して設定を変更しておく必要があります。digitalWrite()の使用例を以下に示します。
|
|
上記のプログラムで、LED_BUILTIN(内蔵LEDが接続されているピン。Arduino Unoの場合は13番ピン)にHIGHを出力します。LED_BUILTINにはボード上のLEDが接続されているので、LEDが光ります。
digitalWrite()以外にも、shiftOut()を使ってデジタルピンに出力することもできます。
アナログ入力
ピンに接続した機器が出力するアナログ値(電圧)を読み取ります。
analogRead()を用いて、アナログピンにかかっている電圧を知ることができます。知ることができるのは、Arduino Unoの場合、0から参照電圧の1024分の1023倍までの電圧で、この関数は0から1023の数値を返却します。0が0Vに、1024が参照電圧に相当します(が、返却されるのは1023までです)。以下のグラフは、参照電圧が5Vの場合のanalogRead()の戻り値と実際の電圧との関係を示しています。
以下に、analogRead()の使い方を示します。
|
|
これにより、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()は、小数を扱えないので、電圧を、例えば、ミリボルト単位で表記して、以下のように計算することができます。
|
|
Arduino Dueは、10ビットではなく12ビットの精度を持っています。ただし、デフォルトでは10ビットの精度に抑えられています。analogReadResolution()を利用することで、変換精度を変更することができます。この場合、実際の電圧に変換するには設定した変換精度を用いる必要があります。
アナログ出力
アナログ出力(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()の使用例を示します。
|
|
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本の信号線を使います。
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