「電飾しましょっ!2~PIC編~」を参考にPICを導入する!(11)最終回
今年も桜の季節ですね!!
今月2度目の更新ですが、1月から続けてきた「電飾しましょっ2」応援企画も、今回で締めにしたいと思います。最終回は、これまでおつきあい頂いた皆様へのお礼も兼ねて、いくつかのプログラムを紹介してみたいと思います。
20.「黄金のPWMプログラム」を活用する!
PICをやりたいと思った理由が、LEDをふわふわ明減させるPWMを実現したいから、という方も多いのではないでしょうか。中でもこの本のP78以降に掲載されているプログラムは、各ポート毎に別々なタイミングで明減させることが出来るなど大変汎用性の高いもので、ワタシはこれを「黄金のPWMプログラム」と呼んでおりますww
企画の最後として、黄金のPWMを応用したプログラムをいくつか紹介したいと思います。
(1)PIC12F1822で「高速明減」
まず最初に紹介するのは高速点滅ではなく「高速明減」です。
点滅は消えたり点灯したりを繰り返しますが、これはあくまでPWMの「明減」で、明るくなったり暗くなったりを繰り返し、完全に消えないのがミソです。
ロケットのエンジンの噴射光などを表現するのに使うと実感が高まります。
まず回路ですが、下の写真のようにRA0、RA1、RA4、RA5に抵抗を介してLEDを接続して下さい。
ではプログラムを紹介します。
「電飾しましょっ!2」のP56の"PIC12F1822テンプレート"を雛形にして、void main(void){ 以降を以下のプログラムに置き換えて下さい。
void main(void) {
OSCCON = 0b01110010;
ANSELA = 0b00000000;
TRISA = 0b00001000;
PORTA = 0;
//------------変数の宣言------------
//ED明減のための変数
char zentime = 65;
char ontime = 20;
char ima = 1;
char fugou =2;
while(1){
//------------明減------------
if(ima < ontime){
PORTA = 0b00110011;
}
else{
PORTA = 0b00000000;
}
//---------明減ロジック---------
ima++;
if(ima > zentime){
ima = 1;
ontime = ontime + fugou; //点灯している時間を徐々に増減
if(ontime > zentime){
fugou = -1;
}
else{
if(ontime < 20){
fugou = 1;
}
}
}
__delay_us(4);
}//End of while
return;
}//End of main
OSCCON = 0b01110010;
ANSELA = 0b00000000;
TRISA = 0b00001000;
PORTA = 0;
//------------変数の宣言------------
//ED明減のための変数
char zentime = 65;
char ontime = 20;
char ima = 1;
char fugou =2;
while(1){
//------------明減------------
if(ima < ontime){
PORTA = 0b00110011;
}
else{
PORTA = 0b00000000;
}
//---------明減ロジック---------
ima++;
if(ima > zentime){
ima = 1;
ontime = ontime + fugou; //点灯している時間を徐々に増減
if(ontime > zentime){
fugou = -1;
}
else{
if(ontime < 20){
fugou = 1;
}
}
}
__delay_us(4);
}//End of while
return;
}//End of main
コンパイル、書き込みを行い動作させると、下の動画のような明減が得られます。↓
ヤマトの波動エンジンや、スターウォーズのX、Yウイングなどにどうぞ!
(2)PIC12F1822で「LED4個のパトランプ風」
これも(1)と同じ回路で、下の動画のようにRA0、RA1、RA4、RA5のLEDがクルクル回転するように明減します。↓
これも(1)と同じ回路で、下の動画のようにRA0、RA1、RA4、RA5のLEDがクルクル回転するように明減します。↓
(1)と同様にP56の"PIC12F1822テンプレート"を雛形にして、void main(void){ 以降を下のプログラムに置き換えて下さい。
void main(void) {
OSCCON = 0b01110010;
ANSELA = 0b00000000;
TRISA = 0b00001000;
PORTA = 0;
//------------変数の宣言------------
//PWM明減のための変数
char zentime0 = 70;
char ontime0 = 2;
char ima0 = 1;
char fugou0 =2;
char zentime1 = 70;
char ontime1 = 2;
char ima1 = 1;
char fugou1 =2;
char zentime4 = 70;
char ontime4 = 2;
char ima4 = 1;
char fugou4 =2;
char zentime5 = 70;
char ontime5 = 2;
char ima5 = 1;
char fugou5 =2;
char senkou0 = 1;
char senkou1 = 0;
char senkou4 = 0;
char senkou5 = 0;
while(1){
//------順次発光・いらないところは消す------------
if(ima0 < ontime0 && senkou0 == 1){
RA0 = 1;
}
else{
RA0 = 0;
}
if(ima1 < ontime1 && senkou1 == 1){
RA1 = 1;
}
else{
RA1 = 0;
}
if(ima4 < ontime4 && senkou4 == 1){
RA4 = 1;
}
else{
RA4 = 0;
}
if(ima5 < ontime5 && senkou5 == 1){
RA5 = 1;
}
else{
RA5 = 0;
}
//---------RA0 LEDの明減--------------
if(senkou0 == 1){ima0++; //手前のLEDがMAX発光になったらPWMスタート
if(ima0 > zentime0){
ima0 = 1;
ontime0 = ontime0 + fugou0;
} //点灯している時間を徐々に増
if(ontime0 > zentime0){
fugou0 = -1; //点灯している時間を徐々に減
senkou1 = 1; //MAX発光になったら次のPWMスタート
}
else{
if(ontime0 < 1){
fugou0 = 1;
ontime0 = 2;
senkou0 = 0;
}
}
}
//---------RA1 LEDの明減--------------
if(senkou1 == 1){ima1++; //手前のLEDがMAX発光になったらPWMスタート
if(ima1 > zentime1){
ima1 = 1;
ontime1 = ontime1 + fugou1;
} //点灯している時間を徐々に増
if(ontime1 > zentime1){
fugou1 = -1; //点灯している時間を徐々に減
senkou4 = 1; //MAX発光になったら次のPWMスタート
}
else{
if(ontime1 < 1){
fugou1 = 1;
ontime1 = 2;
senkou1 = 0;
}
}
}
//---------RA4 LEDの明減--------------
if(senkou4 == 1){ima4++; //手前のLEDがMAX発光になったらPWMスタート
if(ima4 > zentime4){
ima4 = 1;
ontime4 = ontime4 + fugou4;
} //点灯している時間を徐々に増
if(ontime4 > zentime4){
fugou4 = -1; //点灯している時間を徐々に減
senkou5 = 1; //MAX発光になったら次のPWMスタート
}
else{
if(ontime4 < 1){
fugou4 = 1;
ontime4 = 2;
senkou4 = 0;
}
}
}
//---------RA5 LEDの明減--------------
if(senkou5 == 1){ima5++; //手前のLEDがMAX発光になったらPWMスタート
if(ima5 > zentime5){
ima5 = 1;
ontime5 = ontime5 + fugou5;
} //点灯している時間を徐々に増
if(ontime5 > zentime5){
fugou5 = -1; //点灯している時間を徐々に減
senkou0 = 1; //MAX発光になったらまた最初のLEDのPWMスタート
}
else{
if(ontime5 < 1){
fugou5 = 1;
ontime5 = 2;
senkou5 = 0;
}
}
}
__delay_us(4); //明減速度微調整
} //END of while
return;
} //END of main
OSCCON = 0b01110010;
ANSELA = 0b00000000;
TRISA = 0b00001000;
PORTA = 0;
//------------変数の宣言------------
//PWM明減のための変数
char zentime0 = 70;
char ontime0 = 2;
char ima0 = 1;
char fugou0 =2;
char zentime1 = 70;
char ontime1 = 2;
char ima1 = 1;
char fugou1 =2;
char zentime4 = 70;
char ontime4 = 2;
char ima4 = 1;
char fugou4 =2;
char zentime5 = 70;
char ontime5 = 2;
char ima5 = 1;
char fugou5 =2;
char senkou0 = 1;
char senkou1 = 0;
char senkou4 = 0;
char senkou5 = 0;
while(1){
//------順次発光・いらないところは消す------------
if(ima0 < ontime0 && senkou0 == 1){
RA0 = 1;
}
else{
RA0 = 0;
}
if(ima1 < ontime1 && senkou1 == 1){
RA1 = 1;
}
else{
RA1 = 0;
}
if(ima4 < ontime4 && senkou4 == 1){
RA4 = 1;
}
else{
RA4 = 0;
}
if(ima5 < ontime5 && senkou5 == 1){
RA5 = 1;
}
else{
RA5 = 0;
}
//---------RA0 LEDの明減--------------
if(senkou0 == 1){ima0++; //手前のLEDがMAX発光になったらPWMスタート
if(ima0 > zentime0){
ima0 = 1;
ontime0 = ontime0 + fugou0;
} //点灯している時間を徐々に増
if(ontime0 > zentime0){
fugou0 = -1; //点灯している時間を徐々に減
senkou1 = 1; //MAX発光になったら次のPWMスタート
}
else{
if(ontime0 < 1){
fugou0 = 1;
ontime0 = 2;
senkou0 = 0;
}
}
}
//---------RA1 LEDの明減--------------
if(senkou1 == 1){ima1++; //手前のLEDがMAX発光になったらPWMスタート
if(ima1 > zentime1){
ima1 = 1;
ontime1 = ontime1 + fugou1;
} //点灯している時間を徐々に増
if(ontime1 > zentime1){
fugou1 = -1; //点灯している時間を徐々に減
senkou4 = 1; //MAX発光になったら次のPWMスタート
}
else{
if(ontime1 < 1){
fugou1 = 1;
ontime1 = 2;
senkou1 = 0;
}
}
}
//---------RA4 LEDの明減--------------
if(senkou4 == 1){ima4++; //手前のLEDがMAX発光になったらPWMスタート
if(ima4 > zentime4){
ima4 = 1;
ontime4 = ontime4 + fugou4;
} //点灯している時間を徐々に増
if(ontime4 > zentime4){
fugou4 = -1; //点灯している時間を徐々に減
senkou5 = 1; //MAX発光になったら次のPWMスタート
}
else{
if(ontime4 < 1){
fugou4 = 1;
ontime4 = 2;
senkou4 = 0;
}
}
}
//---------RA5 LEDの明減--------------
if(senkou5 == 1){ima5++; //手前のLEDがMAX発光になったらPWMスタート
if(ima5 > zentime5){
ima5 = 1;
ontime5 = ontime5 + fugou5;
} //点灯している時間を徐々に増
if(ontime5 > zentime5){
fugou5 = -1; //点灯している時間を徐々に減
senkou0 = 1; //MAX発光になったらまた最初のLEDのPWMスタート
}
else{
if(ontime5 < 1){
fugou5 = 1;
ontime5 = 2;
senkou5 = 0;
}
}
}
__delay_us(4); //明減速度微調整
} //END of while
return;
} //END of main
チップLEDを4方向に組み込んで光らせると回転灯のような表現ができます。
(3)PIC12F1822で「高速明減と発射発光」
これも(1)と同じ回路で構いませんが、発光するのはRA0、RA1だけです。
RA0は(1)のような高速明減、RA1は定期的に「パッと点灯しじわっと消えてゆく発射発光」になります。
これも(1)と同じ回路で構いませんが、発光するのはRA0、RA1だけです。
RA0は(1)のような高速明減、RA1は定期的に「パッと点灯しじわっと消えてゆく発射発光」になります。
これも(1)と同様にP56の"PIC12F1822テンプレート"を雛形にして、void main(void){ 以降を下のプログラムに置き換えて下さい。
void main(void) {
OSCCON = 0b01110010;
ANSELA = 0b00000000;
TRISA = 0b00001000;
PORTA = 0;
//------------変数の宣言------------
//LED明減のための変数
//高速明減RA0用
unsigned char zentime = 45;
unsigned char ontime = 15;
unsigned char ima = 1;
unsigned char fugou =2;
char holdf = 0; //RA1最大発光ホールドフラグ
unsigned char ht = 0; //RA1最大発光ホールドタイム
//発射発光RA1用
unsigned char zentime1 = 240;
unsigned char ontime1 = 1;
unsigned char ima1 = 1;
unsigned char fugou1 =25;
unsigned char frg = 0; //発射発光間隔調整用
while(1){
//------------高速明減(RA0)------------
if(ima < ontime){
RA0 = 1;
}
else{
RA0 = 0;
}
//------------発射明減(RA1)------------
if(ima1 < ontime1 && frg == 3){ //二つの条件でANDをとり両方が揃ったら点灯する
RA1 = 1;
}
else{
RA1 = 0;
}
//---------高速明減ロジック(RA0)---------
ima++;
if(ima > zentime){
ima = 1;
ontime = ontime + fugou; //点灯している時間を徐々に増減
if(ontime > zentime){
fugou = -1;
}
else{
if(ontime < 20){
fugou = 1;
if(holdf = 1){ //もしRA1最大発光ホールドフラグが立ったら
ht++;} //RA1最大発光ホールドタイムカウント開始
}
}
}
//---------発射明減ロジック(RA1)---------
ima1++;
if(ima1 > zentime1){
ima1 = 1;
ontime1 = ontime1 + fugou1; //点灯している時間を徐々に増減
if(ontime1 > zentime1){
fugou1 = 0; //最大発光
holdf = 1; //最大発光をホールドフラグオン
if(ht > 20){ //最大発光ホールドタイムはこの数字で調整する
fugou1 = -1; //減光開始
holdf = 0; //最大発光をホールドフラグオフ
}
}
else{
if(ontime1 < 1){
frg++; //1発光サイクル毎にfrgをインクリメントする
ht = 0; //1発光サイクル毎に最大発光ホールドタイムをリセットする
fugou1 = 25;
}
}
}
if(frg > 3){
frg = 0;} //frgが5を超えたらfrgをリセットする
__delay_us(10); //やはりこれがあると滑らかなPWMになりますね。お好みで調整して下さい。
}//End of while
return;
}//End of main
OSCCON = 0b01110010;
ANSELA = 0b00000000;
TRISA = 0b00001000;
PORTA = 0;
//------------変数の宣言------------
//LED明減のための変数
//高速明減RA0用
unsigned char zentime = 45;
unsigned char ontime = 15;
unsigned char ima = 1;
unsigned char fugou =2;
char holdf = 0; //RA1最大発光ホールドフラグ
unsigned char ht = 0; //RA1最大発光ホールドタイム
//発射発光RA1用
unsigned char zentime1 = 240;
unsigned char ontime1 = 1;
unsigned char ima1 = 1;
unsigned char fugou1 =25;
unsigned char frg = 0; //発射発光間隔調整用
while(1){
//------------高速明減(RA0)------------
if(ima < ontime){
RA0 = 1;
}
else{
RA0 = 0;
}
//------------発射明減(RA1)------------
if(ima1 < ontime1 && frg == 3){ //二つの条件でANDをとり両方が揃ったら点灯する
RA1 = 1;
}
else{
RA1 = 0;
}
//---------高速明減ロジック(RA0)---------
ima++;
if(ima > zentime){
ima = 1;
ontime = ontime + fugou; //点灯している時間を徐々に増減
if(ontime > zentime){
fugou = -1;
}
else{
if(ontime < 20){
fugou = 1;
if(holdf = 1){ //もしRA1最大発光ホールドフラグが立ったら
ht++;} //RA1最大発光ホールドタイムカウント開始
}
}
}
//---------発射明減ロジック(RA1)---------
ima1++;
if(ima1 > zentime1){
ima1 = 1;
ontime1 = ontime1 + fugou1; //点灯している時間を徐々に増減
if(ontime1 > zentime1){
fugou1 = 0; //最大発光
holdf = 1; //最大発光をホールドフラグオン
if(ht > 20){ //最大発光ホールドタイムはこの数字で調整する
fugou1 = -1; //減光開始
holdf = 0; //最大発光をホールドフラグオフ
}
}
else{
if(ontime1 < 1){
frg++; //1発光サイクル毎にfrgをインクリメントする
ht = 0; //1発光サイクル毎に最大発光ホールドタイムをリセットする
fugou1 = 25;
}
}
}
if(frg > 3){
frg = 0;} //frgが5を超えたらfrgをリセットする
__delay_us(10); //やはりこれがあると滑らかなPWMになりますね。お好みで調整して下さい。
}//End of while
return;
}//End of main
エンジン噴射とレーザー発光など、本来なら二つのPICで別々に行うものが一つのPICにまとまります。1822は全部で5個のLEDを点灯させることができますから、プログラムを工夫すればXウイングの4個のエンジン発光と、プロトン魚雷発射発光を一つのPICで表現できますね。
(4)プログラムを弄り倒す中から新しい発見が!
これらのプログラムは、いずれも黄金のPWMを色々弄り倒しつつ制作したもので、同じような動きをするプログラムでも色々な手法が存在すると思います。
大ベテランのプログラマーから見れば「何と無駄な事を!」と思われるかも知れませんし、「こうすればもっと簡単に実現できるよ!」ということもあると思います。
いずれにせよ大事なのは、まず弄り倒してみる事です。
変数の値を変えてみたり、実行するプログラムの順番を変えてみたり、時にはエラーを出したりする中に新しい発見があります。
時にはおかしな動きをするかも知れませんが、それで誰も死にませんw
21.まとめ・・・のようなもの
さて、そろそろ終わりとしたいのですが、最後にまとめらしき事を・・・
第1回で申し上げたように「電飾しましょっ!2〜PIC編〜」は、単に読むだけのものではありません。読むだけだときっと眠くなりますよんww。
やはりこの本は、実際にPC画面やPICライターなどを使い、悪戦苦闘しながら読む事で、本来かなり遠回りしなければ習得できない技術を最短距離で「身に付ける」ためのツールだと私は思っています。
限られた紙面の中で様々な工夫がなされ、必要機材を揃えるところからプログラムの実践までを解説するだけでなく、最後にはかなり高度なPWMのプログラム手法までを解説しています。 これを身に付ける事で、将来はサーボモーターやDCモーターをコントロールし、模型に動きを付ける、なんて事も決して夢ではないのです!!!
と、まあかなり熱く語りましたが、そこは一つ、肩の力を抜いて、この本を片手に一人でも多くの皆さんがPICマイコン電飾をモノにされる事を願っております。
このカテゴリーではこれからも面白いプログラムやノウハウを紹介していけたらと思っていますが、その前にブログの引越しが先ですねww。
それでは皆様。ここまでお付き合い頂きありがとうございました!(了)