残像表示装置“POV”をプログラムしよう!




 今回はArduinoを使って空中にメッセージを表示する装置を作ります。

 LEDの光が目に残像を残す原理を利用したものです。この回路は、日本ではバーサライト、海外ではPOV(Persistent Of Vision=残像)と呼ばれることがあるようです。我々は短くて覚えやすいので「POV(ポヴ)」と呼んでいます。

写真を見れば、原理はだいたいわかりますね。暗闇で明滅するLEDの列を振ると、空中に文字や画像が浮かび上がって見えます。このLEDの明滅をArduinoでコントロールします

 まずブレッドボードの上にハードウエアを構築しましょう。

 Arduinoには20以上の端子があります。この端子をピン(pin)といいます。実際はピンではなくソケットや穴のこともありますが、端子の機能を説明するときは、ピンと呼びます。ピンの使い分けを把握することがArduino使いになる第一歩です。

現在の標準ボード“Duemilanove”の構造を簡略化した図です。ボードによってレイアウトは異なりますが、外部との接続の仕方は基本的に同じです

・デジタル入出力ピン

 HiとLowの2段階の電圧を出力したり、入力したりできるピンです。0から13までの14本あります。ただし、0と1はUSB経由の通信にも使われるので、ピンに余裕があるうちは空けておいたほうがいいでしょう。PWMと書かれたピンがいくつかあります。これはアナログ出力と兼用のピンです。1つのピンが複数の役目を担うようになっていて混乱の元ですが、数に限りがあるピンを有効に使うため、そのようになっています。

・アナログ入力ピン

 0から5までの6本がアナログ入力ピンです。0Vから5Vまでの電圧を1,024段階で読み取ることができます(電源が5Vの場合)。たとえば、2.5Vがピンにかかっているとすると、511という値が得られます。ADコンバータといわれる機能です。アナログ入力ピンは、プログラムで設定を変更するとデジタル入出力ピンとして使うこともできます。

・電源ピン

 Duemilanoveでは、GND(グラウンド)、5V、3.3V(基板上では3V3とプリント)が使用可能です。電源ピンの構成はボードによって異なり、5Vだけのものや、3.3Vだけのものもあります。Arduinoに回路を付け足すとき、このピンを電源とすることができます。

 上記以外のピンについては、はじめのうちは気にしないでいいでしょう。

 今回の回路では、電源ピンのGNDと5V、そしてデジタル入出力ピンの2~9を使います。

単純な回路ですね。LEDが並んでいるだけです。複雑な処理はソフトウエアの仕事です(とはいっても、今回はソフトウエアもシンプルです)。消費電力を抑えるため、抵抗値は少し大きめになっています
64列のブレッドボードの端にUSB Boarduinoを載せ、反対側の端にLEDを並べました。ちょうどいい大きさです。振って使うものですので、部品や配線が飛ばないよう、必要ならばテープで固定してください

 回路を組み立てる過程では、USBケーブルを外しておきましょう。うっかり電源ラインをショートさせてしまうと、パソコンにダメージが及ぶ可能性があります。

 回路図どおりに配線されていることを確認してからUSBに接続します。この段階では何も起こりません。プログラミングにとりかかりましょう。

●ソースリスト

 人間が書いたプログラムの原文のことを、コンピュータが変換したプログラムと区別するために、ソースといいます。ソースコード、ソースプログラム、ソースリストといった言い方もあります。Arduinoではスケッチともいいます。

 「ニャ」を表示するPOVのスケッチは、データや空行も含めて44行です。

 上から順に説明していきましょう。

 「//」はコメントの印です。//以降の文字はコンピュータではなく人間が読むためのもので、プログラムの内容を説明する目的で書かれます。

