2016-05-28 17:50 | カテゴリ:PIC応用回路
現在の仕様は、SWでサーボを決まった角度に振る、いわゆるON・OFFの制御です。
できれば、模型の仕様によっては、VRを操作してRCサーボの動きをVRに比例的に動作させたい場合もあるかと思い、検討してみました。
ミッドレンジのPICの16F876には、AD変換機能複数CH分が内蔵されています。
今回は、PINの数の制限もあるので、RA0ポートに備わっている、AN0のCHを一つ使用することにしました。

まずは、動作状況をご覧ください。



(注)一番上のLEDは、AD変換にRA0を使いましたので、点灯しません。

さて、AD変換を利用する方法は、それほど難しくありません。
手順的には

割り込み処理を使用しない場合

1)使用するポート(今回はRA0)を入力モードに設定する。

2)A/Dモジュールの構成を設定 (初期化処理)
  アナログポート、基準電圧ポート、デジタルポートを構成 ADCON1/PCFG0-3
3)A/D変換クロックを選択 ADCON0/ADCS0-1

4)A/DモジュールをON状態にする ADCON0/ADON

5)入力チャネル指定(今回はRA0)

6)A/D入力ポートを選択 ADCON0/CHS0-2

7)サンプル/ホールド・コンデンサ充電時間確保として、入力取得時間経過を待つ(20マイクロ秒)

8)変換開始を指示 変換開始ビットを設定 ADCON0/GO=1

9)変換終了確認
  変換開始ビットがクリアされるのを周期的にチェックする ADCON0/GO=0?

10)変換結果読み込み
   変換結果レジスタを読み込む ADRESH,ADRESL

11)次の変換のために(5)から必要に応じて実行

文書にすると長いようですが、実際は簡単です。

//---------------------------------------------
// PICのPORT設定の初期化 AD変換RA0ポートに設定
//---------------------------------------------
//PICのポート設定
ADCON0 = 0b10000001; //アナログ使用AD0
//ADはRA0 結果はADRESHに左寄せ8ビット
ADCON1 = 0b00001110; //For A/D0 & degital I/O
TRISA = 0b00000001; // A/D変換はRA0で行うのでRA0を入力に設定

および

//-------------------------------------------------------------------
// RA0のchでAD変換を実行し結果をservoに代入する
// AD変換結果は0-256となるので、250以上は250として処理
//-------------------------------------------------------------------

void ad_conv(void) {
ADCON0 = 0b10000001; // AD変換準備RA0チャンネル
__delay_us(20); // 20usecの準備待ち
GO = 1; // AD変換開始
while (GO) {
// GOビットが1の間待つ(0になるまで待つ)
}
servo = ADRESH;
if (servo >= 250) servo = 250;

}

が、AD変換部分を記述したところです。
GOの変数は、AD変換の開始を指示(1にする)すると同時に、AD変換が完了(0になる)した合図にもなっています。
また、サーボの処理の部分を一部変更します。

//------------------------------------------------------------------
// TMR0に割り込み時間をセットして、サーボ信号出力をONに
// 660マイクロ秒をDelay関数で待って、
// TMR0に時間をセットして割り込み処理を許可するが、そのまま割り込み
// 発生をLOOPで待ち、割り込み検出後に、ポートをOFFにして次の処理にすすむ
//------------------------------------------------------------------

void sv_on(void) {

//------- 変更分 -------------------------------------------
// target = parameter[portcnt][2]; //サーボ設定値を読み取り(値=0-255)
//
// if (target != current) {
// if (target <= current) current = current - step; //目標値が現在値よりちいさければstepを減算
// else current = current + step; //そうでなければ加算
// if (current <= 0) current = 0; //下限値チェック
// if (current >= 250) current = 250; //上限値チェック
// }
// servo = current; //値(0-255)をservoに渡す
//--------ここまで--------------------------------------------

ad_conv(); // AD変換実行。結果はservoに格納
port_off(); //サーボ接続ポートをON(負論理)

__delay_us(660); //サーボ制御パルスの最初の基本部分750マイクロ秒をここで指定する

TMR0 = servo;

T0IF = 0; // TMR0 割り込みフラッグクリア
T0IE = 1; // タイマー割り込み解除
while (T0IF == 0) {

// TMR0割り込みが発生するまで待つ
}
}


なお、SW入力部分は使用しませんから、今回はコメントアウトしていきます

//---------------------------------------------
// サーボの制御はAD変換で行うのでSWは使用しない
//---------------------------------------------


// if (sw0 == 0)parameter[12][2] = 0; //SWがON(0)ならサーボパラメータを20に
// else {
// parameter[12][2] = 250; //そうでなければ、250にセット
// }

また、RA0はLEDには使用しませんので、メインのLOOP部分は

//-----------------------------------------------------------
// 配列の設定データにしたがって、LEDを接続したポートをON/OFFする
//-----------------------------------------------------------
// ADにRA0を使用するためportcntは、1から13とする
//-----------------------------------------------------------

for (portcnt = 1; portcnt <= 13; portcnt++) {

if (parameter[portcnt][0] == scnt) seri();
if (parameter[portcnt][0] == 0) rndm();
if (parameter[portcnt][0] == 13) regular();
if (parameter[portcnt][0] == 14) port_pwm();
if (parameter[portcnt][0] == 15) sv_on();
}

このように修正します。

最終的なプログラムをここに置きます。

v030_AD.txt


御参考になれば幸いです。

管理者のみに表示する