« 2009年1月 | トップページ | 2009年3月 »

2009年2月

2009/02/23

コイル巻き機を作ってみました。

永野さんのコイル巻き機を参考にコイル巻き機を作ってみました。

巻き数カウンタを付けて設定した巻き数で止まるようにしたので、巻きながら自分で回数を数える必要がなくなりました。これでコイルを巻いている途中で時間とか聞かれても大丈夫でしょう。

Photo

参考というか、構成はほとんどそのまんまです。線材を巻いた重たいボビンを引っ張ったら線がすぐに切れるだろうとか、張力を保つにはどうしたらいいのか、など色々悩んでいたのですが、永野さんのページに掲載されていた動画を見て全て理解しました。

細部は入手した部品の都合などで異なると思うので、写真で説明します。

・巻き取り部

タミヤの「4速クランクギヤーボックスセット」を使用しています。ギヤ比はとりあえず441:1にしてみました。これより早いと張力を保つ機構が追いついてこない可能性があり、また逆にこれより遅いと遅すぎて実用にならないでしょう。コイルを巻き取る軸はΦ6mmのストローを使っています。軸を保持する方法を丸々1カ月悩んでいたのですが、結局はミシンなどで使う糸巻のボビンを使うことにしました。(Indoor Airplane Worldで販売しているコイル用の線材が巻かれているものと多分同じ)内径が6mmなのでぴったりでした。ボビン自体は中央に穴を開けた薄いベニヤ板を貼り付けて板の穴とギヤボックスから出ている軸のマサツで固定しています。軸が丸棒ではなく、6角形なので、うまいことボビンが滑らないようになっています。コイルを巻いている時に軸のストローと線が滑ってしまうのではないかと心配していたのですが、線材の端をボビンに挟み込むことでストローが滑っても巻き取り損なうことはありません。

Photo_3

奥に見えているのはPICマイコン内蔵の「充電器兼電源」を改造した巻き取りコントローラです。巻き取りモータの速度設定、巻き数の設定、カウント、設定値での停止、送り出し側のモータ制御を行っています。

巻き取り側の機構を裏側から見た所です。巻き数を検出するためのマイクロスイッチとマイクロスイッチを押すためのクランクです。巻き取っている間は「ぐい~~~ん、がちゃん。ぐい~~~~ん、がちゃん。」と結構にぎやかです。ていうかうるさい。

Photo_4

・送り出し部

線材を巻いたでっかいボビンを回すため、送り出し側にもモータを設けてボビンを駆動しています。ボビンが乗っているのはホームセンターで見つけてきた戸車です。戸車の車の部分が何種類かあったのですが、真ん中がへこんだU字型のミゾになっているものを使っています。面倒くさかった(ギアボックスを買い足しに行くのが)のでモータの軸に自転車のタイヤの虫ゴムをはめただけでボビンを直接駆動しています。

Photo_5

送り出し側のモータの起動停止を制御し、線材に張力を掛ける機構です。上側2つのプーリーと下側のアームについたプーリーに線材を掛け、アームの重さで張力を掛けています。アームが持ち上がり、アームの下側の板が光センサ(黒い部品)の隙間を遮らなくなった時にモータを駆動しています。アームと遮蔽板の形状は行き当たりばったり、現物合わせで決めています。アームの先の錘は一生かかっても使い切れないくらい大量に在庫しているハンダを流用しました。

Photo

巻き終わったコイルです。内径6mmで1000回巻いています。コイルを巻く途中に筆でサンハヤトの高周波ワニス(写真の右奥)を塗りました。

6

| | コメント (0) | トラックバック (0)

2009/02/14

開発環境

ちょっと趣向を変えて、ウチの開発環境を紹介します。

・MPLAB IDE