----------------------------------------------------------
#define LEDPIN 2 // どのピンから使ったか(今回は2から9)
#define DELAYMS 4 // 点滅間隔(ミリ秒で指定)
#define BITMAPLEN 15 // ビットマップの大きさ(行数に同じ)
----------------------------------------------------------

 「#define」も、どちらかというとコンピュータより人間のために使われる機能で、ここでは3つの数値に名前を付けて、プログラムを読みやすく、また変更しやすくしています。このような数のことを定数といいます。

----------------------------------------------------------
byte bitmap[] = {
0b01000000,
0b01000010,
0b01000010,
0b01000010,
0b01000000,
0b00000000,
0b00000000,
0b00001000,
0b11111110,
0b00001000,
0b00101000,
0b00011000,
0b00000000,
0b00000000,
0b00000000
};
----------------------------------------------------------

 次はLEDに表示させるデータ(ビットマップ)を定義する部分です。17行ありますが、これで1つの文です。2進数で表示パターンを定義しています。各行の最初の「0b」という文字が2進数の印で、それに続き8桁の0と1が定義したいデータです。首を右に傾けて見ると、「ニャ」という文字が浮かんできませんか? 0が闇で1が光です。つまり、LEDの点灯・不点灯に対応しています。

----------------------------------------------------------
unsigned char pos = 0; // 現在のビットマップ中の位置
unsigned char i = 0;
----------------------------------------------------------

 先ほどのビットマップは配列という形式の変数でした。次は単純な変数を2つ定義しています。こちらは実行中に値が書き換わっていきます。

 ここまでが定数と変数の定義で、次からが処理を記述する部分です。

----------------------------------------------------------
void setup() {
// LEDが接続されたピンを出力に設定します
int pin;
for(pin=LEDPIN; pin<LEDPIN + 7; pin++) {
pinMode(pin, OUTPUT);
}
}
----------------------------------------------------------

 Arduinoのプログラムは必ずsetupとloopという2つのパートを持っています。

 setupで初期設定を行ないます。setupはArduinoボードが起動したあとに1度だけ実行されます。ここでは、LEDにつながっているピンを出力モードに設定しています。pinModeという命令を8回書いてもいいのですが、もう少しスマートに、for文を使って繰り返し処理をしています。

 setupが終わったら、loopへ処理が移ります。

----------------------------------------------------------
void loop() {
for(i=0; i<8; i++) {
// 表示する1byteから1bitを取り出してピンの状態に反映
digitalWrite(LEDPIN + i, (bitmap[pos] >> i) & 0b00000001);
}
if(pos++ == BITMAPLEN) pos = 0;
delay(DELAYMS);
}
----------------------------------------------------------

 loopはその名の通り、繰り返し何度も実行されます。Arduinoボードに電源が入っている間ずっと、無限にループし続けます。

 その性質を利用して、loopを1回通過するたびにビットマップを1行ずつ表示するようにプログラムしています。「ニャ」のデータは15行ありますから、15回繰り返したら先頭に戻るようになっています。この15という数字は定数BITMAPLENとして定義してあります。

 一瞬も止めずにループさせてしまうと、点滅が速すぎてメッセージを読み取れないのでdelayという命令で処理をわずかな間、停止しています。止める時間は定数DELAYMSです。我々の実験では4ミリ秒(ms)でいい感じでしたが、もう少し長くてもいいかもしれません。この値は皆さんの好みや環境に合わせて調整してください。

 digitalWriteの行は少し難しいですね。ビット演算というテクニックを利用しています。他人が書いたソースを読む立場で見ると、分かりやすいとはいえない書き方ですが、今回はコンパクトにまとめるため、こうしました。1byteから1bitを取り出す方法の1つ、くらいに覚えておいてください。

 さて、これでスケッチの解説は終了です。

 リストの通り入力したら、Verifyボタンを押してください。スケッチが正しく実行形式に変換できるかどうか(コンパイルできるか)をチェックします。

