Arduinoで遊ぶページ
Arduinoで遊んだ結果を残すページです
プログラムの基本

プログラミング言語

Arduino上で動作するプログラム(Arduinoではプログラムのことはスケッチと呼びます)は、通常Arduinoソフトウェアを用いて作成します。Arduinoソフトウェアで利用するプログラミング言語はC++/Cです。Arduinoで利用する言語のことを「Arduino言語」や「Arduino programming language」、「Arduino Language」という表現をされることもありますが、「Arduino言語」の実体は、Arduino用のAPI(C++のクラス、Cの関数)を追加したC++/C言語です。

Arduino用のAPIは、AVRマイコン等の操作に必要な、レジスタ操作などを隠蔽し、簡単にプログラムを書くための機能を提供しています。

APIが用意されていることに加え、Arduinoソフトウェアは、簡易なプリプロセッサの役割も果たします。詳細は、コンパイルプロセスにまとめています。初期のC++言語は、C言語へのコンバータとして実装されていましたが、そこまで大げさな変換ではなく、ヘッダファイル宣言や関数プロトタイプ宣言を追加する程度の変換です。

C++/Cコンパイラには、AVRアーキテクチャのチップ(例:Arduino Uno)の場合はavr-g++/avr-gccを利用し、avr-libcがリンクされます。ARMアーキテクチャのチップ(例:Arduino Due)の場合は、arm-none-eabi-g++/arm-none-eabi-gccを利用しています。ESP-WROOM-32の場合は、xtensa-esp32-elf-g++/xtensa-esp32-elf-c++を利用しています。このレイヤでは、AVR等のレジスタなどが直接見えています。

コンパイラがインストールされるため、avr-g++/avr-gccやarm-none-eabi-g++/arm-none-eabi-gccが提供するC++/Cの機能を利用することができます。残念ながらavr-g++にはlibstdc++が付属しないようです。arm-none-eabi-g++のほうには付属しています。

Arduinoソフトウェアには、Arduinoを制御するためのAPIや特定の機器向けのライブラリが付属しています(公式に配布されているライブラリ以外にも、Web上にはさまざまな機器向けのライブラリや使い方についての情報が公開されています)。

アプリケーションプログラムは、g++/gcc等の言語としての機能、avr-libcなど言語系が提供するライブラリ、Arduinoが提供するライブラリを利用することができます。もちろん、必要に応じて自分でライブラリを作成することもできます。

簡単に図示すると以下のようになります。

avr-g++/avr-gccが提供している、「直接プロセッサを操作するインターフェイス」も操作しようと思えば操作することもできます。ただし、Arduinoを使う意味がなくなってしまうので、どうしても必要な場合のときだけの利用に留めるのがいいと思います。

ファイルと利用される言語の関係

Arduinoのスケッチは、.ino という拡張子を持つファイルに記述します。

また、メインとなるスケッチは、スケッチの拡張子を除いた部分と同名のディレクトリ(フォルダ)に配置する必要があります。この点については、Arduino IDEが自動で調整してくれます。

それ以外にも、.cや.cppといったファイルを扱うこともできます。これらは、ライブラリを記述する際に利用します。

Arduinoで利用される言語はファイルの拡張子により異なるようです。特にライブラリや複数ファイルを取り扱う際には注意が必要です。

ファイルの拡張子 言語
.ino C++
.c C
.cpp C++

プログラムの基本構造

Arduinoのプログラム(スケッチ)では、2つの関数をユーザが定義(記述)する必要があります。一つはsetup()で、もう一つはloop()です。

setup()
プログラムの開始後に一度だけ実行される関数です。デバイスの初期化などを記述することが多いです。
loop()
setup()の実行後に、無限に実行され続ける関数です。デバイスの制御などを行います。

フローチャートで書くと、以下の通りです。

C++/C言語では、通常、main()という関数を定義する必要があります(Arduinoはフリースタンディング環境なのでmain()が存在する必要はありませんが)。Arduinoでは、Arduinoソフトウェア自身がmain()関数を定義しているため、利用者はmain()関数を定義する必要はありません。Arduinoソフトウェアによりmain()関数は以下のように定義されています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
int main(void)
{
        init();

        initVariant();

#if defined(USBCON)
        USBDevice.attach();
#endif

        setup();

        for (;;) {
                loop();
                if (serialEventRun) serialEventRun();
        }

        return 0;
}

setup()では、プログラムの最初で一度だけ実行する必要のある初期設定などを行います。たとえば、ピンの入出力モードを設定したり、外部に接続した機器の初期化などを行うプログラムを記述します。

