目次

積分回路利用(割込み活用)

 積分回路では、電荷のキャパシタへの充放電をプログラムで計測して
 います。

 充放電処理の時間を計測するには、アナログコンパレータとインプット
 キャプチャ処理を組み合わせて対応します。

 アナログコンパレータをOPアンプを利用した回路にすると、以下。



 電源電圧Vccの2/3よりも、反転端子の入力電圧Vinが上回ると
 出力電圧Voutは、0V近くまで下がります。通常、VoutはVccに
 近い電圧になります。

 PIC16F627Aは、アナログコンパレータを内蔵しています。

 アナログコンパレータによる電圧検出で、割込みを発生させ
 られるので、使えるようになっておくと、ポーリングによる
 指定ピンの電圧監視処理をしないで済ませられます。

 スイッチを接続すると、ハードウエア上は次のようになります。



 回路を見てわかることは、コンパレータの出力がHかLか
 は、反転入力、非反転入力の接続で変わります。

 回路の接続を指定するには、アナログコンパレータ関係の
 レジスタCMCONで設定します。



 レジスタのビット7、6をみると、アナログコンパレータの
 出力値を参照できます。組み合わせは、以下。

 C2OUT 1:Vin+ > Vin- 0:Vin+ < Vin-
 C1OUT 1:Vin+ > Vin- 0:Vin+ < Vin-

 レジスタのビット5、4を使うとC2OUT、C1OUTの出力を
 反転できるようになっています。

 C2INV 1:inverse 0:normal
 C1INV 1:inverse 0:normal

 ここまでで、アナログコンパレータは2個あることがわかります。
 ピンアサインで確認できます。




 PICは、ひとつのピンに複数の機能を割り当てているので
 アナログコンパレータを使うのか、他の機能にするのか
 を指定します。

 CM2からCM0の組合せによる接続は、以下。



 アナログコンパレータを2つ使う場合、100を設定します。

   CMCON = 0x40 ;

 アナログコンパレータが2つあるので、プッシュスイッチ
 を2つ利用できるようにシステムを構成できます。



 プッシュスイッチを押すと、比較電圧よりも小さくなり
 そのときに割込みを発生するように指定します。


   CMCON = (3 << 4) | 0x40 ;

 プッシュスイッチSW1、SW2をスタート、ストップに役割
 分担しておけば、タイマー割込みとシフトレジスタでの
 判定処理よりも簡単にスイッチ状態の変化を読取れます。

 割込みを使うため、アナログコンパレータ関係のレジスタ
 リストを確認します。



 レジスタリストから必要なビット処理を指定していきます。

 周辺モジュールの該当割込み許可

    PIE1.CMIE = ON ;

 周辺モジュールの割込み許可

    INTCON.PEIE = ON ;

 ポートAの入出力方向指定

    TRISA = 0xff ;

 ここまでの内容を、初期化関数の中に入れます。

void usr_init(void)
{
  /* port directions */
  TRISA = 0xff ;
  /* initialize analog comparator */
  {
    /* select analog comparator channel and invert */
    CMCON = (3 << 4) | 0x40 ;
    /* enable analog comparator interrupt */
    PIE1.CMIE = ON ;
    /* enable peripheral interrupt */
    INTCON.PEIE = ON ;
  }
  /* enable global interrupt */
  INTCON.GIE = ON ;
}

 割込みハンドラは、アナログコンパレータの割込みを
 判定し、どちらのチャネルかで該当するフラグを設定
 します。

