PIC AVR 工作室別館 arduinoの館->TopPage->arduinoの構成

arduinoの構成

arduinoを構成する各構成要素について触れ、arduinoの全体像に迫りたいと思います。

arduinoの要素

当初、まだ私がarduinoに手を出してなかった頃、この辺りの点が良く解らないままだったので手が伸びなかったんですが、 いざarduinoを構成している各構成要素のことや、及びそれらを組み合わせた全体像が解ってくると、AVR好きの人にはとても 身近なもののように思えてくるのでは?という気がします。(私はそうでした)

さて、その構成要素ですが、私の感覚で大雑把に分けると以下の4つになります。(この分け方は公式見解ではありません。念のため)

それ以外にも、ハードウェアを拡張する各種「シールド」や、ユーザーが作って提供してくれている各種 「ライブラリ」、そしてこれらの情報を交換するための公式サイト上や 非公式の「コミュニティー」もarduinoに含めてよいかもしれません。

以下ではこれらの4つ+αについて、私の理解している範囲で文章にまとめてみたいと思います。 かなり私の興味や趣向に片寄った内容かもしれませんので、その辺りのバイアスを考慮してお読みください。

arduinoのハードウェア

まずは代表的なarduino-Diecimilaを例に

ハードウェアは、初期のものから徐々に進歩を辿っており、これを書いている時点で主流となっているのは 「arduino-Diecimila」という機器です。サードパーティーから発売されているマシンも最近はDiecimila互換を 謳っているものが多いです。なのでひとまずこれを念頭に書くことにします。

残念ながら手元にDiecimilaが無いんですが、勝手にどこかから写真を持ってきて使っちゃうのもまずいので、 写真掲載はひとまず諦めます。なので、まだ写真見たこと無い方は(多分居ないと思いますが)検索エンジンなどで 「Diecimila」と検索かけてみてください。公式サイトにも写真が掲載されているはずです。

arduinoはソフトもハードも「オープンソース」なので、サードパーティーから供給される互換品や 個人製作の自作品などの亜流もたくさんあるのですが、これら互換品でも基本的にはDiecimilaを意識した構成になっており、 大きな違いはないようです。

さて、arduino-Diecimilaのハードウェアは、28ピンAVRのAT-MEGA168を1個登載したボード上にPCとの 接続を行うためのUSB-シリアル変換ICや、CPUクロックを生成する16MHzのクリスタル、各種外部機器 (シールド等)と接続するためのデジタル入出力ピン、アナログ入力ピン、電源供給ピン、さらにはいざという時に ブートローダなどをISPで書き込むための6ピンISP端子、システムにリセットをかけるリセットボタンなどと いったもので構成されています。

うーん、やっぱり挿絵が全く無いのもアレなので、公式サイトで公開されているシリアル版の Arduino Single-Sided Serial Board (version 3)の写真を載せておきます。

これらの部品のうちarduinoの外観で特徴的なのは、上下2列のピンソケットかと思います。デジタル/アナログ/ 電源供給用の各種入出力用に設けられたピンソケットです。

これらのソケットは、ブレッドボードなどを使って他のICや機器と接続する時に信号線を引き出したりする時に 使われるのですが、それだけでなく、後述する各種「シールド」を接続する時にも 使われます。

このシールドとの接続に関する物理的サイズの互換性を保つため、初期のarduino以来ピンソケットのジオメトリは基本的に 変わっておらず、arduinoを新しいタイプに買い換えてもシールドを使いまわすことが出来るようになっているようです。

なおこれらの入出力端子は、後述する開発用言語からアクセスしやすいように、独特の名前が振られています。 なのでこれらの入出力端子の名称はAVR本来の入出力ピンの名称とは異なるので注意が必要ですが、多分誰にとっても arduinoの入出力端子名称の方が簡単でとっつきやすいと思います。いずれにしても、AVR用のほかの開発言語と 最も異なるのがこのピン名称だろうと思います。

その他のarduinoボード

arduino-Diecimila以外にもarduinoのボードはたくさんのものがリリースされているし、自作派のモノも含めれば無数の種類が存在します。

これらについて一つ一つ触れるわけにもいかないので、幾つかの切り口から眺めてみたいと思います。その切り口とは、

といった辺りになるかと思います。それぞれの切り口からarduinoのバリエーションを眺めてみます。

PCとの接続方式

arduinoとPCの間の通信はシリアル通信(一般には9ピンのRS-232Cと呼ばれているもの)のプロトコルがベースとなっています。 これは、初期のarduinoで採用された通信方式で、DiecimilaのようなUSB版についても踏襲されています。

もちろん外観を見ると判るように、DiecimilaはUSBでPCと接続するように変わっていますが、USB回線上を流れる信号の 「論理的な意味」がシリアル通信(RS-232C信号)相当となっているということです。DiecimilaなどUSB対応機には FT232RLというUSB-シリアル変換のICが登載されており、PC上からは一つのシリアル接続機器として扱われるからです。

シリアルコネクタ(一般には9ピンのRS-232Cといわれているもの)といえばいわゆるレガシー機器のため、 最近のPCではもはやコネクタが登載されていないものもあるという「時代の遺物」ですが、USB対応版であるDiecimilaなどでも 論理的な通信方式はこの変換ICを介すことでシリアル通信が使われています。

AVRやPICなどの一般的なマイコンはもともとこの「シリアル通信機能」が搭載されていることと、プロトコルが単純なために ソフトウェアが簡単に組めるといったメリットがあるので、今でも、そして今後もarduinoの環境ではこのシリアル通信機能が 使われていくものと思われます。

このシリアル通信機能は、ソースプログラム(arduinoではスケッチと呼ぶ)をコンパイルして出来た実行プログラムを arduinoにアップロードする際にも使われますし、実行時にはPCやその他の機器との間で通信を行うためにも使われています。 arduinoに登載されている通信機能の中では最も多用されている機能であるといえます。

いずれにしても、USB接続タイプであろうとシリアル通信タイプであろうと、流れる論理情報はシリアル接続時代から 変わっていないという訳です。まぁ、マイコン関係で使用する通信規格としては、論理信号にこの「シリアル通信」を利用していることの デメリットはあまりないかと思います。

