Arduinoで使用可能な言語や、Arduinoはどうやってプログラムを書きこむのだろう?などといった疑問を持つ方も多いのではないでしょうか?

この記事では、Arduinoで書いているコードが何の言語なのかを、実際のソースコードを確認しながら解説します。

だいき現役の車載組み込みソフトエンジニア車載マイコンのソフトウェアを業務でC言語を使って開発しています。応用情報技術者、C言語プログラミング能力検定1級。自宅の学習でもArduinoを使ってきました。
この記事で分かること

  • Arduinoで書いているのはC++。専用の別言語ではない
  • Arduinoでのプログラムコードの書き方について
  • Arduinoの学習はなにに役立つか?

読了 約10Arduino UNO R3で確認

Arduinoの言語はC++|「Arduino言語」という別の言語ではない

Arduinoのスケッチ(.inoファイル)に書いているコードはC++です。Arduino専用に作られた言語ではありません。

そのため「Arduino専用の言語を勉強する」ということはしなくても大丈夫です。勉強するのはC++と、そのもとになっているC言語のみを勉強しておけば大丈夫です。

公式記載の「Arduino programming language」について

公式のページは「使える関数と書き方の一覧」で、言語の成り立ちには触れていません。そのため別の言語に見えます。

Arduino公式のリファレンス(Language Reference)では、冒頭でこう説明されています。

Arduino programming language can be divided in three main parts: functions, values (variables and constants), and structure.

出典:Arduino Docs「Language Reference」(docs.arduino.cc/language-reference/

訳すと「Arduinoのプログラミング言語は、関数・値(変数と定数)・構造の3つに大きく分けられる」となります。実際にページを開くと、この3つが見出しになっていて、Functions の下に Digital I/O・Analog I/O・Time・Communication といった分類が並び、そこに digitalWrite()delay() が載っています。この分類のまま日本語で引けるようにしたものがArduino日本語リファレンス|UNO R3/R4で使用する関数の解説で、各関数が1回あたり何マイクロ秒かかるかを実機で測って併記しています。

注目したいのは、このページにC++という単語が一度も出てこないことです。使える部品だけが並んでいるので、読んだ側が独立した言語だと受け取るのは無理もありません。

実際には、この呼び名が指しているのはC++に、電子部品を扱うための関数をひとまとめに足したものです。

足されているのは、たとえばこういう関数です。

  • ピンの入出力に使う pinMode()digitalWrite()digitalRead()
  • アナログの読み書きに使う analogRead()analogWrite()
  • 時間を扱う delay()millis()
  • パソコンとの通信に使う Serial

これらはC++の標準機能ではなく、Arduinoが別途用意したライブラリ関数です。内容はC++で書かれているのみです。

Arduinoのプログラムは4つの層でできている

Arduinoプログラムは以下4つの階層構造で作られています。
コードを書く場所は「.ino」の中でコードを直接書くことができます。
「.ino」でArduinoのライブラリ関数などすべてを参照できる作りとなっているので別途「.c」「.h」のファイルを作成する必要はありません。

あなたがプログラムコードを書く場所.inosetup() と loop() の中身を書く

ここから下はArduinoが用意している

ArduinoのライブラリWiringdigitalWrite() や Serial の実体
C++とコンパイラavr-gcc隠れている main() はここ
マイコンのレジスタATmega328PPORTB などを直接読み書きして電気を動かす

ティール=あなたが書く範囲。グレーの3つは、書かなくても最初から動く。

初心者向けと言われる理由は、この積み上がりのうち一番上だけ書けば動くようにしてあることです。下の3つは、知らなくてもコードを書いてArduinoを操作できます。

Arduinoのコードにmain()が無いのはなぜか

無いのではなく、main()はArduino側に用意されていて、IDEから見えないだけです。

C言語やC++を少しでも勉強したことがあると、Arduinoのスケッチには見慣れない点があります。main()がありません。C++やC言語のプログラムはmain()から始まる決まりなので、ここに違和感を感じる人も多いと思います。

setup()とloop()を呼んでいるmain()の中身

そのmain()は、Arduinoをインストールすると一緒に入ってきます。実物を見てみます。

cores/arduino/main.cpp(Arduino公式のソースより該当部分を引用)

int main(void)
{
    init();

    initVariant();

    setup();

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

    return 0;
}
出典
Arduino AVR Core の cores/arduino/main.cpp(LGPL)より引用。#if defined(USBCON) の分岐など、話に関係しない行は省いています。手元のファイルは、Windowsなら次の場所にあります((ユーザー名) はご自身のものに読み替えてください)。

  • Arduino IDE:C:\Users\(ユーザー名)\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino\main.cpp1.8.6 はボードパッケージのバージョンなので、入れた時期で変わります)
  • PlatformIO:C:\Users\(ユーザー名)\.platformio\packages\framework-arduino-avr\cores\arduino\main.cpp