Verifyボタンを押したら、エラーが出ました

 コピー&ペーストするかわりに、手でソースを書き写した人はたぶんエラーに遭遇したと思います。このくらいの分量でも間違いなく打ち込むことはなかなか難しいことです。

 Arduino IDEのエラーメッセージは分かりやすいものとはいえません。英語が得意な人でも、意味を読み取りエラーの原因を特定するのは簡単ではないでしょう。ここがArduino環境の最大の欠点かもしれません。

 エラーが出たら、目を皿のようにしてスケッチを点検することになります。上の写真のエラーは、文末のセミコロン(;)をわざと1つ消すことで発生させました。セミコロンやカッコ、クオーテーションマーク等の書き忘れが一番ありそうなミスです。一度に何行も入力せず、少し入れてはVerifyする習慣をつけるといいかもしれません。疑わしい領域が狭ければ、間違いはすぐ見つかります。

Verify(コンパイル)が成功すると、出来上がったプログラムの大きさが表示されます。14,336byteが上限とありますので、まだまだ余裕がありますね
Upload to I/O Boardボタンで、プログラムをボードへ転送します。コンパイルが済んでいない状態でこのボタンを押すこともできます。そうすると、コンパイルと転送を続けて実行してくれます
USBのケーブルがぶらさがった状態でボードを振るのは危険かもしれません。USBケーブルを抜いて、代わりに電池で駆動することもできます。1.5Vの乾電池3本を、5VとGNDに接続しました。電池ボックスはブレッドボードの裏にとめると、握って振りやすくなります
うまくニャニャニャと表示されましたか?

 表示するメッセージは簡単に変更できます。

----------------------------------------------------------
#define BITMAPLEN 15 // ビットマップの大きさ(行数に同じ)
byte bitmap[] = {
 ……
};
----------------------------------------------------------

 上記の部分に「ニャ」と同じようにビットマップを定義し、その行数をBITMAPLENとして定義するだけです。長さは256行が上限ですが、そのくらいあるとかなり長いメッセージも表示できます。

「BREADBORDERS」の文字とダイオードの記号を書いてみました。ビットマップ定義は75行でした。もっと長くても大丈夫です
シャッタースピードを1秒~2秒くらいにすると、予想できないグラフィックが撮影できるでしょう。時間を忘れて楽しめます

 Arduinoを使うことで、ブレッドボーディングの可能性が拡大することが感じられたでしょうか。今回の作例は、LEDを光らせるだけの片方向的な使い方でしたが、センサーやパソコンと組み合わせることで、もっとインタラクティブな作品が実現可能です。

 Arduinoを使ったさまざまな事例は、公式サイトだけでなく、インターネットのあちこちで見ることができます。ぜひ、検索してみてください。また、武蔵野電波では、Arduinoの言語リファレンスとライブラリリファレンスの日本語訳を公開しています。活用してください。

 さて、24回に渡ってお届けしたブレッドボーダーズは、今回をもちましていったん終了です。しばしのお休みを頂いて、また新たな切り口で再スタートを切る予定です。ブレッドボードに対するこだわりを少し和らげてみてもいいかな、と考えていたり……。楽しみにお待ちいただけますと幸いです。それでは、また!

□関連記事
【12月18日】【武蔵野】かんたんマイコン「Arduino」の始め方
http://pc.watch.impress.co.jp/docs/2008/1218/musashino023.htm

バックナンバー

(2008年12月26日)


船田戦闘機、スタパ齋藤、上杉季明によるユニット。電子工作からバンド演奏までさまざまな活動を行なうが、各活動に共通するテーマは“電気が通ること”としている。電子部品・電子回路の玄人ではなく、それらに対して強い興味を抱いている。ブレッドボーダーズは、そんな立ち位置から電子部品・電子回路に触れていくプロジェクトである。


【PC Watchホームページ】


PC Watch編集部 pc-watch-info@impress.co.jp ご質問に対して、個別にご回答はいたしません

Copyright (c) 2008 Impress Watch Corporation, an Impress Group company. All rights reserved.