一方、物理的にはシリアル版とUSB版では電源の取り方と言う点で差異があるかと思います。シリアル接続タイプの場合、 シリアルケーブルはその規格上信号線から電源が取りだせないため電源ソケットが別途設けられているのですが、USB接続タイプは USBケーブルから5V500mAまで電源が供給できるので配線がすっきりします。ただし、FT232RLというICは少々値がはります…。

というわけで、いまでもUSB接続タイプとシリアル接続タイプが存在しているのですが、予算と利便性、手持ちPCのI/F端子 を考慮して選択すればよいかと思います。互換性の問題は上記の通りありませんので。

なお、USBしか登載されていないPCでも、市販のUSBシリアル変換ケーブルなどを用意すればシリアルタイプを使うことが 出来ます。USB-シリアル変換ケーブルは秋月等で約1000円程度から売られています。

また、比較的新しい公式版arduinoの中でもarduino-miniやarduino-lily-padなどにはUSB変換ICが登載されていませんが、 Mini USB Adapterというアダプターを利用することでUSBタイプと同様に扱うことも可能です。 多分、秋月の「FT232RL USBシリアル変換モジュール」を使っても同様かと思います。

入出力のジオメトリ

先述のとおりarduinoのジオメトリ、つまり入出力端子のピン配置は初期型からDiecimilaに至るまで、ほぼ変更がありません。 正確には、arduinoボードに供給される電源の種類(9VのACアダプタやUSBなど)の違いによって微妙な差異はあるようですが、 デジタルI/Oピンやアナログ入力ピン、グランドピン、5V電源端子などは変更がありません。

初期のarduinoからDiecimilaに至るまで、そして多分今後も、これまでに公開された各種シールドとの互換性と保つために I/Fソケットのジオメトリ変更は行われないかと思います。

公式サイトでは、自作派の人が簡単にarduinoを自作できるようにEAGLE用のパターンファイルや部品一覧などが公開されていて、 部品を集めれば自宅で作れるようにもなっています。上記のシリアル版S3V3はそれを元に私が作ったものです。

上記の写真とDiecimilaなどを見比べてみてください。自作用に公開されている回路図でも上下2列の入出力端子はジオメトリに 互換性が保たれているのが判ると思います。

面白いところでは、SparkFanのskinnyやProといった小型タイプでも同じジオメトリになっています。(ただ、lily-padなど 3.3V版のarduinoでは5Vの代わりに3.3V出力になるようで、従来のシールドとは電気的な互換は無いかもしれません)

小型のarduinoたち

一方、上述のarduino-miniやarduino-lily-pad、さらにはarduino-nanoや各種サードパーティーの小型ボードのように、 シールドとの接続を一切考慮していないボードも存在します。これらはブレッドボードで回路を組むことや その他の環境で使うことを念頭に使われているので「シールド」という縛りにとらわれずに作られたものです。 このタイプには公式/非公式問わず様々なバリエーションがあります。stickDuinoのように直接PCのUSBポートに 差して使う事ができるようなユニークなものまであります。

それらは物理的には互換性はないのですが、ソフトウェア的もしくは電気信号的には互換性が保たれているので、 「小さくて可搬性が良くて、何より見た目がクールだ!」などといったメリットに魅せられた方はこちらのタイプを 選ぶとよろしいかという気がします。

ちなみにDiecimila等の入出力端子の配置は、一般的な1/10インチサイズ配線の並びとは微妙にズレているため、 これらの小型arduinoに各種シールドを繋いで使用するときにはかなり苦労するかと思います。ブレッドボード上でシールドに 配線を繋いだりなどの場合に…。上側のピンソケットが半キャラずらしみたいになってるんですよねぇ。

なお、私が最初にゲットしたarduino(互換)ボードはサードパーティー製 (マイクロファン製)の「reduino-nano」です。 このボードはブレッドボード上で遊ぶことを念頭に、USB接続機能も搭載された、よく出来たデザインです。

写真はreduino-nanoに秋月製の3D加速度計をつないで遊んでいるところです。赤いのがreduino-nanoです。小さくて、 しかもUSBi/fも登載していて、とても使いやすいものです。

登載しているAVRのチップ

初期のarduinoにはAT-MEGA8が登載されていましたが、その後AT-MEGA168が使われるようになり、Diecimilaも MEGA168が登載されています。

目下、公式版ではDiecimilaやNano、mini、Lily-Pad、そしてsparkfunなどのサードパーティー品に至るまで MEGA168登載品に代わっているようです。公式サイトで公開されている自作用回路(シリアル版)の解説文には MEGA8かMEGA168を使用する旨記載されていますが、特に理由の無い限りMEGA168を用いた方がよろしいかと思われます。

arduino-IDE上でボードの種類を選択しておけば、コンパイル時にプリコンパイラがMEGA168用もしくはMEGA8用に 自動で設定されるようになっており、AD変換やデジタルI/Oなどのペリフェラルがほぼシームレスに 使えるようになっているようです。ただし、最近公開された新しいライブラリ類については、その一部分はMEGA168でしか 動かないものも有るので、今から新たにボードを入手するのであればMEGA8搭載機をあえて選ぶ理由は無さそうに思います。

また、MEGA168には16kBのプログラムメモリが登載されていますが、MEGA8では8kBしか登載されていません。 しかもこのプログラムメモリのうち約2kB(1kワード)はブートローダ用に確保されてしまうため、ユーザーが 使えるのはその残りということになります。MEGA8ならユーザーメモリは約6kB、MEGA168なら14kBとなります。 MEGA8では少し長いスケッチを書くとメモリが足らなくなってしまう恐れがありますが、MEGA168ならメモリが足らなく なるようなことは滅多に無いかと思います。(長いスケッチを書くと、メモリ残量ではなく、多分別の問題にぶち当たる ことになると思います…デバッグツールの不足という問題に…)

ちなみにAVRの世代的に捉えると、MEGA8は第2世代、MEGA168は第3世代に分類できます(山根さんの分類による)。

第2世代と第3世代のAVRでは、内部レジスタファイルの定義名などについて考え方が変更されています。 第2世代AVRでは、各種ペリフェラルがチップ内に1個しか登載されてなければ、それを制御するレジスタファイルの名称は 単純に名称が振られているだけなのですが、第3世代からはペリフェラルが1個しか登載されていないチップでも、 他のチップ(複数個のペリフェラルが登載されている場合も想定される)との間でソースコードの可搬性を考慮し、 各ペリフェラルの制御用レジスタにも通番が振られています。

