2.4GHz版プロポ作製-PPM信号制御編

プロポ用のPPM信号出力が可能になりました。

1.動作仕様
ボリューム1の値をAN0で読み出してCH1のパルス幅に反映。
ボリューム2の値をAN1で読み出してCH2のパルス幅に反映。
USB経由でPCへAN0、AN1の読み出し値と、CH1、CH2のパルス幅値を送信。

PPM信号仕様
  チャンネル数 7チャンネル
  フレーム周期 22msec
  各チャンネルのスタートパルス幅 300usec
        
2.動作波形
下波形はTimer割り込みで生成しているフレーム周期出力
上波形はCCPモジュールのコンペア割り込みで生成してるPPM信号出力


























3.プログラムの概要
PICに搭載されていたCCPモジュールのコンペア機能のおかげでフローは非常にシンプルです。(プログラムはSimple is Best!)

1)PPMのフレーム周期でTimer1割り込みをグルグル回しておく。
2)PIC18シリーズの割り込みは2レベルしか無い(買ってから判ったので仕方ない・・・)ので、Timer1割り込みとはズレたタイミングから、PPM信号のフレーム開始位置を定義。
3)Timer1のカウント値とCCP1のコンペア値がマッチしたら割り込みを発生させる様にする。
4)CCP1割り込みの度に、ポート出力と次のCCP1割り込みの発生タイミングを書き換える。
これだけ!

メインループ
PPM信号のシンク期間中に処理時間が食われるADC変換とUSBへの送信を済ませるようにしています。 我ながら良く出来ました(笑)

    while(1)
    {
        #if defined(USB_INTERRUPT) // See HardwareProfile.h
            if(USB_BUS_SENSE && (USBGetDeviceState() == DETACHED_STATE))
            {
                USBDeviceAttach();
            }
        #endif
   
if(adc_flag == TRUE)
{
adc_flag = FALSE;
ADread0 =0;
SetChanADC(ADC_CH0);
for( i=0;i<4;i++) // 念のためノイズ対策として平均を取る為にAD値を4回積算
{
ConvertADC(); // AD変換開始
       while( BusyADC());             // AD変換待ち
       ADread0 += ReadADC(); // AD読込み
}

ADread1 =0;
SetChanADC(ADC_CH1);
for( i=0;i<4;i++)
{
ConvertADC();
       while( BusyADC());
       ADread1 += ReadADC();
}

ADread0 = ADread0 >>2; // AD値を平均
ADread0 = ADread0*5; // AD値を2.5倍
ADread0 = ADread0 >>1;
ch1param = ADread0+PLS_min_def; // CH1のパルス幅値

ADread1 = ADread1 >>2;
ADread1 = ADread1*5;
ADread1 = ADread1 >>1;
ch2param = ADread1+PLS_min_def; // CH2のパルス幅値

PrintADC(ADread0,ADread1,ch1param,ch2param); //USBへAD値を出力
}
    }//end while


PPM信号生成処理(割り込み処理)
ROM容量は余裕なので、PPMパルスの変化ポイント毎にswitch-case文でベタ書きしていますので、一目瞭然のコードです。(しつこく Simple is Best! と叫ぶ)

// PPM信号生成用の割り込みルーチン
// RB6 is PPM output signal
void PPM_int(void)
{
if(PIR1bits.CCP1IF == 1)
{
switch(ccpstep){
case 0:
LATBbits.LATB6 =1;
ccpcount +=PLS_sep_def;
break;
case 1:
LATBbits.LATB6 =0;
ccpcount +=ch1param;
// ccpcount +=PLS_max_def;
break;
case 2:
LATBbits.LATB6 =1;
ccpcount +=PLS_sep_def;
break;
case 3:
LATBbits.LATB6 =0;
ccpcount +=ch2param;
// ccpcount +=PLS_min_def;
break;
case 4:
LATBbits.LATB6 =1;
ccpcount +=PLS_sep_def;
break;
case 5:
LATBbits.LATB6 =0;
ccpcount +=PLS_nom_def;
break;
case 6:
LATBbits.LATB6 =1;
ccpcount +=PLS_sep_def;
break;
case 7:
LATBbits.LATB6 =0;
ccpcount +=PLS_nom_def;
break;
case 8:
LATBbits.LATB6 =1;
ccpcount +=PLS_sep_def;
break;
case 9:
LATBbits.LATB6 =0;
ccpcount +=PLS_nom_def;
break;
case 10:
LATBbits.LATB6 =1;
ccpcount +=PLS_sep_def;
break;
case 11:
LATBbits.LATB6 =0;
ccpcount +=PLS_nom_def;
break;
case 12:
LATBbits.LATB6 =1;
ccpcount +=PLS_sep_def;
break;
case 13:
LATBbits.LATB6 =0;
ccpcount +=PLS_nom_def;
break;
case 14:
LATBbits.LATB6 =1;
ccpcount +=PLS_sep_def;
break;
case 15:
LATBbits.LATB6 =0;
ccpcount =0; // CCPコンペア発生させない(SYNCパルス期間)
adc_flag =TRUE; // SYNCパルス中にADC変換
break;
}

CCPR1 =ccpcount; // CCP1コンペア値更新
ccpstep++;
PIR1bits.CCP1IF =0; // CCP1割り込み要求クリア
}
else if(PIR1bits.TMR1IF == 1)
{
LATBbits.LATB7 = !LATBbits.LATB7; // RB7出力反転
ccpstep =0; // CCP1初期化
ccpcount = Tim1_sta_def+PLS_res_def;
CCPR1 =ccpcount;
WriteTimer1(Tim1_sta_def); // Timer1 再セット
PIR1bits.TMR1IF =0; // Timer1 割り込み要求クリア
}

}//end ppm_int

P.S.
明日は部品を買ってきてTx1送信モジュールに繋ぐ予定です。





コメント

このブログの人気の投稿

ARM用クロスコンパイラのビルド(Windows8+Cygwin)

Raspberry Pi のsleep時間測定

Quartus2 V13.1 ~エントリー編 HDL回路から回路図用シンボルを作成する~