さて、準備が出来たところで実際にスケッチ(Arduinoで動くプログラム)を作ってみたい。まず目的として、前回紹介した回路のLEDを1秒間隔で点滅させてみることにする。ということで、List 1の様なものを書いてみた。

List 1:

#define  PIN_LED  3

void setup()
{
  pinMode(PIN_LED, OUTPUT);  /* 3番ピンを出力に設定 */
}

void loop()
{
  digitalWrite(PIN_LED, HIGH);  /* 3番pinに5V出力 */
  delay(500);                   /* 0.5秒待機 */ 
  digitalWrite(PIN_LED, LOW);   /* 3番pinを0Vに */
  delay(500);                   /* 0.5秒待機 */
}

Arduinoのプログラムは、(細かいところには若干違いはあるものの)概ねC言語と同じと考えて良い。厳密に言えばコメントに"//"が使えたりするあたり、微妙にC++も混じっていたりするが、C++のクラスとかオブジェクト指向の考え方は一切取り込まれていないので、まぁCと見做すのが妥当である。

プログラムで必須なのが、void setup()とvoid loop()である。前者は初期設定で、Arduinoのリセットが掛かった後、一度だけ実行される。後者は通常のC言語で言うところのmain()にあたる部分であるが、大きな違いとしてloop()は(電源が落ちるかリセットされるまで)繰り返し実行されることにある。なのでexit()やreturn()などを呼んでも無駄だし、そもそもexit()は用意されていない(return()はある)。また、main()の場合の様にargv/argcといった形で引数を渡す事はできない。もっともMCUに引数を渡す方法など無いので、動的にパラメータを渡すことが必要であれば、プログラムの中でシリアルポート経由などで受け渡しを行って設定する、ということになる。

ということでプログラムだが、これも極めて簡単である。まずsetup()の中だが、これは3番ピンを出力モードに設定するというものだ。pinMode()はArduinoが用意しているライブラリ関数で、これを設定することで3番ピンの出力をプログラムから制御できるようになる。

続いてloop()だが、こちらも一目瞭然である。digitalWrite()というのは、特定pinの出力を設定するもので、HIGHなら5V、LOWなら0Vにpinの電圧が設定される。各々設定後にdelay()(Win32で言えばsleep()にあたる関数で、一定期間待機するもの)を呼んで、明確に点滅するように設定している。この場合だと500msの待機なので、0.5秒点灯→0.5秒消灯→…を繰り返すという形な訳だ(Movie01)。

動画
Movie01:

スケッチを入力し終わったら、上側左端のVerifyボタンを押す(Photo01)。ここでエラーがあれば、下のステータス欄などに赤字で表示されるが、問題なければこの様にBinary sketch sizeが表示される。Arduinoの欠点の一つはこのプログラムサイズの大きさで、たったこの程度のプログラムなのに1KB近いメモリを占有するのだが、ここではその話は措いて置く。問題なれれば、次にUploadボタンを押すと、今作成したスケッチがArduino側に転送され、数秒後に点滅が始まるはずだ(Photo02)。

Photo01: ツールバーのボタンは左からVerify(プログラムの生成)、Stop(Verifyの中断)、New(新しいスケッチの作成)、Open(既存のスケッチを開く)、Save(スケッチをファイルに保存)、Upload(Verifyが済んだスケッチをArduinoに転送)、Serial Monitor(Arduinoと通信できるモニタを起動)となっている。

Photo02: 無事に転送が終わると、ステータス欄に"Done uploading."と表示される。

さて、今は単にOn/Offという感じの点滅であったが、もう少しじんわりと明るくなったり、暗くしたりというのはどうするか? ということで、回路はそのままでプログラムの方を手直ししてみる。今度はSketchをList 2の様に書き換えてみた(Photo03)。ここで利用するのはPWM制御である。

List 2:

#define  PIN_LED  3

void setup()
{
  pinMode(PIN_LED, OUTPUT);  /* 3番ピンをDigital Outに設定 */
}

void loop()
{
  int  period;                  /* PWMの周期 */

  for(period = 0; period < 256; period++)
  {
    analogWrite(PIN_LED, period);  /* 周期を増やしながらPWM出力 */
    delay(2);                      /* 2ms待機 */
  }
  for(period = 255; period > -1; period--)
  {
    analogWrite(PIN_LED, period);  /* 周期を減らしながらPWM出力 */
    delay(2);                      /* 2ms待機 */
  }
}

Photo03: プログラムサイズは更に増え、約1.2KB弱。まぁ最大32KBまで利用できるから、目くじら立てるほどの事ではない、という考え方もある。

PWM(Pulse Width Modulation)というのは、電子回路で広く使われている電圧制御のメカニズムである。例えば図1は連続して出力されている状態なわけだが、これを適当な周期(Arduinoの場合は約490Hz)で区切り、この周期の間でOn/Offを調整できるというものだ。図2はデューティー比80%の場合のケースで、この場合約2ms(周期が490Hzなので、1周期分の時間は約2msとなる)の80%はOn、20%はOffになっているわけだ。図3は逆にデューティ比20%の場合で、今度はOnが20%、Offが80%となる。白熱電球の様に、電源をOnにしてから点灯まで若干時間がかかるものにはこの方式だとうまく行かないのだが、LEDの様に反応が早いものであれば、このPWM制御を使ってOnの時間を連続的に減らしてゆくことで、見かけ上「段々暗くなってゆく」という制御が可能である。

図1: 図2: 図3:

ということでList 2である。ArduinoでPWM制御を使う場合、analogWrite()というライブラリ関数が用意されている。2つ目の引数がPWMのデューティ比にあたるもので、0だと0(つまり常時Offの状態)、255が100%(つまり常時Onの、図1の状態)となるわけだ。PWM出力が可能なPinは、Arduino Unoの場合3番/5番/6番/9番/10番/11番の6つに限られており、そんな訳で今回はLEDをあらかじめ3番Pinに接続した訳である。話をスケッチに戻すと、setup()はList 1と変更無しである。で、loop()はfor()を使ってperiodという変数を0→255に1づつ増やしながら、その値でPWM出力を行っている。各々2msづつのdelayを入れているので、0→255、つまり真っ暗から完全点灯まで約0.5秒で移行するわけだ。次いで、今度は255→0にperiodという変数を1づつ減らしながら同じ事をしており、今度は0.5秒の間に完全点灯→真っ暗に移行することになる。Movie02がその様子だが、Movie01と点滅の仕方が異なっていることがお判りだろうか。

動画
Movie02:

ちなみにRGB 3色のLEDをこのPWM制御を使って各々の輝度を調整することで、任意の色で発光させる、なんてことも可能である。

(続く)