例えば、内蔵USARTのビットレートを制御するためのレジスタファイルを取り上げてみます。MEGA8ではUBRRH、UBRRL というタグ名になっていますが、第3世代AVRではUBRRxH、UBRRxLという具合に通番が振られます。xの部分がその通番です。 もちろん、MEGA168にUSARTは1個しか登載されていないのでxには「0」が充てられますが、この「0」を含んだタグ名を 使うことで、USARTを2個登載したMEGA128等で流用する際にもコードの修正を行わずに使いまわすことが出来るように なっています。

内部ではこのようなタグの違いをプリコンパイラが自動で判別してくれると言うわけです。

arduinoの基本機能や公開されているライブラリを使用する範囲内では、レジスタファイルのタグ名称を意識することは 殆ど無いと思いますが、MEGA8を使用する場合にはこれが原因でライブラリが使用できないことがあったり、もしくは 自分でライブラリを作成するという場合にはこのタグ名称の違いを意識していないと互換性の問題や不要なトラブルを 引き起こすことが想定されます。

クロック回路

arduinoのクロックには、通常16MHzのクリスタルが用いられています。MEGA168は最速20MHzのクリスタルを 使用することが出来るのにも関わらず、MEGA8時代から16MHzが踏襲されています。lily-padなどでは内蔵の8MHzクロック が適用されています。

なぜ20MHzではなく16MHzが踏襲されているのかについて公式サイトでは明言はないようですが、幾つかの理由が 考えられます。

一つには、タイマー関係の機能が挙げられるかと思います。標準機能として組み込まれているミリ秒の待ち時間を 作る処理「delay(ms)」関数や、外部ライブラリとして公開されているミリ秒単位でタイマー割り込みをかける処理 「MsTimer2」ライブラリなどです。

これらの各タイマー関係機能では、AVRに内蔵されているタイマー機能(timer0やtimer2)が使われています。

timer0やtimer2はカウンターの幅が8ビットのタイマーですが、プリスケーラを含めて1ミリ秒をカウントすることを 考えると、16MHzであれば8ビット幅で足りる一方、20MHzだと8ビット幅のカウント値では正確な1ミリ秒が 表現できなくなります。カウント値に近似値を用いるか、16ビット幅のtimer1に変更する必要が生じるのですが、 その場合いずれにしても従来のarduinoとの互換性問題が生じます。

一方、16MHzから20MHzにクロックアップしても、せいぜい2割程度しか速度は上昇しませんが、 体感的には微々たる物です。微々たる物のために互換性を失うことを考えれば、互換性を優先するという判断が 働いたのではないかという想像ができます。

現実問題、16MHzで処理能力が不足するということは殆ど無いのではないかと思います。

一方現在の5V版MEGAシリーズは最高で20MHzですが、3.3VのxMEGAシリーズは32MHz動作が可能であり、 プリスケーラの設定によっては8ビット幅のタイマーでも1ミリ秒を生成することが可能です。

将来、xMEGAシリーズがarduinoに使われることがあるとしたら、32MHz動作のものが標準になるかも しれません。…私個人の希望的観測ですが…

さて、arduino-miniやarduino-lily-padなどの小型のarduinoにはクリスタルを登載していないタイプもあります。 これらのクロック源は上述のとおりMEGA168に内蔵されたRCオシレータで、動作速度は8MHzです。

RCオシレータなので、クロックの精度という点では誤差が大きくなるのですが、3.3V動作可能である点と、 なによりもその小ささが魅力なタイプです。

なお、16MHz版でも8MHz版でも、arduino-IDEのメニュー→tool→boardで機種をきちんと設定しておけば、 プリコンパイラが自動的にクロック速度にあわせた実行プログラムを生成してくれるので、ボード間でスケッチを 使い回しする場合でもスケッチの手直しは基本的に不要です。

ただし、MEGA168を3.3Vで動作させる場合には5Vトレラントが保証されていません。MEGA168の入力端子に架けられる 許容最大電圧はVcc+0.5Vなので、3.3V動作時なら3.8Vまでしか架けられません。なので、miniやlily-padの 各入力端子に3.8Vを超える電圧を与えると故障してしまいます。ご注意。

統合開発環境 arduino-IDE

arduinoが単なるテストボードやCPUボードの類と大きく違う理由の一つは、この統合開発環境の存在でしょう。 そしてこの統合開発環境が後述する開発言語を包括し、そしてarduinoに内蔵されたブートローダと連携して 動作することによって、プログラム(スケッチ)の作成や実行を容易にしています。

arduinoの統合開発環境

arduinoの統合開発環境はProcessingをベースに作られています。 Processingについては詳説しませんが、ご興味のある方は wikipedeiaの解説をご覧ください。

arduinoの統合開発環境は、VisualStudioなどのような多機能なものではないので、 ちょっと触ってみればすぐに使いこなせるとは思いますが、まったくさわったことのないひとを想定して、 簡単な使い方を触れておきたいと思います。

統合開発環境の画面

パッと見、元になったProcessingの画面に似ています。(あたりまえですが)

これがarduinoの統合開発環境の画面です。赤い矢印で印をつけたところが良く使う機能なので、その部分について まとめておきます。

テキストエディター

まず図の真中の部分、「テキストエディター」と書いてあるところですが、ここに自前のプログラム(arduinoの場合 スケッチと呼びます)を記入します。編集機能としてはwindowsのnote padと大体同じような機能のテキストエディター です。コメント中には日本語(全角文字)も使用できますが、作成したスケッチを公開する前提であれば、できるだけ 半角英数字だけで記入した方がよろしいかもしれません。

コンパイルボタン(Verify)

左上に「コンパイルボタン」と書いてあるのが、入力したスケッチをコンパイルするボタンです。arduinoの場合、 コンパイルではなく「Verify」という表現が使われるのですが、多分、コンパイルを行うとエラーのチェックも 一緒に行われる(特に文法エラーなど)のでVerifyという表現が使われているものと思われます。

アップロードボタンと自動リセットについて