Windows上でPICの開発を行う場合、もっとも使われていると思われるMicroChip純正の開発環境です。現在バージョン8.20を使用していますが、以前の物と比較すると、C言語でプログラムを作成する時、内蔵されたエディタで”(”と”)”とか”{”と”}”にカーソルを持っていくと対応するものが(”{”にカーソルを移動すると"}"が)黄色く着色して表示される機能が追加されました。あと、昨年発表(発売?)されたPICkit3にも対応しているようです。が、持っていないのでメニューに表示されるのを見ただけ。

Mplab

プログラミング言語はPIC10,PIC12ではCC5XとBoostCを併用し、dsPICでは純正のC30を使用しています。

・PICkit2

PIC用の簡易型プログラミング(書き込み)ツールであるPICkit2とその制御ソフトです。現在V2.60を使用しています。

一昨年MPLAB IDEを使い始めた頃にはdsPICの書き込みがPICkit2でないと出来ないこともあって頻繁に使用していたのですが、MPLAB IDEでもdsPICの書き込みが出来るようになってからはあまり使わずにいました。

単なるプログラミング(書き込み)ツールではなく、色々なオマケ機能がついています。クロック周波数の調整機能とか、シリアル通信ツール(画面で指定したコードを送信したり、逆に受信したコードを画面に表示したり)、ロジックツールと呼ばれている簡易ロジアナまであります。

Start

・LogicTool

上記のPICkit2に含まれている簡易ロジックアナライザです。下の方のパソコンのサウンドカードを使ったオシロでは直流とか変化の遅い信号がみられないので最近になって使ってみました。

サンプリングが最大1MHzで3chまでしか使えませんが、インドアプレーンの開発では速度もチャンネル数もそれほど必要ないはずなので案外いいかも知れません。

View1

・SoftOscillo2(CQ Edition)

以前トランジスタ技術誌の付録CDに収録されていたものです。PCの音声入力端子に入力した信号を表示するものです。PCの音声入力端子を使用した簡易オシロスコープ共通の制限なのですが、直流レベルが正しく表示されない、周波数の上限が20kHz程度という点に不満が残ります。(サウンドカードを使っている以上当然なのですが)

Softoscillo2

・SoundCard OscilloScope

SoftOscillo2の使い勝手がイマイチだったため、ネットで検索して見つけてきたものです。

使い勝手はそこそこなのですが、周波数が高い信号を扱う場合にSoftOscilloと表示が異なる(電圧が低めに表示される)ような気がします。

Soundcard_oscilloscope

| | コメント (0) | トラックバック (0)

2009/02/13

455kHzマルチチャンネル化検証4

既存のRCプロポに接続する赤外線アダプタでマルチチャンネル化できないか検討してみました。

ブログ上で図を書くのはしんどいのでPDFを貼っておきます。

multi_chan.pdf

| | コメント (0) | トラックバック (0)

2009/02/09

455kHzマルチチャンネル化検証3

もう少し先へ進める場合に修正すべき項目、赤外線信号受信とPWM制御を同時に可能かどうかの検証を目的としたために端折った項目、それからすこしだけ将来の展望について検討してみます。

まずは修正項目から。

・送信機でチャンネル設定ができない

PIC12F683を使用したのでチャンネル切替えができません。(チャンネル設定用に割り当てるピンがありません。14ピン以上でPWM制御が可能なものとしてはPIC16F684などがあるので、こちらを使用すれば問題なさそうです。(PWMの周期が455kHzになるようにしておき、信号の”1”、”0"でPWMのDUTYを変えるようにします。)

・受信機の初期チャンネル設定が7chになっている

ペアリングしていないときに7chの信号を受信すると動作してしまいます。初期設定を0~7以外の値にしておいてペアリングするまでは動作しないようにする必要があります。

・受信機のチャンネル設定が何回でもできてしまう

無条件にペアリングするモードしか実装していないので、未設定の場合のみチャンネル設定する機能を追加する必要があります。

・赤外線受信中にPWMがOFFになる

スロットルが最低以外の場合は赤外線受信中の2msはスロットルONとなるようにして、スロットルの可変範囲が0%と10%~100%になるようにした方がモータの能力いっぱいまで使えるのでいいはず。(かな)

ラダーはあまり問題ないと思うのでそのまま。

・パリティチェックしていない

面倒なので後回しにしていました。

続いて今後の展望

・3ch受信機の開発

12F683または16F684等のハードウエアでPWM処理できるCPUにすればソフトでPWM制御しなければならないチャンネル数は2ch版と変わらないので可能かも。

・サーボ対応

手持ちのサーボがないので、確認手段なし。ブックオフの玩具コーナーに中古があった(はずだけれども、今からサーボ対応しておいても使い道があるのかな?)

<2月11日追記>

トリガ信号が無いときの送信周期を一律に25msとしていますが、チャンネルごとに周期を変えておけばトイラジ風のチャンネルごとに周期を変えて信号の衝突を避ける方式になりますね。(トリガ用のラジコン不要ですね。)

他のチャンネルの信号を受信している間PWM制御が止まりますが・・・。ってイマイチ駄目ぢゃん。

| | コメント (0) | トラックバック (0)

455kHzマルチチャンネル化検証2(受信機)

「455kHzマルチチャンネル化検証」のための受信機プログラムのとりあえずデバッグが終わったレベルのものです。

PIC10F222等で「20kbpsの赤外線信号受信とPWM制御が同時に可能かどうか」を検証することを目的としていましたが、結局のところ無理でした。(私の技術では)下記に掲載したプログラムは赤外線信号受信とPWM制御を交互に行い、極力PWM制御が停止する期間を短くするようにしたものです。

具体的には下記のシーケンスで動作しています。PWM制御は設定したチャンネルと受信した信号のチャンネルが合っていない場合は行いません。このような場合は”3”、”4”をスキップして再度”1”の赤外線信号待ちの状態となります。

38ビット目がONの場合、受信した信号のチャンネル情報を自分が設定されたチャンネルとして記憶します。(このままだと何回でも再設定できてしまうので、要修正です。・・・今、気がついた)

1. 赤外線信号待ち(この時はPWM制御しない)

2.赤外線信号受信(2ms、この時はPWM制御しない)

3.PWM制御(2ms×8サイクル=16ms、この間は赤外線信号を受信しない)

4.次の赤外線信号受信までPWM制御を継続する

5.赤外線信号の先頭を受信したら"2"ヘ

以下、プログラムのソースリストです。ソースリストの下に信号波形を掲載しています。

~~~~~~~~~~~~~~~~~~~~~~~~~~

//
// IRRX455 (PIC10F222)  3CH PCM IR Remote Control Receiver
// for CC5X
//
// Ver 0.10 09.02.05  T.Kojima マルチチャンネル化検証用
// Ver 0.20 09.02.09  T.Kojima 赤外線受信動作とPWM制御動作を交互に実行するように修正
//
        // SOT23  DIP
#define signal GPIO.3   // Pin6   Pin8
#define rud1 GPIO.0   // Pin1   Pin5
#define rud2 GPIO.1   // Pin3   Pin4
#define motor GPIO.2   // Pin4   Pin3

#define TMR0_50us 6
#define TMR0_half 2

unsigned char stat;     // 信号受信ステータス

unsigned char Bits_cnt;    // ビットカウンタ

bit rud_pol_1;      // ラダーを振る方向1 どっちが右なのかは回路次第
bit rud_pol_2;      // ラダーを振る方向2
bit chsel;       // ペアリング要求1
bit resv2;       // ペアリング要求2
bit parity;
bit error_f;
bit next_seq;

unsigned char rud_wid;
unsigned char th_wid;

unsigned char TMR0ck;    // 受信した信号をチェックするタイミング
unsigned char chnum;
unsigned char ch;

unsigned char ch0;
unsigned char ch1;
unsigned char ch2;
unsigned char work;

unsigned char TMR0_1;
unsigned char TMR0_2;

unsigned char i;

void main(void)
{
// Hard config
OPTION = 0xc3;     // TMR0は16分周モードで使用する (TMR0が1回オーバーフローするごとに約2ms)
TRISGPIO = 0x08;    // GPIO3は入力, 他は出力
ADCON0 = 0x00;     // 全ピンデジタル指定
OSCCAL = 0xc14;     // 要調整

// IO Pin Initial
// rud1 = 1;
// rud2 = 1;
// motor = 1;

// for(i=0;i<50000;i++);
rud1 = 0;
rud2 = 0;
motor = 0;

// WORK Initial
stat = 0;
chnum = 0;
ch = 7;
ch0 = 0;
ch1 = 0x80;
ch2 = 0x80;
work = 1;
rud_pol_1 = 0;
rud_pol_2 = 0;
rud_wid = 0;
th_wid = 0;
error_f = 0;

while (1){
  error_f = 0;
  // STARTビットの先頭を探す
  while(signal == 1){
  };
  TMR0ck = TMR0 + TMR0_half;

  // STARTビットのチェック
  // 半サイクル後から1サイクルごとにSTARTビットのチェックを9回繰り返す
  Bits_cnt = 0;
  while ((error_f == 0) && (Bits_cnt < 9)){
   if (TMR0ck == TMR0){
    // 信号はONか?
    if (signal == 0){
     Bits_cnt++;
    }
    else {
     error_f = 1;
    };
    TMR0ck = TMR0ck + TMR0_50us;
   };
  };

  // "0"のチェック
  next_seq = 0;
  while ((error_f == 0) && (next_seq == 0)){
   if (TMR0ck == TMR0){
    // 信号はONか?
    if (signal == 1){
     next_seq = 1;
    }
    else {
     error_f = 1;
    };
    TMR0ck = TMR0ck + TMR0_50us;
   };
  };
 
  // chnum受信
  if (error_f == 0){
   Bits_cnt = 0;
   while (Bits_cnt < 3){
    if (TMR0ck == TMR0){
     // 信号はONか?
     Bits_cnt++;
     chnum = chnum * 2;
     if (signal == 0){
      chnum++;
     };
     TMR0ck = TMR0ck + TMR0_50us;
    };
   };

   // "0"のチェック
   next_seq = 0;
   while ((error_f == 0) && (next_seq == 0)){
    if (TMR0ck == TMR0){
     // 信号はONか?
     if (signal == 1){
      next_seq = 1;
     }
     else {
      error_f = 1;
     };
     TMR0ck = TMR0ck + TMR0_50us;
    };
   };
  };

  // data1受信
  if (error_f == 0){
   Bits_cnt = 0;
   ch0 = 0;
   while (Bits_cnt < 7){
    if (TMR0ck == TMR0){
     // 信号はONか?
     Bits_cnt++;
     ch0 = ch0 * 2;
     if (signal == 0){
      ch0++;
     };
     TMR0ck = TMR0ck + TMR0_50us;
    };
   };

   // "0"のチェック
   next_seq = 0;
   while ((error_f == 0) && (next_seq == 0)){
    if (TMR0ck == TMR0){
     // 信号はONか?
     if (signal == 1){
      next_seq = 1;
     }
     else {
      error_f = 1;
     };
     TMR0ck = TMR0ck + TMR0_50us;
    };
   };
  };

  // data2受信
  if (error_f == 0){
   Bits_cnt = 0;
   ch1 = 0;
   while (Bits_cnt < 7){
    if (TMR0ck == TMR0){
     // 信号はONか?
     Bits_cnt++;
     ch1 = ch1 * 2;
     if (signal == 0){
      ch1++;
     };
     TMR0ck = TMR0ck + TMR0_50us;
    };
   };

   // "0"のチェック
   next_seq = 0;
   while ((error_f == 0) && (next_seq == 0)){
    if (TMR0ck == TMR0){
     // 信号はONか?
     if (signal == 1){
      next_seq = 1;
     }
     else {
      error_f = 1;
     };
     TMR0ck = TMR0ck + TMR0_50us;
    };
   };
  };

  // data3受信
  if (error_f == 0){
   Bits_cnt = 0;
   ch2 = 0;
   while (Bits_cnt < 7){
    if (TMR0ck == TMR0){
     // 信号はONか?
     Bits_cnt++;
     ch2 = ch2 * 2;
     if (signal == 0){
      ch2++;
     };
     TMR0ck = TMR0ck + TMR0_50us;
    };
   };

   // "0"のチェック
   next_seq = 0;
   while ((error_f == 0) && (next_seq == 0)){
    if (TMR0ck == TMR0){
     // 信号はONか?
     if (signal == 1){
      next_seq = 1;
     }
     else {
      error_f = 1;
     };
     TMR0ck = TMR0ck + TMR0_50us;
    };
   };

   // resv1受信
   next_seq = 0;
   while (next_seq == 0){
    if (TMR0ck == TMR0){
     // 信号はONか?
     next_seq = 1;
     if (signal == 0){
      chsel = 1;
     }
     else {
      chsel = 0;
     };
     TMR0ck = TMR0ck + TMR0_50us;
    };
   };

   // resv2受信
   next_seq = 0;
   while (next_seq == 0){
    if (TMR0ck == TMR0){
     // 信号はONか?
     next_seq = 1;
     if (signal == 0){
      resv2 = 1;
     }
     else {
      resv2 = 0;
     };
     TMR0ck = TMR0ck + TMR0_50us;
    };
   };

   // parity受信
   next_seq = 0;
   while (next_seq == 0){
    if (TMR0ck == TMR0){
     // 信号はONか?
     next_seq = 1;
     if (signal == 0){
      parity = 1;
     }
     else {
      parity = 0;
     };
     TMR0ck = TMR0ck + TMR0_50us;
    };
   };
  };

  // チャンネル設定要求?
  if (chsel){ch = chnum;};

  // パリティチェック(略)

  if ((error_f == 0) && (chnum == ch)){
   // 制御量計算
   th_wid = ch0 * 2;
   rud_pol_1 = 0;
   rud_pol_2 = 0;
   rud_wid = 0;
   if (ch1 > 0x40){
    rud_pol_1 = 1;    
    rud_wid = ch1 - 0x40;
   }
   else if (ch1 < 0x40){
    rud_pol_2 = 1;
    rud_wid = 0x40 - ch1;
   };
   rud_wid = rud_wid * 4;
 
   // RUD,TH PWM制御
   // 信号受信成功後0~16msの間は信号を受信しても無視してPWM制御を行う
   for(i=0;i<8;i++){
    // RUD,TH ON/OFFタイミング設定
    TMR0ck = TMR0;
    TMR0_1 = TMR0ck + rud_wid;
    TMR0_2 = TMR0ck + th_wid;

    // RUD,TH ON
    while ((TMR0 != TMR0ck) && (TMR0 != (TMR0ck+1)));
    if (rud_wid > 5){
     if (rud_pol_1 == 1){
      rud1 = 1;
      rud2 = 0;   
     } else if(rud_pol_2 == 1){
      rud1 = 0;
      rud2 = 1;
     };
    };
    if (th_wid > 5){
     motor = 1;
    };
   
    // RUD,TH OFF
    while ((rud1 == 1) || (rud2 == 1) || (motor == 1)){
     if ((TMR0 == TMR0_1) || (TMR0 == (TMR0_1+1))){
      rud1 = 0;
      rud2 = 0;
     };
     if ((TMR0 == TMR0_2) || (TMR0 == (TMR0_2+1))){
      motor = 0;
     };
    };
   };

   // 信号受信成功後18ms以降は信号を受信するまでPWM制御する。信号受信したらPWM制御は終了する
   while(1){
    // RUD,TH ON/OFFタイミング設定
    if (signal==0){break;};
    TMR0ck = TMR0;
    TMR0_1 = TMR0ck + rud_wid;
    TMR0_2 = TMR0ck + th_wid;
    // RUD,TH ON
    while ((TMR0 != TMR0ck) && (TMR0 != TMR0ck+1)){if (signal==0){break;};};
    if (rud_wid > 5){
     if (rud_pol_1 == 1){
      rud1 = 1;
      rud2 = 0;   
     } else if(rud_pol_2 == 1){
      rud1 = 0;
      rud2 = 1;
     };
    };
    if (th_wid > 5){
     motor = 1;
    };
      
    // RUD,TH OFF
    while ((rud1 == 1) || (rud2 == 1) || (motor == 1)){
     if (signal==0){break;};
     if ((TMR0 == TMR0_1) || (TMR0 == (TMR0_1+1))){
      rud1 = 0;
      rud2 = 0;
     };
     if ((TMR0 == TMR0_2) || (TMR0 == (TMR0_2+1))){
      motor = 0;
     };
    };
   };
  };   
  motor = 0;
  rud1 = 0;
  rud2 = 0;
};
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~

送信機側の出力信号です。20ms周期のトリガ信号を入力していないため、25msごとに勝手に信号を出しています。

Irtx_2

一回の信号を拡大しました。PICの内部タイマの都合のため、信号1ビットあたり48μsとしています。

Irtx_

受信機のPWM出力波形です。25msごとの信号受信中はPWM出力がOFFになっています。

(フルスロットル時)

Irrx455_100

(ハーフスロットル時)

Irrx455_50

<2009.2.18追記>

スペックについて追記します。

・バンド数               8バンド

・チャンネル数    2チャンネル

・PWM周期         2ms

・分解能                128(送受信データは7ビット、ただし0~4はOFFとする)

・送受信周期    約20ms(同期信号に依存、同期信号未使用時は25ms)

・送受信データサイズ 40ビット

・1ビットあたりの時間 48μs

| | コメント (0) | トラックバック (0)

2009/02/08

455kHzマルチチャンネル化検証 (送信機)

赤外線マルチチャンネル検証用の送信機プログラムです。

PIC12F683を使用します。GP2に論理1の時に"L"を出力し、論理0の時に”H”を出力しています。(実際に赤外線を出す場合はPWM出力機能を利用してGP2にパルス信号を出力します。http://fwhp6462.cocolog-nifty.com/blog/2009/02/post-c667.html参照)

このプログラムで作った信号を前の記事に掲載した受信機用プログラムで受信してみた所、処理が追いつかずダメダメでした。なんとかならないかいろいろとやってみていますが、目処が立ちません。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//
// IRTX455 Ver0.01
// 455kHzマルチチャンネル検証用
// 送信機のGP2端子から受信機のGP3端子へ直結
//

//
//Pin 1 VDD
//Pin 2 GP5/         T1CKI/         IOC   // NC
//Pin 3 GP4/AN3/                    IOC   // CH2_IN
//Pin 4 GP3/         T1G/           IOC/*MCLR // SYNC SIGNAL IN
//Pin 5 GP2/AN2/COUT/T0CKI/CCP1/INT/IOC   // LED_OUT
//Pin 6 GP1/AN1/CIN-/               IOC   // CH1_IN
//Pin 7 GP0/AN0/CIN+/               IOC   // CH0_IN
//Pin 8 VSS
//

//
// Timer0 50uS timer (正確には48uS)
// Timer1
// Timer2 Reserve for 455kHz
//
//

#define CH0_IN GPIO.0   // Pin7
#define CH1_IN GPIO.1   // Pin6
#define LEDOUT GPIO.2   // Pin5
#define SYNC GPIO.3   // Pin4
#define CH2_IN GPIO.4   // Pin3
#define TESTPIN GPIO.5   // Pin2

#define ON 0
#define OFF 1

#define TMR0_50us 6;

#define an0sel 0x00
#define an1sel 0x04
#define an2sel 0x08
#define an3sel 0x0c
#define adconint 0x01
#define adgo 0x02

unsigned char stat;

unsigned char TMR0ck;

unsigned char ch0dt;
unsigned char ch1dt;
unsigned char ch2dt;

unsigned long timer50us;

unsigned char ch;

unsigned char work;
unsigned long i;

void main(void)
{
//
TRISIO = 0x1b;    // GPIO0,1,3,4,5は入力, 2は出力
ANSEL = 0x0b;    // GPIO0,1,4はアナログ
OSCCON = 0x71;    // CPU Clock 8MHz
OPTION_REG = 0xc3;   // TMR0 Clock 8MHz /4 /16 (125kHz)
OSCTUNE = 0x00;

LEDOUT = OFF;
ch =0x07;
stat = 0;
ADCON0 = adconint + an0sel;
 
// Wait for OSC stable
while(OSCCON.2==0);

TMR0ck = TMR0 + TMR0_50us;
 
  while(1){
 
  switch(stat){
    // AD入力
   case 0:{ 
    ADCON0 = adconint + an0sel + adgo;
    while (ADCON0.1 == 1);  // wait A/D DONE.
    ADCON0 = adconint + an0sel + adgo;
    while (ADCON0.1 == 1);  // wait A/D DONE.
    ch0dt = ADRESH;

    ADCON0 = adconint + an1sel + adgo;
    while (ADCON0.1 == 1);  // wait A/D DONE.
    ADCON0 = adconint + an1sel + adgo;
    while (ADCON0.1 == 1);  // wait A/D DONE.
    ch1dt = ADRESH;

    ADCON0 = adconint + an3sel + adgo;
    while (ADCON0.1 == 1);  // wait A/D DONE.
    ADCON0 = adconint + an3sel + adgo;
    while (ADCON0.1 == 1);  // wait A/D DONE.
    ch2dt = ADRESH;
   
    TMR0ck = TMR0 + TMR0_50us;
   
    timer50us = 0;
    stat++;

    break;
   };
   // 送信開始トリガ待ち
   case 1:{
    while(TMR0ck > TMR0);
    TMR0ck = TMR0 + TMR0_50us;
    timer50us++; 
    if (timer50us >= 500){
     timer50us = 0;
     stat++;
    };
    break;
   };
   // 順番待ち
   case 2:
   {
   
    stat++;
    break;
   };
   // 送信開始
   case 3:
    // bit 1
    LEDOUT = ON;
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 2
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 3
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 4
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 5
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 6
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 7
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 8
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 9
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 10
    LEDOUT = OFF;
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 11-13
    work = ch;
    for(i=0;i<3;i++){
     if (work.2 ==1){LEDOUT = ON;}else {LEDOUT = OFF;};
     work = work * 2;
     TMR0ck = TMR0ck + TMR0_50us;
     while(TMR0ck != TMR0);
    };
    // bit 14
    LEDOUT = OFF;
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 15-21
    work = ch0dt;
    for(i=0;i<7;i++){
     if (work.7 ==1){LEDOUT = ON;}else {LEDOUT = OFF;};
     work = work * 2;
     TMR0ck = TMR0ck + TMR0_50us;
     while(TMR0ck != TMR0);
    };
    // bit 22
    LEDOUT = OFF;
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 23-29
    work = ch1dt;
    for(i=0;i<7;i++){
     if (work.7 ==1){LEDOUT = ON;}else {LEDOUT = OFF;};
     work = work * 2;
     TMR0ck = TMR0ck + TMR0_50us;
     while(TMR0ck != TMR0);
    };
    // bit 30
    LEDOUT = OFF;
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 31-37
    work = ch2dt;
    for(i=0;i<7;i++){
     if (work.7 ==1){LEDOUT = ON;}else {LEDOUT = OFF;};
     work = work * 2;
     TMR0ck = TMR0ck + TMR0_50us;
     while(TMR0ck != TMR0);
    };
    // bit 38 (dumy)
    LEDOUT = OFF;
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 39 (dumy)
    LEDOUT = OFF;
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);
    // bit 40 (dumy)
    LEDOUT = ON;
    TMR0ck = TMR0ck + TMR0_50us;
    while(TMR0ck != TMR0);

    LEDOUT = OFF;
   
    stat = 0;
  };
};
}

| | コメント (0) | トラックバック (0)

2009/02/06

455kHzマルチチャンネル化検証 (受信機)

赤外線マルチチャンネル化検証のための受信機側プログラム

(2月10日、下線部と横線部分を訂正)

とりあえずコンパイルエラーが出ないだけのレベルです。送信機側を作らないと動作するかどうかまったく不明です。

データフォーマットは以下の通りです。(暫定)

予備の2ビットを同時に"1"にするとスタートを表すデータと同じになってしまう可能性があるので同時に"1"にすることは禁止です。

ビット 機能
1~9 スタートを表すための9ビット連続した”1”
10 0固定(スタート以外に”1”が9ビット連続した箇所ができないようにする)
11~13 チャンネル(3ビット)
14 0固定(スタート以外に”1”が9ビット連続した箇所ができないようにする)
15~21 スロットル(7ビット)
22 0固定(スタート以外に”1”が9ビット連続した箇所ができないようにする)
23~29 ラダーラダー/エレベータ/エルロンのいずれか(7ビット)
30 0固定(スタート以外に”1”が9ビット連続した箇所ができないようにする)
31~37 エルロンラダー/エレベータ/エルロンのいずれか(7ビット)
38~39 予備
40 パリティ用のリザーブ

1ビットあたりの時間を5048μsとし、”1”ならば発光(センサ出力L)することにします。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//
// IRRX455 (PIC10F222)  3CH PCM IR Remote Control Receiver
// for CC5X
//
// Ver 0.10 09.02.05  T.Kojima マルチチャンネル化検証用
//
        // SOT23  DIP
#define signal GPIO.3   // Pin6   Pin8
#define rud1 GPIO.0   // Pin1   Pin5
#define rud2 GPIO.1   // Pin3   Pin4
#define motor GPIO.2   // Pin4   Pin3

#define tmr0_50us 25
#define tmr0_25us 12

unsigned char stat;     // 信号受信ステータス

unsigned char Bits_cnt;    // ビットカウンタ

bit rud_pol_1;      // ラダーを振る方向1 どっちが右なのかは回路次第
bit rud_pol_2;      // ラダーを振る方向2
bit resv1;       // ペアリング要求1
bit resv2;       // ペアリング要求2
bit parity;

unsigned char rud_wid;
unsigned char th_wid;

unsigned char tmr0ck;    // 受信した信号をチェックするタイミング
unsigned char tmr0ck1;
unsigned char tmr0ck2;

unsigned char chnum;
unsigned char ch;

unsigned char ch0;
unsigned char ch1;
unsigned char ch2;
unsigned char work;

void main(void)
{
// Hard config
OPTION = 0xc1;     // TMR0は4分周モードで使用する
TRISGPIO = 0x08;    // GPIO3は入力, 他は出力
ADCON0 = 0x00;     // 全ピンデジタル指定
OSCCAL = 0x26;     // 要調整

// IO Pin Initial
rud1 = 0;
rud2 = 0;
motor = 0;

// WORK Initial
stat = 0;
chnum = 0;
ch = 5;
ch0 = 0;
ch1 = 0x80;
ch2 = 0x80;
work = 0;
rud_pol_1 = 0;
rud_pol_2 = 0;
rud_wid = 0;
th_wid = 0;

while (1){   

  // RUD,TH  ON
  if (TMR0  < 8){
   //RUD
   rud1 = 0;
   rud2 = 0;
   if (rud_wid >= 8){
    if (rud_pol_1 == 1){rud1 = 1;} else {rud2 = 1;};
   };
   //TH
   if (th_wid >= 8){
    motor = 1;
   };
  };
   
  // RUD,TH OFF
  if (TMR0 > rud_wid){
   rud1 = 0;
   rud2 = 0;
  };
  if (TMR0 > th_wid){
   motor = 0;
  };

  switch(stat){
   case 0:{
    // STARTビットの先頭を探す
    if (signal == 0){
     stat++;
     Bits_cnt = 0;
     chnum = 0;
    };
    tmr0ck2 = (tmr0ck1 = (tmr0ck = tmr0ck + tmr0_50us) + 1) + 1;
    break;
   };
   case 1:{
    // 半サイクル後から1サイクルごとにSTARTビットのチェック
    if ((tmr0ck == TMR0) || (tmr0ck1 == TMR0) || (tmr0ck2 == TMR0)){
     // 信号はONか?
     if (signal == 0){
      Bits_cnt++;
     }
     else {
      stat = 0;  // 違っていたのでやり直し
     };
     // 9ビットともONならば次へ
     if (Bits_cnt == 9){
      stat++;
      Bits_cnt = 0;
     };
     tmr0ck2 = (tmr0ck1 = (tmr0ck = tmr0ck + tmr0_50us) + 1) + 1;
    };
    break;
   };
   case  2: // STARTビット後の"0"チェック
   case  4: // チャンネル後の"0"チェック
   case  6: // データ1後の"0"チェック
   case  8: // データ2後の"0"チェック
   case 10: // データ3後の"0"チェック
    {
    if ((tmr0ck == TMR0) || (tmr0ck1 == TMR0) || (tmr0ck2 == TMR0)){
     // 信号はONか?
     if (signal == 1){
      stat++;
     }
     else {
      stat = 0;  // 違っていたのでやり直し
     };
     tmr0ck2 = (tmr0ck1 = (tmr0ck = tmr0ck + tmr0_50us) + 1) + 1;
    };
    break;
   };
   case 3:{
    // チャンネルの受信
    if ((tmr0ck == TMR0) || (tmr0ck1 == TMR0) || (tmr0ck2 == TMR0)){
     // 信号はONか?
     chnum = chnum * 2;
     if (signal == 0){
      chnum++;
     };
     Bits_cnt++;
     if (Bits_cnt == 3){
      if (chnum == ch){
       stat++;
       Bits_cnt = 0;
      }
      else {
       stat = 0;
      };
     };
     tmr0ck2 = (tmr0ck1 = (tmr0ck = tmr0ck + tmr0_50us) + 1) + 1;
    };
    break;
   };
   case 5: // データ1受信
   case 7: // データ2受信
   case 9: // データ3受信
    {
    if ((tmr0ck == TMR0) || (tmr0ck1 == TMR0) || (tmr0ck2 == TMR0)){
     // 信号はONか?
     work = work * 2;
     if (signal == 0){
      work++;
     };
     Bits_cnt++;
     if (Bits_cnt == 7){
      stat++;
      Bits_cnt = 0;
      ch0 = ch1;
      ch1 = ch2;
      ch2 = work * 2;
      work = 0;
     };
     tmr0ck2 = (tmr0ck1 = (tmr0ck = tmr0ck + tmr0_50us) + 1) + 1;
    };
    break;
   };
   case 11:// 予備データ1の受信
   case 12:// 予備データ2の受信
    {
    if ((tmr0ck == TMR0) || (tmr0ck1 == TMR0) || (tmr0ck2 == TMR0)){
     resv2 = resv1;
     // 信号はONか?
     if (signal == 0){
      resv1 = 1;
     }
     else {
      resv1 = 0;
     };
     tmr0ck2 = (tmr0ck1 = (tmr0ck = tmr0ck + tmr0_50us) + 1) + 1;
     stat++;
    };
    break;
   };
   case 13:{
    // パリティの受信
    if ((tmr0ck == TMR0) || (tmr0ck1 == TMR0) || (tmr0ck2 == TMR0)){
     // 信号はONか?
     if (signal == 0){
      parity = 1;
     }
     else {
      parity = 0;
     };
     stat++;
    };
    break;
   };
   case 14:{
    // パリティチェック(略)
   
    // 制御量計算
    th_wid = ch0;
   
    rud_pol_1 = 0;
    rud_pol_2 = 0;
    rud_wid = 0;
    if (ch1 > 0x80){
     rud_pol_1 = 1;    
     rud_wid = ch1 - 0x80;
    }
    else if (ch1 < 0x80){
     rud_pol_2 = 1;
     rud_wid = 0x80 - ch1;
    };
   
    // 受信データ初期化
    stat = 0;
    chnum = 0;
    ch2 = 0;
    break;
   };
  };
};
}

| | コメント (0) | トラックバック (0)

2009/02/03

2CH赤外線受信機用ソフトウエア

PIC10F222を使った2CH赤外線受信機のソフトウエアです。

電源が入った後約5秒以内に有効な赤外線信号を受信すると赤外線受信機として赤外線の信号に従って動作します。5秒以内に有効な赤外線信号を受信しなかった場合はフライトタイマモードとなります。このモード判定を行っている間はどちらのモードにするか決まっていないのでラダーをパタパタして注意を促すようにしています。フライトタイマモードになると、数秒間モータを駆動します。このとき途中で左右各1回だけラダーを切るようにしています。

フライトタイマモードの場合にモータを停止した後はラダーのテストのためにラダーだけパタパタ動作するようにしています。

送信機から操作する場合は一度スロットルを下限まで下げないとモータが回らないようにしています。また、途中で1秒以上信号が途切れた場合はモータを停止させています。

受信した信号と1回前の同じチャンネルの信号のパルス幅の平均をとって制御しているつもりですが、効果は不明です。

以下、プログラムです。

PWM制御周波数はモータ、ラダーともに250Hz(約4ms周期)で分解能はモータ、ラダーともに31段階程度です。プログラム上のステップ数に依存しないで、CPUに内蔵されたタイマを基準に動作しています。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//
// IRRX51 (PIC10F222)   T.Kojima
// for CC5X
//
// Ver 1.00 09.02.01
//

                                 // SOT23  DIP
#define signal GPIO.3     // Pin6   Pin8
#define rud1 GPIO.0      // Pin1   Pin5
#define rud2 GPIO.1      // Pin3   Pin4
#define motor GPIO.2    // Pin4   Pin3

#define tmr0_4000us 250
#define tmr0_3000us 186
#define tmr0_2400us 148
#define tmr0_2000us 124
#define tmr0_1500us 93
#define tmr0_1000us 62
#define tmr0_800us 48
#define tmr0_500us 31
#define tmr0_100us  6
#define wid_center tmr0_500us

unsigned char signal_bk;
unsigned char signal_wid0;     // TH
unsigned char signal_wid0a;   // 平均化処理用バックアップ
unsigned char signal_wid0b;
unsigned char signal_wid1;     // RUD
unsigned char signal_wid1a;   // 平均化処理用バックアップ
unsigned char signal_wid1b;

unsigned char stat;            // 信号受信ステータス
#define stat_gap_search 0  // ギャップ検出
#define stat_rcv  1           // 信号受信
#define stat_calc 2           // 制御量計算
#define stat_stop 0xff       // 停止

unsigned char ch;             // 受信中のチャンネル

bit rud_pol_1;                   // ラダーを振る方向1
bit rud_pol_2;                   // ラダーを振る方向2
unsigned char rud_wid;      // ラダーを振る量
unsigned char th_wid;        // スロットルの量

unsigned char mode;        // 動作モード
#define mode_chk 0        // 未定
#define mode_flt_tmr 1    // フライトタイマ兼アクチュエータテスト
#define mode_RC 2         // RC(プロポ制御)

unsigned long timer;         // 動作モード判定時間タイマ兼フライトタイマ用カウンタ兼RCモード時の無信号時間チェック用

unsigned char tmr0_wid;    // 受信した信号がH→Lになるエッジの間隔
unsigned char tmr0_bk;     // 受信した信号が前回H→Lになったエッジのタイミング

bit start_chk;                  // RCモード時に一度スロットルが0になったら1

void main(void)
{
// Hard config
OPTION = 0xc4;
TRISGPIO = 0x08;    // GPIO3は入力, 他は出力
ADCON0 = 0x00;      // 全ピンデジタル指定
OSCCAL = 0x26;

// IO Initial
rud1 = 0;
rud2 = 0;
motor = 0;

// WORK Initial
tmr0_bk = TMR0;
tmr0_wid = TMR0 - tmr0_bk;
signal_wid0a = tmr0_1500us;
signal_wid1a = tmr0_1500us; 
mode = mode_chk;
timer = 0;
stat = 0;
signal_bk = 0xff;
th_wid = 0;
rud_wid = 0;
start_chk = 0;

while (1){   
  // 信号のフィルタリング
  signal_bk = signal_bk * 2;
  if (signal){signal_bk++;};

  // RUD,TH  ON
  if (TMR0  < 8){
   //RUD
   rud1 = 0;
   rud2 = 0;
   if (rud_wid >= 8){
    if (rud_pol_1 == 1){rud1 = 1;}
    else if (rud_pol_2 == 1){rud2 = 1;};
   };
   //TH
   if ((th_wid >= 8) && (start_chk)){
    motor = 1;
   };
  };
   
  // RUD,TH OFF
  if (TMR0 > rud_wid){
   rud1 = 0;
   rud2 = 0;
  };
  if (TMR0 > th_wid){
   motor = 0;
  };

  // 無信号時と起動時の処理
  // 無信号が4ms連続したか?ifの内側は無信号時4msごとに実行される
  tmr0_wid = TMR0 - tmr0_bk;
  if (tmr0_wid > tmr0_4000us){
   tmr0_bk = TMR0;   
   switch (mode){
    // 制御モードが決まるまではパタパタさせる
    case mode_chk:{
     rud_wid = 120;
     timer++;
     if ((timer & 0x0040) ==0){
      // 左パタ(128ms)
      rud_pol_1 = 1;
      rud_pol_2 = 0;
     }
     else {
      // 右パタ(128ms)
      rud_pol_1 = 0;
      rud_pol_2 = 1;
     };
     // 無信号が5秒続いたらFlight timer modeにする
     // 5秒以内に信号を受信していたら受信処理内でPropo modeに切り替える
     if (timer > 1250){
      mode = mode_flt_tmr;
      stat = stat_stop;
      start_chk = 1;
      timer = 0;
     };
     break;
    };
    // Flight timer mode
    case mode_flt_tmr:{
     timer++;
     switch (timer){
      case 1:{
       th_wid = 200; // モータON
       rud_pol_1 = 0;
       rud_pol_2 = 0;
       rud_wid = 0;
       break;
      };
      case 500:{    // 2.0sec
       rud_pol_1 = 1;
       rud_wid = 120;
       break;
      };
      case 625:{    // 2.5sec
       rud_pol_1 = 0;
       rud_wid = 0;
       break;
      };
      case 1000:{    // 4.0sec
       rud_pol_2 = 1;
       rud_wid = 120;
       break;
      };
      case 1250:{    // 5.0sec
       rud_pol_2 = 0;
       rud_wid = 0;
       break;
      };
      case 2000:{    // 8.0 sec
       rud_wid = 0;
       th_wid = 0;   // モータOFF
       break;
      };
      case 2500:{    // 10.0sec
       rud_pol_1 = 1;
       rud_wid = 120;
       break;
      };
      case 2625:{    // 10.5sec
       rud_pol_1 = 0;
       rud_wid = 0;
       break;
      };
      case 2750:{    // 11.0sec
       rud_pol_2 = 1;
       rud_wid = 120;
       break;
      };
      case 2875:{    // 11.5sec
       rud_pol_2 = 0;
       rud_wid = 0;
       break;
      };
      case 2999:{    // 11.996 sec
       timer = 2499;
       break;
      };
     };
     break;
    };
    // Propo mode
    // 無信号になったら舵中央、スロットルオフ
    case mode_RC:{
     timer++;
     if (timer > 250){
      rud_pol_1 = 0;
      rud_pol_2 = 0;
      rud_wid = 0;
      th_wid = 0;
      timer = 0;
     };
     break;
    };
   };
  };
   


  // 信号受信処理
   switch(stat){
   // GAP検出(4ms以上連続して OFF)
   case stat_gap_search:{
    if ((signal_bk & 0x03) == 0x02){tmr0_bk = TMR0;}
    else if (tmr0_wid > tmr0_4000us){
     ch = 0;
     stat++;
    };
    break;
   };
   // 信号検出
   case stat_rcv:{
    // ノイズキャンセル
    if ((signal_bk== 0xf0) &&(tmr0_wid > tmr0_100us)){
     // パルス幅チェック1(NGならば受信やり直し)
     if ((ch != 0) && (tmr0_800us   > tmr0_wid)){stat = 0;};
     if ((ch != 0) && (tmr0_2400us < tmr0_wid)){stat = 0;};
     // パルス幅チェック2(はみ出していたら補正)
     if (tmr0_wid < tmr0_1000us){tmr0_wid = 0;}
     else if (tmr0_wid > tmr0_2000us){tmr0_wid = tmr0_1000us;}
     else {tmr0_wid = tmr0_wid - tmr0_1000us;};
     // パルス幅データ取り込み
     // ラダー
     if (ch == 4){
      // 前回受信した信号との平均化処理
      signal_wid1b =signal_wid1a;
      signal_wid1a = tmr0_wid;
      signal_wid1 = (signal_wid1a + signal_wid1b) / 2;
     }
     // スロットル
     else if (ch == 3){
      // 前回受信した信号との平均化処理
      signal_wid0b =signal_wid0a;
      signal_wid0a = tmr0_wid;
      signal_wid0 = (signal_wid0a + signal_wid0b) / 2;
      // スロットル下限でモータ停止する
      if (signal_wid0 < tmr0_100us){signal_wid0 = 0;};
    
     };
    
     tmr0_bk = TMR0;        // 今回エッジを受信したタイミングのバックアップ(エッジ間の時間測定のため)
     ch++;          // 次のチャンネル
     // 全部のチャンネルを受信したか
     if (ch >= 7){
      stat++;         // 計算処理ヘ
      timer = 0;        // 無信号時間タイマをリセット
      if (signal_wid0 == 0){start_chk = 1;}; // 起動後スロットルを一度0にした
      if (mode == mode_chk){mode = mode_RC;}; // RCモード確定
     };
    };
    break;
   };
   
   // 制御量の計算
   case stat_calc:{
    // RUD calc
     rud_pol_1 = 0;
     rud_pol_2 = 0;
     rud_wid = 0;
    if (signal_wid1 > wid_center){
     rud_pol_1 = 1;
     rud_wid = signal_wid1 - wid_center;
    }
    else if (signal_wid1 < wid_center){
     rud_pol_2 = 1;
     rud_wid = wid_center - signal_wid1;
    };
    rud_wid = rud_wid * 8;

    //TH calc
    if (signal_wid0 > 0x3f){th_wid = 0xff;}
    else {th_wid = signal_wid0 *4;};

    stat = stat_gap_search;       // 次の信号を待つ
    break;
   };
  };
};
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

| | コメント (0) | トラックバック (0)

2CH赤外線受信機と書き込みアダプタの製作

プロポ用の赤外線送信アダプタができたので、これと組み合わせて使う赤外線受信機を製作しました。

Dscf1045_3

部品実装前の基板です。前に作った基板はぎりぎりまで薄くなるように削っていたのですが、使っているうちに接触不良などの不良が多発したため板厚0.5mm(基板重量0.3g)くらいにしました。前に作った12F683を使った受信機よりはだいぶ小さくなったのですが、まだまだかな~~~。それでも部品実装状態で1.0g位にはなっていたので、前に作った受信機を積んでいた機体に載せ変えたら思いっきり重心がずれてました。

下の画面は左上が12F683を使ったFETドライバ付きの3CH赤外線受信機、右上が今回製作したFETドライバ無しの2CH赤外線受信機です。右下はIndoor Airplane Worldで販売している受信機の部品配置とパターンを一部手本にして見直した2CH赤外線受信機案、左下が右下のものを元に基板を両面化した案です。

Ir_recv

部品を実装した写真を撮影するのを忘れていました。機体に実装して基板の裏側から撮影したものです。機体は昨年暮れにYSFCにおじゃました時に持っていったものを一部改造したものです。

Dscf1044

例によって基板の裏側に生えたソケットにコードの先にハンダ付けしたピンを差し込むようにしています。重くなりますが、メンテナンスは楽になると思います。

基板にソケットをハンダ付けしている理由がもう一つあって、下の写真のような受信機基板とPICKit2をつなぐ書き込みアダプタを使うことでCPUを基板に実装した後でもプログラムの書き換えが出来るようにしています。(そのため飛ばす時には不要なGP3ピンの信号を取り出すソケットもついています。)

Dscf1047

(写真上または裏面に実装した6ピンの端子にPICKit2をつなぎ、残りの3ピンと2ピンの端子を基板のソケットに差し込んで使います。)

また、基板につないで使う書き込みアダプタの他にハンダ付けする前のPICに書き込む場合に使うアダプタも製作しました。(製作ってほどのものでもないんですが)

Dscf1036x50

こんな感じで基板の右側がPICKit2につながるピンで、素子は基板上のパターンにセロテープなどで仮止めしておきます。それを下の写真のように洗濯バサミで挟んで基板に押しつけます。あとは基板ごとPICKit2につなげばなんの問題もなく書き込みできました。

Dscf1035x50_2

| | コメント (0) | トラックバック (0)

赤外線送信アダプタの製作

「FMSやってみました」に書いたようにプロポを格安で譲っていただいたので、今度は赤外線送信アダプタを製作しました。

Dscf1038_2

やたらと大きいケースがついていますが、中身はこんなふうにスカスカです。

Dscf1041

スイッチは一方が送信出力切替え(赤外線LEDを1回路だけ使用/全部使用の切替え)とあとは周波数切替え用の予備です。電源は全てプロポからもらい、PIC用の電源は基板上の3端子レギュレータ(7805互換品、そのへんにあったもの)で5Vを作っています。

回路は下記の通りで、そのへんにあったPIC12F683を使っています。(こればっかり?)

Irtx

最初のうちはプロポ本体とは別にバッテリーを内蔵しようとしていたため、電源電圧検出用にする予定の可変抵抗がはいっていますが、AD入力できるピンでなかったため、無駄な回路になっています。

プログラムはこれだけです。プロポからの信号に従って「12F683のPWM出力機能を動作させたり、停止したりしているだけ」です。送信周波数の切替えも設定する値を変えるだけで実現しています。(実際には38kHzのみ確認済)

先日"Indoor Airplae world"で紹介されていた455kHzの受光素子への対応も設定を2~3箇所変えるだけで大丈夫なはずですが、受光素子を入手していないため未確認です。

~~プログラム~~

//
// 赤外線送信アダプタ用プログラム
//
//
#include "PIC12F683.h"

//
//Pin 1 VDD
//Pin 2 GP5/         T1CKI/         IOC   // NC
//Pin 3 GP4/AN3/                    IOC   // PROPO_SIG
//Pin 4 GP3/         T1G/           IOC/*MCLR // MODE_SW(38/57kHz)
//Pin 5 GP2/AN2/COUT/T0CKI/CCP1/INT/IOC   // LED_OUT
//Pin 6 GP1/AN1/CIN-/               IOC   // ICSPCLK
//Pin 7 GP0/AN0/CIN+/               IOC   // ICSPDAT
//Pin 8 VSS
//

//
// Timer0
// Timer1
// Timer2 CCP Mode (PR2,TMR2,CCPR1H,CCPR1L for LED_OUT)
//
//

#define LED_OUT gpio.2
#define mode gpio.3   // Pin4
#define propo gpio.4   // Pin3

#define pr2_38k 53
#define pr2_38k_on 17
#define pr2_57k 35
#define pr2_57k_on 12
#define ccp1con_val 0x0c

void ir_out_on(void)
{
if (mode){ccpr1l = pr2_38k_on;}
else {ccpr1l = pr2_57k_on;}
}

void ir_out_off(void)
{
ccpr1l = 0;
}

void main(void)
{
//
trisio = 0x38;    // GPIO3,4,5は入力, 他は出力
ansel = 0x00;    // 全ピンデジタル指定
osccon = 0x78;

// Set CCP Mode PWM
if (mode){pr2 = pr2_38k;} else {pr2 = pr2_57k;};
ccpr1l = 0;    // duty 0%
ccp1con = ccp1con_val;
t2con = 0x04;

// Wait for OSC stable
while(osccon.2==0);

while(1){
  if (propo){
   ir_out_off();
  }
   else {
   ir_out_on();
  };
}
}

~~ここまで~~

| | コメント (0) | トラックバック (0)

« 2009年1月 | トップページ | 2009年3月 »