カテゴリ
リンク

当サイトは、玄箱PRO (KURO-BOX/Pro)を中心とした組み込み、Linuxと電子工作を扱っています。
会社案内

情報セキュリティおよび個人情報の取り扱いについて


コメントとトラックバックは、spamを予防するために、編集担当が公開の作業をするまで非公開になっています。コメントはそれぞれ投稿した人のものです。

■はじめに
 今回は Windows, Linux (UNIX) のプログラミングした経験がある人に向けて Arduino の動作を解説します。
 Arduino ではプログラムのことをスケッチと呼んでいます。イメージをスケッチブックに描くように、気軽にアイデアをコンピュータで実行してみて欲しいという思いが入っているそうです。まずは、CPU の動作をおさらいします。

■CPU の動作は? ~Arduino のスケッチを理解する前に~
 Arduino とパソコン、玄柴、いずれのCPUも動作の基本は同じです。
1)命令(機械語)をメモリ(主記憶)から読み出して実行し
2)レジスタやメモリ(主記憶)を書き換え
3)次の命令に移って1から繰り返す
 機械語は、多くの場合、C/C++言語などの高級言語からコンパイラ、アセンブラ、リンカなどを使って生成されます。Microsoft の Visual C++、Arduino IDE など統合開発環境 (IDE) とよばれる開発環境では、個々のコンパイラやリンカをあまり意識せずに機械語が生成できるようになっています。

 パソコンや玄柴の場合には、電源が入ると CPU は内蔵のROMからプログラム(BIOS や uBoot)を読み出して実行します。BIOS や uBoot は、さらにファイルを主記憶に読み込み、Windows や Linux といった OS を起動します。OS が起動すると Windows や Linux では、CUI シェル (コマンドプロンプトや bash, tcsh など)から実行ファイル名を指定したり、GUI シェルからアイコンをダブルクリックすると、ファイル・システム上の実行ファイル(*.exeなど)から必要な機械語が主記憶に読み込まれ、実行されるようになっています。 複数の実行ファイルのプログラムを実行でき、一つが終了してもほかのプログラムが動作しています。タスク・マネージャ(Windows) や ps, top (Linux)で動作中のプロセス(プログラム)を見ると多くのプログラムが動作していることがわかると思います。

 一方で Arduino の場合には、内蔵のROMからプログラム(スケッチ)を読み込むと、そのプログラムが電源を切るまで動作しています。OS やシェルをもたないため、(自分で仕組みを用意しなければ)実行するプログラムをあとから指定することはできません。またシングル・タスクで、同時に動くプログラムはありません。マイコンを使った小規模なシステムでは、同様の動作をする場合が多いです。

■Arduino のスケッチの文法
 Arduino のスケッチの文法は、ほぼ C++ と同じと、思ってよいようです。C++ との違いは main 関数がなく(正確には隠されている)、代わりに setup 関数と loop 関数があることです。また Linux で使える printf 関数や cout などは、用意されていません。文法や用意されている関数については、リファレンスマニュアルに書かれています。船田巧さんによって、日本語訳が公開されています。「ライブラリ」に含まれる関数は、ライブラリの使い方にあるようにヘッダをincludeする必要があります。

■Arduino のROMに書き込まれるプログラム
 Arduino に書き込まれるプログラムは大きく三つに分かれます。
  1. 初期化部分
  2. ライブラリ(スケッチのsetup関数 loop関数から呼び出す)
  3. スケッチ
スケッチの中には、
  1. setup関数
  2. loop関数
  3. setup関数または loop 関数から呼び出す関数
を用意します。もちろん小さなプログラムであればsetup関数とloop関数以外の関数は、ないかもしれません。
 Arduino の電源が入ると、1.初期化部分が実行されます。初期化が終了すると setup 関数が呼び出されます。その次に loop 関数が呼び出されます。loop関数が終了すると、すぐにまた loop 関数が呼び出され、電源を切るまで終了することはありません。

■デジタル出力と入力
 Arduino と周辺の回路とつなぐ基本は、ディジタル出力とディジタル入力です。ディジタル出力は LOW (0[V]) または HIGH (電源電圧の 5[V], 3.3V動作のArduinoの場合は3.3V)をピンに出すことができます。電流は20[mA] (=0.02[A])ぐらいまで出力できます。
 ディジタル入力は、ピンの電圧が LOW (閾値以下)か HIGH (閾値以上) かを知ることができます。たとえばスイッチをつなぎます。

■ディジタル入出力とピンの番号
 ピンの番号は、ボードにシルク印刷で書かれています(写真1)。DIGITAL と書かれたピン 0 から 13 (プログラム上でも0から13)と、ANALOG IN と書かれたピン 0 から 5 (プログラム上では14から19) をディジタル入出力に使うことができます。Arduino Duemilanove の説明を一度読んでおくとピンの役割がよくわかるでしょう。
 ディジタル出力や入力を使うときには、スケッチの先頭で
const int LEDpin = 13;
const int SWpin = 2;
といったようにピン番号を代入したグローバル変数を用意しておくとプログラムが見やすくなります。