その右の方に「arduinoへのアップロード」とかかれているボタンは、コンパイルした実行ファイルを arduinoの実機にアップロードするためのボタンです。diecimila等の自動リセット機能対応の場合には このボタンをクリックするだけでarduinoに強制的にリセットをかけてブートローダ(後述)の起動をかけ、 実行プログラムをPCからarduinoにアップロードします。

自動リセット対応ではない機種では、arduinoボード上のリセットボタンを手動で押下後およそ10秒以内 (ブートローダの実行中)にこのアップロードボタンをクリックすることで、実行プログラムがアップロード されることになります。

アップロードされると再度ブートローダが10秒間動作するのですが、この時間手を触れずに待っていてください。 約10秒後にアップロードしたプログラムが実行開始します。

シリアルモニタとその表示/非表示ボタン

その右隣の「シリアルモニタ(表示/非表示)」と書いてあるボタンは、シリアルモニタ表示のオン/オフを 切り替えるボタンです。シリアルモニタというのは、arduino実機とPC側でシリアル通信を行う時に 使用するモノで、arduino実機から送られてきた通信内容を表示したり、PC側から入力した文字列をarduinoに 送ったりできます。

シリアルモニタは、基本的にハイパーターミナルやtera termなどの様なシリアル通信ソフトと 同じような機能を持っていますが、統合環境上からボタン一発で表示/表示を切り替えて使え、また プログラムのアップロードと同じケーブルを共用してarduino実機と通信が出来るので、 スケッチの作成~アップロード~実行時の通信機能がシームレスに行えて便利です。

通常は表示されていませんが、このボタンを押すことで表示されます。上の図は、このシリアルモニタが 表示されている時の図で、テキストエディターより下の部分がそれにあたります。arduino-IDEの起動時には このシリアルモニタは表示されておらず、IDEからのメッセージが表示されることになっています。コンパイル時の 結果や、エラーがあればそのエラーメッセージなどが表示されるのですが、モニタをオンにするとシリアル通信の 内容が表示されることになります。

シリアルモニターは大まかに言って3つの部分に分かれます。一つは通信速度を設定するところで、 図では9600baudと書いてある部分です。これは9600baud(この場合は9600bpsと同じ)の 速度でPCとarduinoの間で通信を行うことを示しています。

その右隣の白枠は、PC側からarduino宛に送信するための文字列(ascii文字)を手入力するための テキストボックスです。ここに適当な文字列を入力し、その右の「send」ボタンを押すと、PCから arduino宛に文字を送信します。

その下の黒い部分は、arduino実機からシリアル通信で送信されてきた文字列を表示するエリアです。

スケッチの保存/呼び出しなど

上記の機能以外にも、作成したスケッチを保存したり、保存しておいたスケッチを呼び出したりするボタンも 有るのですが、これらはwindows標準のメニューバーから操作した方がわかりやすいですし、一般的なwindowsソフトと一緒なので、 操作方法については説明を省きます。

ちなみに、windows用のIDEの場合スケッチのデフォルト保存先は「My Documents\Arduino」です。このフォルダのことを Sketchbookと呼び、スケッチを纏めて保存しておくところという扱いになります。

適当な名前を付けて保存の操作を行うと、このSketchbookのフォルダの下にその名前のフォルダが作成され、スケッチ自体や実行ファイル、 中間生成物など一式が保存されることになります。

スケッチそのものは拡張子がpdeというファイル名のテキストファイルなのですが、IDE上からは直接このpdeファイルを扱うことは無いので (プロジェクト単位で扱うので)、拡張子は特に意識する必要は無いと思います。

シリアルモニタの接続のための設定

シリアルモニターを使う際には事前にcomポートの設定が必要です。現実は、コンパイルした実行プログラムを アップロードするのもシリアル通信を使うので、シリアルモニタを使う以前にarduinoの設定を行った段階で設定済みと 思いますが…。

設定方法ですが、メニューバーからtool→serial portでarduinoを繋いでいるcomポートを選択するとで使用可能となります。 USB版のarduinoにはUSB-シリアル変換ICのFT232RLを登載しているので、arduino-IDEからは シリアル版と同じようにシリアル通信で接続することになります。

その他

シリアル通信機能は、arduino側で実行プログラムが実行している時に、PC(やその他のコンピューター)との 間でデータのやり取りを行う最もポピュラーな仕組みです。

また、シリアルモニターはarduinoの場合きちんとしたシミュレーターや、実機デバッグ機能といったものが無いため、 自作したスケッチの動作確認を行う場合にはこのシリアルモニターを使うことが多くなると思われます。実行中に一部の変数を PC画面上に表示したり、PC側から動的にデータを送り込んだり…等など。ある程度簡単なスケッチであれば、 変数をこのシリアル通信機能を使って表示しながらデバッグを行うなどということも可能だと思われます。

逆に、このシリアル通信でデバッグできない規模や複雑さの開発を行う時には、arduinoではなくAVR-studio上で アセンブラやgccを使った開発を行う方が確実でしょう。

それ以外にも、arduino-IDEからAVR-ISPmkⅡ等を通してブートローダを書き込む機能も 付いているのですが、私が実際に試してみたところ、arduino-IDEからUSB上のAVR-ISPmkⅡが 上手く認識できませんでした。なので私はIDE経由でブートローダを書き込んだことは有りません。 (AVR-StudioからAVR-ISPmkⅡ経由で書き込みました)

まぁ、Diecimilaなどを購入すれば最初からブートローダは書き込み済みですし、自作の場合でもAVR-ISPmkⅡ等を お持ちの方ならAVR-studio上から直接ブートローダ用のHEXファイルを直接書き込むことが出来るので、 あまり実質的な話ではないかと思われます。

開発言語の概要

arduino言語の簡単な生い立ち

arduinoの開発言語はwiringをベースに作られた一つの独立した言語です。 (wiringについては詳説を省きますが、AT-MEGA128登載の専用ボード上で動くgccベースの開発言語です)

wiringがそうであるように、arduinoの言語もgccをベースに作られているため、C言語やC++を使ったことのある人 には殆ど違和感無く使える言語だと思います。実際、有志で提供されている各種ライブラリの中身はgccベースでかかれている モノが多く、C言語でかかれたものが提供されていたり、オブジェクト指向を取り入れてC++の形式で かかれていたり…といった具合です。(ご興味のある方は一度ライブラリとして提供されている各機能の ソースプログラムを読んで見ると面白いかと思います)

