注意 今回の記事はプログラムに付いての物なのでかなり面倒くさい文章になってしまっています。
デアゴ カウンタックいよいよ終わりが近づいてきて全体の構成が見えてきました。
そろそろ電飾のプログラムを仕上げないといけません。
前の土日でどうにか満足できる動きをするようになりましたが、初心者の私に取っては結構難しく、もう頭がテンパっていました.。
今回は、いつもと違って私のつたないプログラムを一部ご紹介してみたいと思います。
以前から、プログラムのアイデア自体は色々考えていたのですが実際動かすと問題続発でしたw
まずは、ウインカーの問題。ポジションライトとウインカーが一つのLEDで供用になっています。で、ウインカーを停止した時が問題で、ポジションライトが点いている時は、点灯で終わり、ポジションライトが付いていない時は消灯で終らないといけません。
なんとかできた〜〜!と思って動かすと、ポジションライト付けるとすぐに勝手に消灯するしw
どうやらタイマー割り込みで、ウインカーとして認識して消えてるみたい・・・・。
あれこれ考えてこんな感じになりました。
タイマー割り込み部分です。
w^=1;
if (x==1)
{if(w && c){PORTB&=~(1<<PB0);PORTD|=(1<<PD0);PORTB|=(1<<PB0);} //Right winker
else{PORTD&=~(1<<PD0);PORTB&=~(1<<PB0);}
if(w && d){PORTD&=~(1<<PD4);PORTD|=(1<<PD1);PORTD|=(1<<PD4);} //Left winker
else{PORTD&=~(1<<PD1);PORTD&=~(1<<PD4);}
if (c==0){PORTB|=(1<<PB0);} //positionの回復
if (d==0){PORTD|=(1<<PD4);} //positionの回復
}
if (x==0)
{if(w && c){PORTD|=(1<<PD0);PORTB|=(1<<PB0);}//Right winker
else{PORTD&=~(1<<PD0);PORTB&=~(1<<PB0);}
if(w && d){PORTD|=(1<<PD1);PORTD|=(1<<PD4);}//Left winker
else{PORTD&=~(1<<PD1);PORTD&=~(1<<PD4);}
}
なんのこっちゃわからん!と思われると思いますが、その通りで興味のある方は下の解説読んでみてください。
とりあえず、こんな呪文を唱えたらこのような動きをします。
馴染みのない人用(まっ私もあまり馴染みは無いのですがw)に簡略化して説明しますと、
if文はこんな感じの構成になっています。if(**){*****}else{***}
ifの次の()の中がもし正しい、もしくは1ならすぐ直後の{ }の中身が実行されます。ifの次の()の中がもし偽、もしくは1以外ならその後のelse以降の{ }の中身部分が実行されます。if文は何重にも重ねる事が出来ます。
例えば
if(カウンタックカッコいい){ガンバって作る}else{諦める}
カウンタックがカッコいいならガンバって作る。カウンタックがカッコ良くないなら諦める。てな感じです。
PORTB|=(1<<PB0)てのはポートBの0番のLED点灯して〜!と言う命令です。
PORTB&=~(1<<PB0)てのはポートBの0番のLED消して〜!という命令です。
ポートというのは(前回と少し配置が変わっていますが)
汚い字でPD0とかPB1とか四角で囲まれた中に書かれている部分です。この部分にLEDがつながれています。
では実際に見てみましょう。
タイマー割り込みの部分です。タイマー割り込みとは一定の時間が来たら、そこに書かれている処理を自動で行います。
w^=1;
//タイマー設定していますのでwは設定時間が来るたびに自動的にw=1、w=0を繰り返します。
if (x==1)
//ポジションライトが付いている時をx=1とします。
{if(w && c){PORTB&=~(1<<PB0);PORTD|=(1<<PD0);PORTB|=(1<<PB0);} //Right winker
else{PORTD&=~(1<<PD0);PORTB&=~(1<<PB0);}
//右のウインカーを動かすにはc=1を入力します。もしw=1ですと、if()の中が1と成りますので、まずポジションライトを消してウインカーのライトが全部付きます。次に設定時間がくるとw=0となりif()の中が1でなくなりますので、else文以降の命令を実行してウインカーのライトが消えます。次にまた設定時間が来るとw=1となり、c=1ですのでif()は1となり直後の{ }内の命令を実行してウインカーが点灯します。
これを繰り返してウインカーが点滅します。
c=0になるとwがいくらw=1でもif()の中が1とならないのでウインカーが止まります。
if(w && d){PORTD&=~(1<<PD4);PORTD|=(1<<PD1);PORTD|=(1<<PD4);} //Left winker
else{PORTD&=~(1<<PD1);PORTD&=~(1<<PD4);}
//左のウインカーを動かすにはd=1を入力します。動作は右の時と同じです。
ちなみにc=1、d=1を入れると上の2つのプログラムが同時に動きます。これがハザードとなります。
wが周期を司っていますので、どのタイミングでd,cを入力しても同期して点滅する事になります。
if (c==0){PORTB|=(1<<PB0);} //positionの回復
if (d==0){PORTD|=(1<<PD4);} //positionの回復
//ウインカー動作が終了(c=0やd=0)になったら、if()の中が正しいのでポジションライトを点灯します。
} //ここでx=1つまりポジションライトが付いている時の処理が終了します。
if (x==0)
//次にポジションライトが点灯していない時はx=0とします。
{if(w && c){PORTD|=(1<<PD0);PORTB|=(1<<PB0);}//Right winker
else{PORTD&=~(1<<PD0);PORTB&=~(1<<PB0);}
if(w && d){PORTD|=(1<<PD1);PORTD|=(1<<PD4);}//Left winker
else{PORTD&=~(1<<PD1);PORTD&=~(1<<PD4);}
//先ほどと同じようにc=1、d=1で今回はポジションライト消灯の動作が無くウインカーが動作します。
c=0,d=0となると前回のような処理はないのでウインカーは消灯したままです。
} //ここでx=0つまりポジションライトが点灯していない時の処理が終ります。
再度動画を見てもらうとより理解できると思います。
で、デアゴのスイッチ類もAVRにつなぐのでそのコントロールをしないといけないのですが、特にライト類の操作をするハンドル左のレバーのスイッチが曲者です。
1回押すとポジションが点いて、2回押すとヘッドライトのスモール、3回目でハイビームと以前聞いた気がしたのでそのようにプログラム組んでみましたが、後で1回目でポジションとヘッドライトが点いて、2回目でハイビームとなる事が分かりました。もうプログラム組んだのでそのままにしました^^;
プログラムがこちら
if (~PINC & 0x20){
while ((~PINC & 0x20)== 0);
wait(1000); //チャダリング対策
if (count < 5)
count++;
else
count = 0;
switch(count){
case 1: x=1;PORTD|=(1<<PD4);PORTC|=(1<<PC0);PORTB|=(1<<PB0);//position
OCR0A=j;PORTD|=(1<<PD5);//tail,meter
break;
case 2: PORTB|=(1<<PB4);ti();ti();//retra
PORTB|=(1<<PB6);//headL
break;
case 3: PORTC|=(1<<PC1);//headH
break;
case 4: PORTD&=~(1<<PD4);PORTC&=~(1<<PC0);PORTB&=~(1<<PB0);x=0;//position-off
OCR0A=0;PORTD&=~(1<<PD5);//tail,meter-off
PORTB&=~(1<<PB6);//headL-off
PORTC&=~(1<<PC1);//headH-off
PORTB&=~(1<<PB4);//retra-close
count=0;
break;
default:
break;
}
while ((~PINC & 0x20)!= 0);//スイッチが押されていない時待機
wait(1000);
}
この呪文を唱えるとこのような動きをします。
ではまたプログラムを少しずつ見てみましょう。
if (~PINC & 0x20){ //もしポートCの5番のスイッチが押されたら を表しています。0x20は5番を表すと思ってください。つまりデアゴのハンドル横のレバーのスイッチです。
while ((~PINC & 0x20)== 0); //スイッチがonの時には待機する。(変な感じがするかもしれませんが、スイッチがonの時は値は0なんです。)
wait(1000); //チャダリング対策と言ってスイッチの誤動作を防ぐためにスイッチが押されている事を確認する時間を取ります。
if (count < 5)//countという自分で決めた数字の代わりの引数を一番最初に設定しています。ここに色々な数字を入れていきます。ウインカーの時のwやcやdと同じ扱いです。ここでは、countという数字がもし5より少なければ次の処理を実行しなさい と言っています。
count++; //countを1足しなさい という事です。つまりcountが0だったなら+1でcount=1、もし1だったなら+1してcount=2としなさいと命令しています
else
count = 0;
//その他、つまりcountが5以上ならcountを0にしなさいと命令しています。これにより、countは5以上にならない事になります。
switch(count){
//countが1、2、3、4でそれぞれ以下のcaseにそって処理するようにとの命令文です。
case 1: x=1;PORTD|=(1<<PD4);PORTC|=(1<<PC0);PORTB|=(1<<PB0);//position
OCR0A=j;PORTD|=(1<<PD5);//tail,meter
//count=1つまりスイッチを1回押した時は ポジションとテールとメーターを点灯しなさいと命令しています。
ここでx=1と言うのが有りますが、これはウインカーの時に説明したxと同じ物でポジションライトが点灯している時はx=1としなさいと命令しています。
break;
//ここでswitch文から抜け出し、以下のcase2以降の処理をせずにwhile ((~PINC & 0x20)!= 0);の命令文まで飛びます。つまりswitch文から抜け出します。その後、スイッチの押されていない時の待機を超えて、またスイッチが押されると今はcount=1なりますのでcount++されるとcount=2となりまたswitch文の命令によりcase 2の次の文の命令の実行となります。
case 2: PORTB|=(1<<PB4);ti();ti();//retra
PORTB|=(1<<PB6);//headL
//count=2、スイッチが2回押された時はリトラクタブルが開いて、ヘッドライトのスモールが点灯します。
break;
//switch文を抜け出します。
case 3: PORTC|=(1<<PC1);//headH
//count=3、スイッチが3回おされた時はハイビームが点灯します。
break;
//switch文を抜け出します。
case 4: PORTD&=~(1<<PD4);PORTC&=~(1<<PC0);PORTB&=~(1<<PB0);x=0;//position-off
OCR0A=0;PORTD&=~(1<<PD5);//tail,meter-off
PORTB&=~(1<<PB6);//headL-off
PORTC&=~(1<<PC1);//headH-off
PORTB&=(1<<PB4);//retra-close
count=0;
//count=4、スイッチが4回押された時は全てのライト類が消灯します。
ポジションライトが消えますので、x=0とするように命令しています。
さらにcountを0に戻しておきます。
break; //switch文を抜け出します。
default:
//これは必要なのかよくわからないのですが追加しておきました。
break;
}//ここまでがswitch文です。
while ((~PINC & 0x20)!= 0);//スイッチが押されていない時待機
wait(1000); //チャダリング対策
}//これは一番最初のif (~PINC & 0x20){ の閉じカッコです。
勘のいい方は気づかれると思いますが、このswitch文いくらでも数を増やす事が出来ますので、なんなら5回目でハザードを出すなんて事も出来ますが、元々赤外線リモコンでハザード等は動かせますので今回はここまでとしています。
これで、デアゴのスイッチでデアゴの基盤と同じ動きをするようになりました。
他にも色々とデアゴカウンタックに合うようにプログラム組んでみました。
ただ、ホーンが有るのを忘れていて、ポートの数が足りないのでホーンはリモコンでのコントロールは諦めました^^;
上記のプログラムはC言語で書かれてて、全体のプログラムの一部のみです。
厳密にいうと説明の違うところもありますが、大体こんな感じです。
vividさんやyangminさんはプログラム言語はアセンブラを使用されているみたいです。そのうち私も勉強してみたいと思います。
アイデア次第でどのような動作でもできるので、使いこなせれば(私には無理ですが)とても便利で、楽しいです。
パズルを解くみたいな感覚でプログラムを組みますので、結構楽しいです。ただ、やりだすと気になって寝れないことも^^;
関連すると思われる記事:
- None Found
こんにちは。
今回の内容は濃い~ですね~(^_^)
ライト点灯カッコイイです!
動画だと分かり易くて良いですね。
とても本を買って1ヶ月ほど独学で学んだだけとは思えません(汗)
Cの方がアセンブラより高級言語で出来ることも多いらしいので、
Cを習得されているなら、アセンブラは学ばなくても良いと思いますよぉ(^-^;)
自分は一からプログラムなんて書けないので、
ネットで探すとアセンブラで作ったプログラムが多く見付かるんで、
それを少し読み解いて出来そうな所を弄って変更しているだけですから…
その証拠に?具体的に解説していただいているのに、全然分かりません(爆)
う~ん、これだけの事が出来るなんて、やはりCも学ばないとダメかなぁ(^.^;)
おはようございます!
しばらくBlogの更新が無かったので、あれ?と思っていましたが、プログラムと戦っておられたのですね!
成功してよかったです!
私は、アセンブラ派なので、C言語のSwitch文は使えないので、
いつもは各種の条件をビットに0と1で記憶しておいて、条件でアドレスへジャンプしますので、面倒ですが、各種条件を網羅してしまえば、あとは力仕事です。
C言語を使いこなせるなんて、うらやましい限りです。
私は勉強しても、どうも消化不良です。
yangminさん こんにちは!
どうも文才がないのでちょっと難解な文章になってしまったかなと思います^^;
周りにC言語を扱える人はいるのですが、AVRを扱うためのC言語用の命令文なんてのはあまり使わないのでプログラムを見てもわからないらしいんですよね。赤外線リモコンの受信に至っては、赤外線通信を理解していないといけないので全くお手上げでした。
仕方ないので、ネットと本に頼って勉強してみました。
ただ、まだ理解が乏しくてわからないことだらけです^^;
C言語の方が高級言語なんてことさえも知りませんでした・・・。
ただ、使えこなせればですよねwまだまだ先は長そうです。
私も一から全部のプログラムを書くのは無理なので、全体はパクって・・・いえ、参考にさせていただいて作ってます。w
vividさん こんにちは!
かなり戦っていました。w
プログラム書いてはブレッドボードで確認を繰り返していました。
正直私ぐらい低レベルですと一つ変えると別なところが動かなくなるてのが頻発です。で、また考え直したりで、もうずっとプログラムのことが頭から離れない状態でしたw
で、わかりました。とりあえずif文をこねくり回すと何とかなるってw
ただ無駄にプログラムが大きくなつてしまいますが・・・。
vividさんはアセンブラ使いこなされてるのですごいですよね~。
私ももっと勉強して使いこなせるようになりたいと思います。
プログラムはいろいろな事が出来るんですね。
まずは配線のすごさに驚いてます。
追伸
スタートレックのキットを注文してしまいました。 なんか値段がすごく高いんです。全長80cmとか書いてありました。 後先考えずにポチっと w
MAXYさん こんばんは!
C言語使いこなせるようになるとかなり複雑な事も出来るようですね。まだまだ私には分からない領域です^^;
配線はデアゴの配線そのままで、ソケットを切り落としただけでAVRにつないでいるので本数は多いですがとても単純な配線です。
もしや1/350のエンタープライズですか???ポチっちゃいましたか!!
いいな〜。私も電飾キットを含めてほしいな〜〜!
てか80cmて凄いでかいですねw