Arduino Duemilanove.jpg
写真1 Arduino Duemilanove の様子

■ピンの初期化
 ピンがディジタル入力か出力かは pinMode 関数で設定します。多くの場合は setup 関数内で pinMode 関数を呼びます。必要なら setup 関数以外で呼ぶこともできます。LEDをつないだピンを出力に、スイッチをつないだピンを入力にするには次のようにします。

void setup()
{
  pinMode(LEDpin, OUTPUT);
  pinMode(SWpin, INPUT);
}

■ディジタル出力
 ディジタル出力を設定するには、digitalWrite関数を使います。LEDpin のピンを LOW にするには、
  digitalWrite(LEDpin, LOW);
HIGH にするには、
  digitalWrite(LEDpin, HIGH);
とします。LED を抵抗を通して適切につないであれば、それぞれLEDが消灯、点灯します。出力は次に digitalWrite 関数を呼び出すまで変わりません。

■ディジタル入力
 デイジタル入力は digitalRead 関数で読みます。引数がピンの番号で、戻り値が 0 なら LOW、1ならHIGHです。loop関数に、
void loop()
{
  if (digitalRead(SWpin) == 0) {
    digitalWrite(LEDpin, HIGH);
  } else {
    digitalWrite(LEDpin, LOW);
  }
}
と書くと、シャットダウン・スイッチ用の回路で、スイッチを押す(ディジタル入力は LOW になる)と LED が点灯し、離すと消灯するスケッチになります。digitalRead 関数は現在の値を返すので、スイッチを以前に押したかどうかはわからないことに注意します。

■時間を意識して書く
 Arduino で LED を点滅させるとき、
void loop()
{
  digitalWrite(LEDpin, LOW);
  digitalWrite(LEDpin, HIGH);
}
というスケッチを書くと、LEDの点滅が速すぎて、目には点滅が見えなくなってしまいます(ぜひ試してください!!)。そこで、時間待ち関数 delay が用意されています。delay 関数の引数には、待ち時間をミリ秒(1/1000秒)単位で指定します。
void loop()
{
  digitalWrite(LEDpin, LOW);
  delay(500);
  digitalWrite(LEDpin, HIGH);
  delay(500);
}
とすると0.5秒ごとに点灯、消灯するので、1秒に1回LEDが点滅します。
 ところで、一つのLEDを点滅させるだけならよいのですが、スイッチを押したことを検出するにはどうしたらよいでしょうか?

■LED を点滅させながらスイッチを見張る
 常に LED を点滅させておき、スイッチを押されたら LED を点灯したままにするスケッチを考えてみます。
void loop()
{
  digitalWrite(LEDpin, LOW);
  delay(500);
  digitalWrite(LEDpin, HIGH);
  delay(500);

  while (digitalRead(SWpin) == 0) {
    digitalWrite(LEDpin, HIGH);
  }
}
とすると、どうなるでしょうか?delay関数が呼ばれている間はスイッチをチェックしていないので、LEDが消えている 0.5秒の間にスイッチを押しても、LED は点灯しません。LEDが点灯しているときにスイッチを押しても、LED は消えてしまうでしょう。
 そこで、電源投入時からの時間経過をミリ秒単位で返す millis 関数を使います。

const int LEDpin = 13;
const int SWpin = 2;
unsigned long previousMillis = 0;
bool LED = false;

void setup()
{
  pinMode(LEDpin, OUTPUT);  
  pinMode(SWpin, INPUT);
}

void loop()
{
  if (millis() - previousMillis > 500) {
    previousMillis = millis();
    if (LED) {
      digitalWrite(LEDpin, LOW);
      LED = false;
    } else {
      digitalWrite(LEDpin, HIGH);
      LED = true;
    }
  }
  if (digitalRead(SWpin) == 0) {
    while (digitalRead(SWpin) == 0) {
      digitalWrite(LEDpin, HIGH);
    }
    digitalWrite(LEDpin, LOW);
    LED = false;
    previousMillis = millis();
  }
}

 このようにしておくと、500ms (0.5秒)経過したときだけ、LEDの点滅を反転し、スイッチを押している間は LED が点灯するスケッチになります。

 このスケッチでは問題がありませんが、スイッチを押したり離したりした直後は、ディジタル入力が LOW/HIGh を繰り返すことがあります。これによる誤動作を避けるには、前回ディジタル入力を読んだ後20ms以上経過してから読むようにするという方法があるので、覚えておくとよいかもしれません。

 次回は、非同期シリアル通信に関する関数の使い方を紹介します。Arduino側のスケッチを理解できるようになるはずです。
(光永 法明)


 カテゴリ 

 

トラックバック(0)

このブログ記事を参照しているブログ一覧: Arduinoで玄柴用のシャットダウン・スイッチを作る(3/5)

このブログ記事に対するトラックバックURL: http://www.eleki-jack.com/mt/mt-tb.cgi/4049

おすすめ書籍
Powered by
Movable Type 4.1
/*yahoo remove*/