C言語やC++などを使ったことの無い人にも簡単に扱えるような工夫が盛り込まれていますので、 これまでに何かしらのコンピューター言語を使ったことがある人にとってはgccをそれほど意識しなくても 簡単なスケッチは作成できるかと思います。

arduino言語の特徴

arduino言語は上述の通りgccをベースに作られた言語ですが、arduinoで開発を行う時の作業負荷を軽減するために 「デジタル入出力」「AD変換」「アナログ出力(PWM)」「シリアル通信」「時間管理(経過時間や遅延処理など)」 「外部ピン割り込み」「算術計算(浮動小数含む)」などは標準機能に取り込まれており、とても簡単に扱えるようになっています。

標準機能に取り込まれていないような各種ペリフェラルを扱うには、色々なライブラリが利用できます。 2線シリアルi/f(TWI)や、一定間隔で定期的に処理を行うためのタイマー割り込みなど、 通常フィジカルコンピューティングで使用するような機能は、既に大抵誰かの手によってライブラリが作られて 公開されています。

また変数の型についてはgccでもおなじみの整数型、浮動小数型、boolean型などが使えます。

初めて使う人にとってはそれほどgccベースであることを意識する必要はないでしょうし、逆にある程度使いこなすには それなりに本格的にgccを覚える必要もあるでしょうし、どちらにしてもここでgccを解説しても 中途半端にしかならないので、gccの説明は端折ります。

とはいえ、何らかの言語を弄ったことのある人にとってはひとまず簡単なスケッチを書くことは造作ないでしょうし、 C言語で1回でも何かプログラムを組んだことのある人ならそこそこ複雑なスケッチでも書けてしまうだろうと思います。

そしてgccを使ったことがある人にとってもarduinoの言語はとても容易に使うことが出来るよう工夫されているので、 ちょっとお試しにプログラムを組んでテストしてみたい時には、アセンブラやgccと比べて大きな戦力になるのでは ないかと思っています。

なお、自分でライブラリを書いてみたいとか、公開されているライブラリを解読したいという方であれば C言語とC++を理解しておくとよろしいかと思います。

ちなみにarduinoで書くプログラムをプログラムとは呼ばずに「スケッチ」と呼びます。確かに arduinoで何か作ろうとする時、プログラムを組むというよりは、単にやりたいことを列挙していく雰囲気で 出来上がってしまうような簡単さが感じられると思います。まさに「スケッチ」の感覚です。

arduino言語の実体

arduino-IDE上からコンパイルボタンをポチッと押すと、裏ではgccが働いてくれて、スケッチ(プログラム)を 実行プログラムに作り変えてくれます。

スケッチを構成する3つのモノ

arduinoのスケッチは大きくは3つの部分に分かれています。1つ目は冒頭の宣言部分…つまりライブラリの読み込みや スケッチ全体で共用するグローバル変数を定義する部分。2つ目は初期設定処理(実行時の最初に1回だけ行う処理を列挙)。 3つ目は処理の主要部分(何度も繰り返し処理しつづける部分)です。

宣言部分

1つ目の「冒頭部分」についてです。ライブラリの使い方については各種ライブラリの ところをご参照ください。ここでは端折ります。

変数の定義については他の言語と大きく異なるわけではないと思うので、細かい説明をしなくてもすぐにとっつけると思います。 変数の型+変数名で定義できます。変数名の右に”等号と初期値”を書き加えることで、変数に初期値を設定することも可能です。 整数型や浮動小数など一般的な型は当然ながら使えます。実際にスケッチを書いてコンパイルしてみて、エラーが出たら エラーメッセージを読んでいけばすぐに慣れると思います。

慣れが必要といえば配列の扱いあたりでしょうか…C言語系の配列なので。例えば2次元配列ならば要素の指定は y、xの順です。data[y,x]の様に。私、C言語系の言語でプログラム組むとき、今でも時々間違えます。(^_^)

初期設定処理とメイン処理

2点目の初期設定処理と3点目のメイン処理については、この部分はarduino言語を少し特徴付けている部分だという気がします。

これらはそれぞれ一つの処理の纏まり(C言語でいうと関数)として、以下のような書式で記述します。 初期設定処理の書式は以下のような感じ。

void setup() {

  ここに初期設定の処理を
  列挙していく

}

この { から } の間に書き連ねた命令が、実行時の冒頭で1回だけ実行されます。初期化処理に使われます。

そして3点目。メイン処理の書式は以下のような感じです。

void loop(void)
{

  ここに、実行時に繰り返し行う処理を
  列挙していく

}

ここに書いた処理は、何度も繰り返して実行されます。

サンプルスケッチ

簡単なスケッチを例にして、具体的に見ていきたいと思います。

いわゆるLEDピコピコなどと呼ばれる処理です。組み込み系コンピューターの世界では 「hello world」に相当するプログラムです。

デジタルピン13番(Diecimilaなどではボード上に標準で登載されているLEDに接続されています)に 約0.5秒おきでオンとオフの信号を出力するという内容のスケッチです。

int ledPin = 13;

void setup() {

  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  Serial.println("start");
}

void loop() {

  digitalWrite(ledPin,HIGH);
  delay(500);
  digitalWrite(ledPin,LOW);
  delay(500);
}

簡単に処理内容を補足します。まず宣言部分ですが、ledPinという名前で整数型の変数を定義し、初期値に13を設定しています。

初期化処理でledPinに相当する出力端子(=13番)を出力モードに設定しつつ、シリアル通信機能を速度9600ビット/秒 で初期化し、「start」という文字列を出力します。この文字列はarduino-IDEのシリアルモニタ上に表示されます。

そしてメイン処理ですが、ledPin(=デジタル13番)にHIGHを出力して500ミリ秒待ち、LOWを出力して500ミリ秒待ち を行います。そしてそれが終ったらまたメイン処理の冒頭に戻って、それを延々と繰り返します。

コンパイル機能の内部について補足

なお余談ですが、arduino言語で書かれたスケッチはプリプロセッサというものを通して一旦gcc用プログラムに変換され、 それをgccでコンパイルするという流れで処理されています。

