PICで電飾はじめの一歩 その6 点滅パターンの作成 その2
もっとフレキシブルに
前回ナイトライダー風の往復発光パターンを作りました。実際に点灯させてみて、もう少し速く往復させたいとか、遅く往復させたいと思われるかもしれません。そんな時はどうすればよいでしょうか。
__delay_ms(500)の500を大きくしたり小さくしたりすればいいわけですが、速さを変えてみようとするたびに8箇所書き換えなくてはいけないのは面倒ですね。
このプログラムは「あるパターンで点灯させてX秒待て」を繰り返しているわけですから、そのようにプログラムを書けば、「X秒」のところを直すだけで済みます。
前回のプログラムをそのように書きなおしてみましょう。
#define _XTAL_FREQ 1000000
#include <xc.h>
// CONFIG
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = ON
#pragma config IESO = OFF
#pragma config FCMEN = OFF
void main(void) {
OSCCON=0b01000000;
ANSEL= 0b00000000;
CMCON0=0b00000111;
TRISIO=0b00000000;
GPIO= 0b00000000;
int a[5],C,D;
a[0]=0b00000001;
a[1]=0b00000010;
a[2]=0b00000100;
a[3]=0b00010000;
a[4]=0b00100000;
while(1)
{
for (C=0; C<8; C=C+1)
{
if (C<5)
D=C;
else
D=8-C;
GPIO=a[D];
__delay_ms(500);
}
}
}
前回と違うところだけ色付きになっています。
変数と配列変数
PICにやらせたい仕事は
「あるパターンで点灯させてX秒待て」
でした。まずとりかかるのは「あるパターンで点灯させて」の部分です。
表示させるパターンは5個あります。そこでPICにどのパターンを表示させるか指示できるように、パターンに名前と番号を付けてやる必要があります。
ここでは名前はa、番号は0,1,2,3,4としましょう。つまりそれぞれのパターンをa[0], a[1], a[2], a[3], a[4]と呼ぶわけです。
そのためにまずPICに名前と番号ごとのパターンを覚える場所を確保させます。
int a[5]
と書くと、PICの中に5個、数値を覚えておく場所が確保され、その場所に入れておく数値には a[0], a[1], a[2], a[3], a[4] と名前が付けられます。
プログラムの中で扱うある数値を指し示す文字列のことを「変数」と呼びます。
特にこの例のa[x]のようにカッコ書きで番号札がついている変数は「配列変数」と言います。
「int」 はプログラムで使う変数はこれこれがあるから場所を確保して名前覚えとけよ、とPICに指示する言葉です。(厳密には指示の仕方は複数あってその中のひとつです。)
今の時点ではその変数の中には何も入っていません。(正確には、何が入っているかわかりません。)そこで、それぞれの配列変数にLED点灯パターンを数値の形で教えこんでやります。
パターンは0bxxxxxxxxというように、2進数の数値の形になっていました。
プログラムを書くとき、「=」は右辺の内容を左辺に代入するという意味で使いますので、
a[0]=0b00000001; は、a[0]という変数に0b00000001を代入しなさい、という意味になります。
a[0]=0b00000001;
a[1]=0b00000010;
a[2]=0b00000100;
a[3]=0b00010000;
a[4]=0b00100000;
これでa[0]からa[4]という名前の数値置き場に置かれている値が決まりました。すると、GP0のLEDを点灯させろという意味で
GPIO=0b00000001;
と書くのと同じ結果が
GPIO=a[0];
と書くことで得られます。
GPIO=a[0];の[ ]の中の数値を0,1,2,3,4,3,2,1という順番で変えてやればナイトライダーができるわけですね。
カッコの中に置く数値も変数にします。変数名はなんでもいいのですがここではDとします。プログラムでも
GPIO=a[D];
となっていますね。このDを0,1,2,3,4,3,2,1と変化させることにしましょう。
for文
Dの変化は0,1,2,3,4,3,2,1という8ステップで終わり、あとはそれの繰り返しです。ある決まったステップ数の作業を繰り返すときによく使われる構文がfor文です。ここではステップを数える変数をCとします。
プログラムの例では
for (C=0; C<8; C=C+1)
{
実行内容
}
という形になっています。forに続く括弧(C=0; C<8; C=C+1)の中身の意味は、
・最初のCはゼロにして(C=0;)、
・もしCが8未満なら(C<8;) 、
・Cに1を足してまたCに代入しなさい(C=C+1)、
となります。
最後のC=C+1は数学的にはおかしな表記ですが、プログラム言語では=は左辺に右辺を代入する、という意味なので、これで問題ありません。
プログラムの実行がこの行にさしかかるとまずCをゼロに設定し{ }内の作業を繰り返します。一回繰り返すごとにC=C+1が実行されてCの値はゼロから1,2,・・・と増えていき、8になるとカッコ内を実行せずfor文を抜けます。
for文自体もwhile(1){実行内容}に囲まれている実行内容なので、抜けるとまたはじめに戻ってC=0から同じステップを繰り返してゆきます。
これで8段階のステップを数える事ができました。あとはそれぞれのステップでどの番号を呼び出すかです。
話が前後しますが次に行く前に補足。CやDも変数ですのであらかじめ使うぞと宣言しておく必要があります。プログラム例でもa[5]の後に続けて宣言してありますね。
int a[5],C,D;
if文
Cが0,1,2,3,4の間は、Dも同じく0,1,2,3,4としてやれば点灯ランプは左に流れてゆきます。しかしCが5,6,7の時は逆にDは3,2,1,と減らす必要があります。
このように場合によって処理を変えたい時に使うのがif文です。if文の基本構文は
if (条件) 実行内容
という形です。条件を満たしたら実行内容を実行し、そうでないなら実行しません。
条件を満たすならAを、満たさないならBを実行しなさいという場合は
if (条件) 実行内容A; else 実行内容B;
と書き、今回の例はそのようになっています。
if (C<5) もしCが0,1,2,3,4なら
D=C; Cの内容をDにコピー
else そうじゃないなら
D=8-C; 8-CをDをに書き込む
Cが5以上になったら Dが8-C になるのがここでのキモです。Cが5なら3、Cが6なら2、というようにCが増えるほどDが減るのでLEDの点灯も折り返してゆくわけですね。
これでプログラムの仕組みはだいたい説明しましたがいかがでしょうか。for、if、whileの組み合わせでだけでもかなりの発光パターンが作れるはずです。ご自身でいろいろ試してみてください。
プログラムはなんだか面倒だなあと思ったら、前回のように発光パターンをひとつひとつ手作業で指示しても別に構わないと思います。
今回のプログラムの形にすると__delay_ms()が一箇所しかありませんので、往復スピードを変えるのが簡単になります。ゆったりさせたり超高速にしたりして楽しんでみてください。
超高速になると動きはほとんど目で見えず、5個ともが同時に弱く光っているように見えると思います。これを上手く使うと任意の明るさでLEDを光らせる方法になります。
この講座はここで第一部完とし、あとは後日再開したいと思います。LED調光についてはその時に扱います。