読むとそのままです。init()でマイコンの初期設定をして、setup()を1回呼び、あとはfor (;;)の中でloop()を延々と呼び続けているだけです。

loop()に書いた処理が繰り返される」という説明は比喩ではなく、本当に無限ループの中から呼ばれているということでした。

ここが分かると理解が早くなる
Arduinoはmain()が無いのではなく、main()を書かせない作りになっています。初心者がつまずきやすい「プログラムの入口」を、あらかじめ固定しているのみであり、実際にはC言語のルールに則りコードを書いている。

Arduinoを始める前に、C言語を勉強しないとダメなのか?

入門書を1冊やり切る必要はありません。変数・分岐・ループが分かれば動かせます。

ただし「まったく要らない」わけでもないので、どこまで要るのかの線を引いておきます。

どこまで知っていれば動かせるか

なぜ基本構文だけで足りるのか。Arduinoの基板と合わせて説明します。

Arduinoの基板のふちには、金属の端子がずらりと並んでいます。これがピンで、マイコンから外に電気を出したり、外から電圧を読んだりする出入り口です。1本ずつに番号がふってあり、13番ピン、7番ピンというように番号で指定します。

そしてArduinoには、「何番ピンをどうするか」を指定するだけの関数があらかじめ用意されていますdigitalWrite(13, HIGH)と書けば、13番ピンから電圧が出ます。そこにLEDをつないでおけば、LEDが光ります。

Arduino UNOの基板図。上辺に13番から2番までのデジタルピンが並び、13番だけが強調されている。下にdigitalWrite(13, HIGH)と書くと13番ピンに電圧が出てLEDが光る、という3段階の流れが示されている
図:ピンには1本ずつ番号がふってある。関数で番号を指定すると、そのピンから電圧が出る

マイコン本体には、ピンの状態を決めるためのスイッチのような設定項目(レジスタ)があり、本来はそこを直接書き換える必要があります。その手続きをまとめて肩代わりしてくれるのが、Arduinoのライブラリ関数です。そのため裏側を知らなくても、番号を指定するだけで動かせます。

先に動かして、詰まったところで都度調べていく方が早いと考えています。

ポインタを理解しないとダメか?

電子工作をしたいだけなら不要。組み込みエンジニアを目指すなら必須です。

Arduinoで電子工作をしたいだけなら、ポインタは要りません。ここまで見てきたとおり、ピンの操作は digitalWrite() のような関数が用意されていて、番号を指定するだけで動きます。センサーもモーターもライブラリが揃っているので、ポインタを知らないまま作品を完成させられます。

一方、組み込みエンジニアを目指すなら避けて通れません。理由は、マイコンの機能を決めているレジスタが、メモリ上の決まった番地(アドレス)に割り当てられているからです。たとえば「0x40000010番地がスイッチの状態を表す」といった対応がハードウェア側で決まっていて、そこを直接読み書きしないと機能を制御できません。

C言語でこれを書くと、次の形になります。番地を数値で指定し、それをポインタとして扱い、* で中身を読み書きします。

レジスタを直接読む書き方(一般形)

unsigned int *reg = (unsigned int*)0x40000010;

while (*reg == 0) {
    /* スイッチが押されるのを待つ */
}

つまり組み込みの世界では、ポインタは「便利な機能」ではなく、ハードウェアを触るための唯一の入口です。Arduinoのライブラリは、この手続きを関数の中に隠してくれているだけで、無くなったわけではありません。

目的別|Arduinoを触るにあたり必要な知識のまとめ

Arduinoはプログラムと電子回路の両方を扱うので、必要な知識も言語だけではありません。目的別に整理します。