アップロードボタンを押すと、各スケッチ用のフォルダ内にappletというフォルダが自動で作成されるのですが、 この中に拡張子がcppというファイルが作成されます。このファイルがそのプリプロセッサを通して作成されたgcc用プログラムそのものです。 試しに、先ほどのスケッチをコンパイルした際のgccソースを開いて見ましょう。(改行コードの都合、note padではなく word padで開いてみてください) こうなります。

#include "WProgram.h"
void setup();
void loop();
int ledPin = 13;

void setup() {

  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  Serial.println("start");
}

void loop() {

  digitalWrite(ledPin,HIGH);
  delay(500);
  digitalWrite(ledPin,LOW);
  delay(500);
}

int main(void)
{
	init();

	setup();
    
	for (;;)
		loop();
        
	return 0;
}

まぁ、ご覧の通りC言語系のプログラムそのものですね。一番下の方にmain関数がくっつけられていて、 その中から1回だけsetup関数が呼び出され、その後loop関数が無限ループで呼び出されているというのが見て取れます。

setup関数やloop関数は元のまま展開されていて、プログラムの先頭ではこのsetup関数やloop関数のプロトタイプ宣言が 行われています。

C言語系が得意な人にとってはこの辺りが解っていると、ちょっと込み入ったスケッチを書くときや自前でライブラリを 作成したりする時等に役立つのではないかと思います。トリビア的に頭の隅に置いておいて頂ければと…。

コンパイル時のボードの自動対応

arduino-IDEのメニューバーのtool→boardと辿っていくと、各種arduinoのボードを選択することが出来ます。 これらの中からボードを選択しておくと、コンパイラ自身がどのボード用にコンパイルをすればよいかを自動的に判断して 処理してくれます。

具体的には、プリプロセッサが各ボード毎に内部の定数などの設定を切り替えてくれます。

上記のgcc展開リストの1行目の#include "WProgram.h"で読み込まれる標準ライブラリ内や、公式サイトで公開されている 各種ライブラリ内において、自動的に機種を判定して然るべき定数などに設定するようライブラリが組まれています。

こうしたことで、本来はMEGA168コアタイプとMEGA8コアタイプ、もしくは5.5Vで16MHz動作のDiecimilaや3.3Vで8MHz動作のLily-Pad などで異なるはずの定数なども適宜自動的に切り替えられて、どのボードでも基本的には同じスケッチで同じ動作が得られるように なっています。

大抵これらのライブラリは上手く作られており、どのボードでも何も考えずにコンパイルが上手く通るのですが、 ライブラリによってはMEGA8版arduinoでは動作しない(コンパイルエラーとなる)モノ等も存在するので注意が必要です。

他の開発言語との比較

arduinoの開発言語はgccをベースに作られた言語であることについて触れました。このarduinoの開発言語を gccやアセンブラと比較してどの様な違いが有るのかを見比べてみたいと思います。

arduinogccアセンブラ(arduinoに関するコメント)
理解しやすさ×さすがに簡易化された言語体系
設計自由度簡易言語とは表裏一体…やむなし
ハードウェア接続性フィジカルコンピューティングの目標なのである意味当然か
デバッグ容易性×ソフトウェアシミュレータやICEが使えない
初期投資本体とUSB(かシリアル)ケーブルだけ有ればアップロードが可能
CPU選択自由度×目下、AT-MEGA168かMEGA8しか選択できない

なんとなく個人的に興味のあるところについて触れてみました。これ以外の観点やこれ以外の言語など、いろいろ比較して みたいこともおありとは思いますが、ひとまず私の思いついたところを取り上げるに留めます。

総じていえるのは、簡易化・理解しやすさなどに力点が置かれていて、とっつきやすさが利点である反面、 ある程度縛りをかけることで簡易化をはかっているともいえるので、自由度が低かったり、本格的な開発には 少々物足らないという印象も否めない。そういった感じになるかと思います。

ブートローダ

ブートローダとセルフプログラミング

通常、AVRのチップに実行プログラムを書き込むためには、AVR-ISPmkⅡなどといったプログラマー機器が 必要となります。コンパイルして出来上がった実行ファイル(hexファイル)を、これらのプログラマー機器を使って AVR内部のプログラムメモリに書き込む必要があります。

一方AVRにはセルフプログラミングという機能が登載されており、プログラム自身がプログラムメモリ領域にデータ(もちろん プログラムの実体のこと)を書き込むことが可能になっています。この書き込む機能のことを「セルフプログラミング」と言います。

arduinoはこのセルフプログラミング機能を利用して、専用の書き込み機を使わなくても、実行プログラムを 書き換える機能を搭載しています。この機能を「ブートローダ」と言います。厳密に言うとちょっと言葉足らずかもしれませんが、 大体そんな感じです。

ブートローダは、arduinoの電源オン、もしくはリセット時に真っ先に実行されます。そしてシリアルケーブル経由で PCから実行プログラムがアップロードされてくるかどうかを約10秒間監視します。

10秒の間にプログラムがアップロードされ始めると、arduinoのブートローダはそのプログラムをPCから受け取り、 arduinoのメモリ内部に書き込んでいきます。そしてまたシステムをリセットしなおします。(ここでまた10秒待ちになる)

10秒待ってもPCからプログラムがアップロードされない場合は、既に書き込み済みの実行プログラムの起動を行います。

こういうブートローダという機能を搭載しているので、arduinoは専用のプログラマー機器を使わずに実行プログラムを アップロードすることが可能になっています。

Diecimilaなどの製品版arduinoを購入すると、このブートローダーが最初から書き込まれているので、 あとはUSBケーブルなりシリアルケーブルなりを用意すれば、簡単にPCと接続できるようになっています。

通常の起動スキーム

文章だと解り難いと思うので、漫画にしてみます。まずは通常の起動スキームについてです。電源オンやリセット信号が入ってきた 時の起動スキームです。

この図は、AVRのAT-MEGA168のメモリマップ(概略)と、AVRが起動するときの処理の流れを簡単に 示したものです。

まず①ですが、AVRの電源オンもしくはリセットがかかった時には、AVRはメモリの先頭(0x0000番地)に 処理が移されます。このメモリの先頭部分数十バイトには割り込みベクタというものが書き込まれることになっています。 アセンブラだろうとgccだろうと、この割り込みベクタが頭にくっ付いているのは一緒です。