void interrupt(void)
{
  /* analog comparator */
  if ( INTCON.CMIF == ON ) {
    /* clear flag */
    INTCON.CMIF = OFF ;
    /* judge */
    if ( CMCON.C2OUT == ON ) { AC2FLAG = ON ; }
    if ( CMCON.C1OUT == ON ) { AC1FLAG = ON ; }
  }
}

 イベントフラグができれば、main関数内部の該当
 処理の記述は単純になります。

 積分回路では、キャパシタに電荷をチャージしてから
 放電により電荷がなくなるまでの時間を、タイマーで
 カウントさせるようにします。



 動作シーケンスは、次のようにします。
  1. ターゲットピンに1を出力
  2. ターゲットピンを出力に設定
  3. 時間待ち
  4. ターゲットピンを入力に設定
  5. カウンタ値をクリア
  6. 割込み処理のイベントフラグ待ち
  7. カウンタ値をリード
  8. カウンタ値に応じた処理実行
 1から4はひとつの関数にまとめられます。 void charge(void) { /* impress 1 */ PORTA.F0 = ON ; /* set RA0 as output pin */ TRISA.F0 = 0 ; /* delay */ Delay_ms(1); /* set RA0 as input pin */ TRISA.F0 = 1 ; }  タイマーカウンタの値をクリアして  放電を開始するコードは、以下。 /* clear counter */ TMR1H = 0 ; TMR1L = 0 ; /* enable timer 1 */ T1CON.TMR1ON = ON ;  カウントを開始してしまえば、アナログコンパレータ  からの通知を待つだけになります。 if ( CM1FLAG == ON ) { /* clear flag */ CM1FLAG = OFF ; /* stop count */ T1CON.TMR1ON = OFF ; /* get counter */ xcnt = TMR1H ; xcnt <<= 8 ; xcnt |= TMR1L ; }  充放電時間幅を求めるには、インプットキャプチャを利用します。  2つのアナログコンパレータを利用し、開始と終了の  トリガーを受けて、各時のタイマーカウンタ値を記録  するのが、インプットキャプチャになります。  カウンタを、フリーで自動インクリメントさせておき  2つのアナログコンパレータ割込みで、カウンタ値を  保存し、その差分Nを求めると、周期xNで時間差を  計算できます。  OPアンプで構成したウィンドウコンパレータが、この  処理と等価です。  キャパシタの放電では、2つの電位でトリガーをかけて  カウンタ値を取得します。放電するには、充電が必要と  なるので、動作シーケンスを考えます。  利用する回路は、以下。  充電開始   充電開始のトリガーには、タイマー割込みを使います。   1秒ごとに、タイマー割込みでイベント通知フラグを   セットし、1ms充電します。 if ( TFLAG == ON ) { /* clear flag */ TFLAG = OFF ; /* disable analog comparator */ CMCON = 0x07 ; /* stop count */ T1CON.TMR1ON = OFF ; /* charge */ charge(); /* clear counter */ TMR1H = 0 ; TMR1L = 0 ; /* start count */ T1CON.TMR1ON = ON ; /* enable analog comparator */ CMCON = 0x04 ; /* clear state */ state = 0 ; }  コンパレータ1割込み   コンパレータ1の割込み発生をイベント通知フラグで検出。   イベント通知フラグを利用し、カウンタ値を保存。 if ( AC1TFLAG == ON ) { /* clear flag */ AC1TFLAG = OFF ; /* store counter value */ cmpcnt1 = TMR1H ; cmpcnt1 <<= 8 ; cmpcnt1 |= TMR1L ; /* update state */ state++ ; }  コンパレータ2割込み   コンパレータ2の割込み発生をイベント通知フラグで検出。   イベント通知フラグを利用し、カウンタ値を保存。 if ( AC2TFLAG == ON ) { /* clear flag */ AC2TFLAG = OFF ; /* store counter value */ cmpcnt2 = TMR1H ; cmpcnt2 <<= 8 ; cmpcnt2 |= TMR1L ; /* update state */ state++ ; }  計算   状態変数を利用し、2カウンタ値を取得したことを   確認し、計算に入ります。 if ( state == 2 ) { /* clear */ state = 0 ; /* disable analog comparator */ CMCON = 0x07 ; /* stop count */ T1CON.TMR1ON = OFF ; /* calculate */ if ( cmpcnt2 >= cmpcnt1 ) { cmpcnt = cmpcnt2 - cmpcnt1 ; } else { cmpcnt = cmpcnt1 - cmpcnt2 ; } }  ここまでで、状態変数と通知フラグだけを利用し  制御変数を利用した、for文でのシーケンスには  なっていないことに注意します。  組込みのファームウエアを作成する場合、タイマー割込みと  通知フラグを使ったイベント駆動処理にするのが定石です。 (under construction)

目次

inserted by FC2 system