loop()では、外部の状況把握、処理決定、機器操作等を行うプログラムを記述していきます。例えば、センサの値を読み取り、センサの値に応じて、他の機器を操作するプログラムを記述します。

setup()loop()で実際に行う処理がない場合でも、これらの関数を定義する必要があります。定義しない場合は、リンク時にエラーが発生します。

init()は、Arduino環境が定義している関数で、マイクロコントローラの初期設定を行なっています。この関数は利用者は定義してはいけません。正確には、定義してもエラーにはなりませんでしたが、タイマ関連の関数などが正しく動かなくなると思います。また、この関数はvoid init()と定義されているので、異なるシグネチャの関数であれば定義は可能ですが、トラブルの元のような気もするので、やめておいた方がいいと思います。自分で関数を作成を命名する際には注意が必要です。

setup()loop()に対して引数を渡すことはできません。これらの関数はそれぞれ、void setup(void)void loop(void)と宣言されています。

また、loop()を実行後、serialEventRun()という関数が呼び出されます。この関数は、シリアルバッファにデータがあるときに、serialEvent()という関数を呼び出す関数です。このため、serialEvent()という関数を定義しておけば、シリアル通信の処理を行うことができます。ただし、割り込みベースではなく、ループの中での検査なので、あまり有用ではないような気がします(必要ならば、自分でloop()の中に処理を書けばいいので)。

Arduino-1.5.2からは、新規ファイルを作成するときに、以下のコードが自動でエディタに挿入されるようになりました。

1
2
3
4
5
6
7
8
9
void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}

setup()の中で初期化を行い、loop()の中で実際の処理を記述するという性質上、グローバル変数を多用することが多くなると思います。また、プロトタイプ宣言を行う必要がありません。このため、C++/C言語によるプログラミングの習得を目的としてArduinoを利用することは、私はお勧めしません。あくまで、Arduinoを使って何かをするために利用するのがいいと思います。

Blink(Arduinoに付属のサンプルプログラム)

ここでは、インストールのページで出てきた、Arduinoソフトウェアにサンプルとしてついてきた、Blinkについて、簡単に解説します。

プログラムの仕様

Arduino Unoに搭載されているLEDを1秒周期で点滅させます。

プログラムの実装

初期化

LEDが接続されているピンを、出力モードに設定します。

Arduino Unoに搭載されているLEDは、デジタルの13番ピンに接続されています。13番ピンをデジタルの出力で利用するようArduinoに指示します。

この処理は最初に1回だけ行えばいいので、setup()の中で実行します。28行目のpinMode(LED_BUILTIN, OUTPUT);が該当する命令です。LED_BUILTINというマクロは、Arduinoの内蔵LEDが接続されているピンを示します。Arduino Unoの場合は、13と定義されています。

LEDの点滅

13番ピンをHIGHにすればLEDは点灯し、LOWにすれば消灯します。

1秒周期でLEDを点滅させるためには、以下を繰り返します。この処理は無限に実行するため、loop()の中に記述します。

  • 13番ピンをHIGHにする。
  • 1秒待つ。
  • 13番ピンをLOWにする。
  • 1秒待つ。

33行目のdigitalWrite(LED_BUILTIN, HIGH);で、13番ピンをHIGHにし、LEDを点灯します。34行目のdelay(1000);では、1000ミリ秒(=1秒)待ちます。35行目のdigitalWrite(LED_BUILTIN, LOW);では、13番ピンをLOWにし、LEDを消灯します。36行目ではまた1000ミリ秒待ちます。loop()自身は、Arduino自身が無限に実行するため、結果として、1秒周期でLEDが点滅します。

34行目と36行目の待ち時間を変更することで、LEDの点滅周期を自由に設定することができます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
  Blink

  Turns an LED on for one second, then off for one second, repeatedly.

  Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
  it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
  the correct LED pin independent of which board is used.
  If you want to know what pin the on-board LED is connected to on your Arduino
  model, check the Technical Specs of your board at:
  https://www.arduino.cc/en/Main/Products

  modified 8 May 2014
  by Scott Fitzgerald
  modified 2 Sep 2016
  by Arturo Guadalupi
  modified 8 Sep 2016
  by Colby Newman

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/Blink
*/

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}

バージョン

Hardware:Arduino Uno/Arduino Due/ESP-WROOM-32
Software:Arduino 1.8.12

最終更新日

May 1, 2020

inserted by FC2 system