この割り込みベクタの一番先頭は「リセット」時におけるジャンプ命令が書き込まれることになっているのですが、 このジャンプ先はユーザープログラムの先頭(正確には入り口…C言語で言えばmain関数)が指定されることになっています。 gccでもアセンブラでも一緒です。

その結果、②のようにユーザープログラムの先頭に強制的に処理が移されることになります。こうして ユーザープログラムが頭から実行される仕掛けになっています。

余談ですが、割り込みベクタにはリセット要因だけでなく、「タイマー割り込み」や「USART受信割り込み」 「ADコンバーター完了割り込み」「ピンチェンジ割り込み」などが有ります。これらの制御方法や具体的なアドレスなどについては arduinoの話からズレるので端折ります。お知りになりたい場合はデータシートなどをご参照ください。

ブートローダ経由の起動スキーム

もしブートローダーが有効になっていると、事態は少々変わってきます。

ブートローだが有効の場合、この図の橙色の部分と紫色の部分のように、実質2つの実行プログラムが同居した形になっています。 (ユーザープログラムとブートローダープログラム)

その際、まず電源オンorリセットの際には、①のとおり0x0000番地ではなく0x1C00(MEGA168版arduinoの場合) から処理が開始されることになります。(なおこのアドレスはバイト単位ではなくワード単位です)

この0x1C00にはブートローダ専用の割り込みベクタテーブルが置かれています。その一番先頭にはやはりリセット要因による 割り込みベクタが書き込まれているのですが、この場合はブートローダープログラムの先頭を指し示しているので、②のとおり ブートローダプログラムの先頭に処理が移されることになります。そして、この紫色の部分に閉じた狭い範囲内でブートローダープログラム が実行されることになります。

arduinoのブートローダは10秒の間、PC上のarduino-IDEからアップロードされるプログラムが届かないかを監視し、 もしアップロードされたら③のようにユーザープログラム部分にプログラムを上書き(つまりセルフプログラミング)します。

セルフプログラミングが終ったらまたブートローダーを①から再度実行し始めます。通常は2度続けてアップロードしない限り 10秒が経過して、ブートローダーは処理を終えます。

そしてようやく④の様に0x0000に処理が移ることになります。ここから先はブートローダが無効の場合と一緒の流れになり、 ⑤でアップロードされたユーザープログラムが実行開始されるというわけです。

このようにブートローダという機能を搭載することによって、arduinoは専用のプログラマー機器を使うことなく クリック一発で実行プログラムをアップロードすることが可能になっています。うーん、便利! しかも安上がり!

なお、この説明ではarduinoのブートローダを例に取ったのですが、AVRのブートローダはもう少し色々な 機能が搭載されています。ご興味のある方はdatasheetや 山根さんの本をご覧ください。

コンパイルで生成された実行プログラムとブートローダの関係

スケッチをコンパイルすると、拡張子がhexというファイルが生成されます。これが実行ファイルです。 AVR-studioだけでなく、PICのMPLABなどお使いの方にはおなじみのhexファイルです。

このファイルは、書き込むべき実行プログラムの中身とそれを書き込む先のアドレスを16進数で表記してテキストファイルに 収めたもの…いわゆる16進数表記のダンプリストです。

arduino-IDEの場合はインテル形式のhexファイルというフォーマットが使われています。

まぁ、フォーマット形式はどうでもいいのですが、実際に書き込まれるプログラムとその書き込み先アドレスが セットになっているということに少し意味がありまして…

arduinoの主要パーツであるAT-MEGA168というIC(もしくはMEGA8でもいいですが)は、通常の状態では リセット時にはアドレス=0番地から順々に実行されることになっています。

arduino-IDEでコンパイルされた実行プログラムも先頭は0番地になっていて、そしてその先頭部分には割り込みベクタテーブルが 数十バイト書き込まれています。そしてブートローダ側の処理が完了した後(プログラムのアップロード有り/無しに関わらず)、 処理が0番地に移り、通常のブートと同様に処理が開始されることになります。

さて、ここからが私がarduinoに惹かれることになった原因の一つです。

この場合の0番地にはやはり「リセット」要因による割り込みベクタ(アセンブラのJMP命令+ジャンプ先アドレス)が書かれているので そのベクタが指すアドレスに実行が移り、ユーザが作ったプログラムを頭から順々に処理をしていくことになります。

arduinoのブートローダを使った場合と、通常どおり0番地から実行される場合では、ブートローダが一旦起動されるという点を除けば 一緒なわけです。ユーザープログラムが共に0番地からスタートするという意味で。ということは…

arduino-IDE上でコンパイルして出来上がったhexファイルだけを取り出して、直接AVRのプログラマ (AVR-ISPmkⅡなど)でISP書き込みするとどうなるでしょうか?

→なんと、普通に実行できます。しかもブートローダの10秒間待ちを経ずに、ダイレクトに実行開始します。

このことは、開発環境としてarduinoの簡単な言語体系を活用しつつ、実行時にはブートローダーの約10秒間の プログラムアップロード待ちに付きあわされなくてもいいということを言っています。一通りテストが済んで品質が それなりに確保できたスケッチは、ブートローダーを介さずに実行プログラムとして使用する事ができるということです。

…あまりピンと来ないかもしれませんが、わたし的にはこのようにブートローダーをすっ飛ばして、 実行ファイルだけを書き込んで使えるということがとても魅力的に感じました。アセンブラやgccで作ったプログラムと 基本的に変わりなく扱うことが出来るので。

もちろん実行するためのCPUはMEGA168(もしくはMEGA8)に限定されますし、AVR-ISPmkⅡなどのプログラマー機器が 別途必要になるのですが、arduinoの簡単な言語仕様でスケッチを有効活用しつつ、arduino以外のボード (MEGA168やMEGA8を登載しているもの)でも書き込みさえすれば普通に実行出来てしまうというのは便利だなぁと思えて…。

自作派向け情報

市販品を手に入れなくても公式サイトにはEAGLEのパターンが公開されているので、MEGA168(もしくはMEGA8)や 周辺部品を自前で買ってきてarduinoを自前で作成することも簡単にできますし、究極的にはmakeブログの ここに紹介されているような 贅肉を取っ払ったarduino(uDuinoというらしい)まであるので、自作してみようという方は多いでしょう。

