PICで電飾 PWM調光 その2 ホタル
徐々に明るく
前回、while(1){ }の中身が空っぽで、そこでDutyの数値を変えれば明るさが変わるという話をしました。今回幾つかのパターンでそれをやってみましょう。
まずは徐々に明るくなっていって、100%の明るさになったらまら0%に戻るというパターンを作ってみます。こういう感じです。
これを実現するには各LEDのDutyをどんどん書き換えればいいわけです。
今回は、書き換えの大元になる変数をつくることにして、変数の名前を(Duty Counter という意味で)DC1とします。
変数は使う前に使うぞと宣言しておかないといけません。すでにある各変数の宣言の行に書き足しておくことにします。
int Counter,DutyRB6,DutyRB7,DutyRA1,DC1;//変数の設定
その上でfor文を使って、DC1を0から100まで、変化させてゆきます。
そうやって増えてゆくDC1の値を、RB6とRB7のDutyに代入することにします。
したがってwhile(1){ }の中に入れるプログラムは以下のようになります。
for(DC1=0; DC1<100; DC1=DC1+1)
{
DutyRB6=DC1;
DutyRB7=DC1;
__delay_ms(10);
}
(RA1を今回無視していますが、特に他意はありません。同様にDC1を代入する式を書けばRB6や7と同様に光ります。)
for文は以前も説明しましたが、for( )のカッコの中の3つの式が作業内容を表します。
DC1の最初の値を0と決めて、(DC1=0)
DC1が100未満なら、(DC1<100)
DCに1を足す(DC1=DC1+1)
この作業内容の繰り返しで、DC1は100になるまで、1づつ大きくなります。その間は{ }の中に書かれた作業も繰り返されます。
{ }の中に書かれているのは、DC1の値をDutyRB6やDutyRB7に代入するという作業です。DC1は0から100まで、徐々に大きくなりますので、DutyRB6や7も徐々に大きくなり、それに伴ってLEDの明るさも増します。
DC1が100になるとDC1<100の条件を満たさなくなるので、プログラムの実行は{ }の外に出ます。
しかしこのfor文自体がwhile(1){ }にくくられているので、またfor文の頭に戻って繰り返します。
以前、for文、while文、if文で大抵のことはできると申し上げましたが、今回もそうですね。
ホタル
徐々に明るくすることが出来るなら、逆のプロセスで徐々に暗くすることも出来ます。
for(DC1=100; DC1>0; DC1=DC1-1)
{
DutyRB6=DC1;
DutyRB7=DC1;
__delay_ms(10);
}
DC1をまず100にして、0より大きい限り1を引いてゆく、という形でfor文を書けばいいわけですね。これをさっきのfor文のすぐ下に置くと、だんだん明るくなるfor文を抜けるとだんだん暗くなるfor文に入る形になりますので、ホタルのように徐々に明るくなったり暗くなったりする発光になります。
こんな感じです。
交互ホタル
2つのLEDが足並みをそろえて発光するよりずれている方が面白いこともあるでしょう。Dutyの値は0から100までなので、一方のDutyはDC1そのままの値、もう一方のDutyは100-DC1にすることで、発光のピークが互いにずれた発光にすることができます。
こんな感じです。
この発光パターンのプログラム例を下に貼っておきます。前回のプログラムとほとんど同じなのですが、
1) int でDC1を宣言
2) DutyRB6,RB7の初期値は宣言しない(DC1の代入で決まるので)
3) 上記のブログラムがwhile(1){ }に挿入されている
ということろが違っています。
明るさの変化をもっと早くしたいとか、遅くしたい場合は __delay_ms(10);の10を大きくしたり小さくしたりしてみてください。
#include <xc.h>
#define _XTAL_FREQ 8000000
//コンフィグ設定
#pragma config FOSC = INTOSC
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = ON
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = ON
#pragma config CLKOUTEN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
#pragma config WRT = OFF
#pragma config PLLEN = OFF
#pragma config STVREN = ON
#pragma config BORV = HI
#pragma config LVP = OFF
int Counter,DutyRB6,DutyRB7,DutyRA1,DC1;//変数の設定
//メイン関数ここから
void main(void)
{
//特殊レジスタの設定
OSCCON = 0b01110010 ;//内部クロック8MHz
ANSELA = 0b00000000 ;//RAの足をすべてデジタルI/Oとして使う
ANSELB = 0b00000000 ;//RBの足をすべてデジタルI/Oとして使う
OPTION_REG = 0b00000000;//内部プルアップ抵抗を使う
TRISA = 0b00000000 ;//RAの足はすべて出力に使う
TRISB = 0b00001100 ;//RBの足のうちRB2,RB3を入力に使う
WPUB = 0b00001100 ;//RB2,3に内部プルアップ抵抗をつなぐ
PORTA = 0b00000000 ;//RAの初期値はすべてゼロ
PORTB = 0b00000000 ;//RBの初期値はすべてゼロ
Counter=0;
DutyRA1=5;//Dutyの設定
// タイマ2設定
T2CON=0b00000100;//②プリスケール1、③ポストスケール1
PR2=99;//④PR2初期値99に
TMR2IF = 0; //タイマ2割り込みフラグゼロに
TMR2IE=1;//タイマ2割り込み許可
TMR2ON=1;//タイマ2スタート
PEIE=1;//周辺割り込み許可
GIE=1;//全体割り込み許可
while(1)
{
for(DC1=0; DC1<100; DC1=DC1+1)
{
DutyRB6=100-DC1;
DutyRB7=DC1;
__delay_ms(10);
}
for(DC1=100; DC1>0; DC1=DC1-1)
{
DutyRB6=100-DC1;
DutyRB7=DC1;
__delay_ms(10);
}
}
}//メイン関数ここまで
//割り込み関数ここから
void __interrupt() xxx(void)
{
if(TMR2IF)//タイマ2による割り込み
{
PR2=99;//PR2初期値99にもどす
Counter=Counter+1;//①カウントアップ
if (Counter==100)//②カウント100になったら
{
Counter=0;//②リセットしてカウントを0に
if (DutyRB6>0) RB6=1;//③カウント0と同時にRB6点灯
if (DutyRB7>0) RB7=1;//③カウント0と同時にRB7点灯
if (DutyRA1>0) RA1=1;//③カウント0と同時にRA1点灯
}
if (Counter>DutyRB6) RB6=0;//④カウント数がDutyRB6を超えたらRB6消灯
if (Counter>DutyRB7) RB7=0;//④カウント数がDutyRB7を超えたらRB7消灯
if (Counter>DutyRA1) RA1=0;//④カウント数がDutyRA1を超えたらRA1消灯
TMR2IF=0;//タイマ2による割り込みリセット
}
}//割り込み関数ここまで