目的 身につける知識 ポインタ・レジスタ
Arduinoで電子工作をしたい
LED・センサー・モーターを動かす
・C言語の基本構文(変数・分岐・ループ)
電子回路の基礎(電流・電圧・抵抗、オームの法則)
・デジタルとアナログの違い
・部品の仕様の読み方
不要
ライブラリの関数で動かせる
組み込みエンジニアレベルのC言語を身につけたい ・上に加えてポインタ
データシートの読み方(ピンとレジスタの対応)
必要
関数を使わず自分で操作するのが、いちばん学習になる

見落としやすいのが電子回路のほうです。LEDを1個光らせるだけでも、電流を抑える抵抗を選ぶのにオームの法則を使います。プログラムが正しくても、配線や部品の選び方を間違えると動きません。

私の見解
特にポインタはレジスタ操作の必須知識です。ただしArduinoは公式ライブラリがレジスタ操作を関数化してくれているので、レジスタを触らず、マイコンを制御できます。なのでポインタを理解せずともLチカや簡単なマイコン制御は可能となっています。

組み込みエンジニアレベルのC言語を身につけたい場合は、そのための練習問題を用意しています。次の順に進めてください。

  1. C言語 基礎ドリル(8テーマまとめ)で、変数・分岐・ループから順に固める
  2. C言語 ポインタの練習問題7問で、番地を指して読み書きする感覚をつかむ
  3. Arduino 基礎ドリル|レジスタから学ぶ組み込みマイコン入門で、実際にレジスタを操作する

Arduinoの学習は何に役立つか

作れるものが増え、プログラムと電子回路が同時に身につき、ほかのマイコンでも通用します。
作品づくり作れるものが増えるセンサーで測る、モーターで動かす、無線で飛ばす。組み合わせを覚えるほど作品の幅が広がります。

回路も学べるプログラムと電子回路が同時にArduinoは2つを切り離して扱えるので、回路に詳しくなくても始められます。触るうちに抵抗の選び方も付いてきます。

他機種へ応用ほかのマイコンでも通用する言語がC++なので書き方をそのまま持ち越せます。ピンの入出力やタイマーの考え方も共通です。

実際に作られているものには、こんな例があります。

  • 土の水分を測って自動で水をやる植物育成デバイス
  • 赤外線でエアコンを操作するリモコン
  • 超音波で距離を測る装置
  • モーターを制御するラジコンカーやロボット

さらに、表の2行目にあるレジスタを自分で操作するところまで進むと、もうひとつ得られるものがあります。

私の場合
Arduinoでレジスタ操作をやったことが、実務に入ってから一番役立ちました。ただし役立ったのは操作そのものより、「ポインタがなぜ必要なのか」を理解できたことです。本を読んでポインタの文法を覚えるのと、「この番地を指して書き込まないとピンが動かない」という場面に自分で当たるのとでは、納得の仕方が違いました。

入門書のポインタは「変数のアドレスを入れる箱」と説明されることが多く、文法としては正しいのですが、なぜそんなものが要るのかまでは分かりません。レジスタを触ると、番地を指す以外に方法がない場面が出てくるので、そこがつながります。

Arduinoでレジスタを直接読み書きしてみたい場合は、Arduino Lチカのやり方|digitalWriteからレジスタ操作まで練習問題9問で、同じLチカをdigitalWrite()とレジスタの両方で書く練習ができます。

まとめ

Arduinoで書いているのはC++です。「Arduino言語」という別の言語があるわけではなく、C++に電子部品を扱うための関数を足したものを、公式がそう呼んでいるだけでした。

main()が見当たらないのも、無いのではなくArduino側が用意していて書かせない作りのためです。実物のmain.cppを開けば、setup()を1回呼んでfor (;;)loop()を回しているだけだと分かります。

勉強の順番としては、レジスタを触らないうちは変数・分岐・ループで足ります。ポインタが必要になるのはレジスタを直接読み書きするときで、そこが境目です。

もうひとつ忘れやすいのが電子回路のほう。Arduinoはプログラムと回路の両方を扱うので、抵抗の選び方やデジタルとアナログの違いも一緒に必要になります。裏を返せば、その2つを同時に覚えられるということです。まずは動かしてみて、詰まったところで戻ってください。