わたしも公式サイトで公開されているシリアル版を自作してみた一人です。

工作自体は特に難しいわけではないのですが、私がシリアル版のarduinoを作ったときに少々ハマってしまったのが ブートローダーの書き込みとfuseビットの設定関係です。

また、サードパーティーから発売されている互換ボード/準互換ボードを使うときに、ブートローダをどう設定すればいいのか について自分なりに調べてみたので、そのことについても記しておきたいと思います。

というわけで、その辺りについて以下に纏めておきます。

ブートローダーとfuseビットの書き込みについて

arduinoの実機が出来上がったら、あとはブートローダーとfuseビットを書き込めばarduino-IDEから arduinoとして扱うことができるようになります。

ブートローダーやfuseの書き込みには、AVR-ISPmkⅡなどのプログラマーが必要になります。 一旦arduinoになってしまえばシリアル経由でスケッチを書き込むことが出来るんですが、arduinoになる前は いわゆるAVRマイコンそのものなので、一旦AVR用の書き込み機が必要なわけです。

なので、自作する場合はAVR用の書き込み機をご用意ください。

ブートローダーの所在

ブートローダは、arduino-IDEをインストールするとhexファイルの形で展開されます。展開される先は以下の所です。

”arduino-0011\hardware\bootloaders\atmega168” (…バージョン0011の場合の展開先)

ここにあるhexファイルを、AVR用の書き込み機で書き込みます。

ここにはMEGA168を登載したarduino用のhexファイルが一式入っています。MEGA8版の場合はフォルダ名のところが ”atmega8”になったり、BlueTooth登載版やlily-pad版などもそれぞれのフォルダに格納されていますが、機器構成やクロック速度 がマッチするタイプのモノを適当に選んでおけばいいでしょう。少なくともクロック速度が合ってないと、アップロードするときの 転送レートが狂ってしまい通信できません。

fuseビットとlockビットの設定

hexファイルを書き込んだら、fuseビットとlockビットを設定します。設定する内容は3点です。

BOOTSZとBOOTRSTは「fuses」タブで、BLB1は「LockBits」タブで設定します。

AVR-studioからAVR-ISPmkⅡ経由で書き込むときのキャプチャー画面を記します。 (クリックで拡大表示します)

確認(Verity)

書き込みが終ったら、Verifyをかけてきちんと書けたか確認します。

なお、hexファイルを書いてからfuseビット、lockビットを書き込めば問題ないのですが、 その逆にfuseビット、lockビットを書いてからhexファイルを書き込むと、lockビットが 上書き消去されてしまうようです。

なので、先にhexファイルを書き込んでからfuse・lockビットを書き込んでください。

(もしかしたらAVR-ISPmkⅡだけの問題かもしれません。ちなみにAVR-ISPmkⅡは hexファイルとeepファイルを 書き込むときにも、先にeepファイルを書いてからhexファイルを書き込むとeeprom領域の内容が消えてしまうことが あったので…。他の書き込み機でも同じなのでしょうかねぇ???)

Verifyが出来たら、早速PCと接続してスケッチを書き込み→実行してみてください。PC上のarduino-IDEから 書き込みが出来ればokです。

一応試しに2回続けてアップロードしてみてください。fuseビットやlockビットに不備があれば、1回目は書き込めても 2回目に失敗することがありますので、是非。

arduino-IDEメニューからのブートローダ書き込み … 目下、成功してません

arduino-IDEのメニューバーから「Tools」→「Burn Bootloader」と辿ると、AVR-ISPmkⅡなど各種プログラマー機器が 選択できるようになっており、多分本来はこのメニュー上から直接ブートローダを書き込むことが出来るんだと思うのですが、実際に 使ってみようとすると

avrdude: usbdev_open(): did not find any USB device "usb"

というエラーが出てきて書き込めませんでした。公式サイトなどをウロウロさまよってみたのですが、それらしい情報は 見つからず…。

仕方なく、上記のとおりAVR-Studioなどからブートローダを書き込むことにしました。arduino-IDE上から 書き込めた方が当然楽なのですが、どうせブートローダは最初に1回だけしか書き込まないのでひとまず目をつぶることにします。

いつか暇な時にまた調べなおしてみたいと思います。

トラブルシューティング

私が以前自作した時に、ブートローダー関係で上手く行かなかった事例とその対応などについて書き残しておきたいと思います。 はんだ付けの成否などについてはここでは触れませんので、適宜テスターを当てたりして確かめてください。

fuseビットとlockビットの設定のタイミング

上記にも書いた様に、「hexファイルの書き込み」と「fuseビット・lockビットの設定」の作業順序を逆にすると、 1度だけはアップロードが出来るんですが、2度目からはブートローダーが無効になってしまって、リセット時に ブートローダーが起動しないという事象に遭遇しました。

ブートローダーが上書きされて消えちゃっているのか、それともリセット時にブートローダ先頭から 起動されなくなっているのかわかりませんが、いずれにしても古いユーザープログラムが先頭から再実行されてしまいます。 単純に$0000から再起動されてしまっているようです。

そんな時には、hexファイルを書き込んだ後にfuseビット・lockビットを書き込んでみてください。

サードパーティー製や自作arduinoの場合

私が最初に手に入れたarduino(互換機)は、マイクロファンのreduino-nanoなのですが、このボードのLEDは 一般的なデジタル13番ではなく、デジタル3番に接続されています。しかもこのLEDは負論理(HIGH出力で消灯、LOW出力で点灯) です。

reduino-nanoの場合はこのようにLED関係が独自仕様なので、その部分だけ修正されたブートローダがマイクロファンの サイト上で公開されています。

ブートローダのプログラムには、リセット直後にLEDを数回点滅させる処理が入っているのですが、 このように独自の拡張を行ったボードを使う場合には、LEDの位置を意識した処理にブートローダを書き換える必要がある わけです。(まぁ、LEDの点滅信号が必要ないとか、デジタル13番に何も繋いでいないというのであれば変えなくても構いませんが)

詳しくは、公式版のブートローダソースプログラムと、マイクロファン公開のブートローダソースプログラムを テキストコンペアツールなどでコンペアしてみてください。どの辺を修正する必要があるかすぐ判るかと思います。

…  準備中です  …