目次

Ultra sonic sensor

 5ピンの超音波センサーを接続して、距離を電圧に変換して
 出力できないかと相談されました。



 5ピンの信号を調べると、以下となっています。

 TRG、ECHOがあるので、4ピンの超音波センサーと同じ
 制御をすればよいのではと考えました。



 いろいろと情報を集めてみると、制御は4ピンの場合と
 同じだとか。それならと、PIC12F1501と超音波センサー
 およびD/A変換器の接続を考えて、次の回路にしました。



 TRG、ECHOは、2、3ピンに接続します。

 TRGから10us以上のHパルスを与え、ECHOのHパルス幅を時間で
 カウントすればよいとしました。




 PIC12F1501は、3、7ピンにD/A変換器の出力を接続できるので
 OPアンプをバッファにして、インピーダンスによる電圧変動を
 おさえます。

 計測結果の電圧を受け取るマイコンが、3.3Vの電源電圧であると
 言われていたので、OPアンプの出力電圧が3.5V程度になるように
 デバイスを選んで対応。

 計測結果の電圧を受け取る側が、IchigoJamであれば
 VOUTXをIN_2に接続し、GNDとGNDを接続。

 IchigoJamのBASICでは、ANA(2)で距離に相当する電圧の
 換算値を取得できます。

 TOVERXは、計測距離が4m以上というときに、'H'を出力。

 回路が決まれば、PIC12F1501の動作を考えます。

 ECHOがHになっている時間を計測すればよいので、Timer1の
 ゲート処理を使います。

 Timer1に関係するブロック図を眺めて検討。



 Timer1のカウンタ(TMR1H、TMR1L)のクロックソースは、Fosc/4を
 1/4にして与えます。

 ECHOは、T1Gから入れて'H'になっているときだけ、カウンタを
 インクリメント。

 ECHOがH→Lになったとき、計測終了となるので、割込みハンドラ
 から、イベント発生をフラグ通知します。フラグで通知されたら
 計算にもっていきます。

 計測開始は、タイマー割込みで対処すると考え、主となる処理は
 次のように定義しました。

    /* execute */
    if ( EFLAG == ON ) {
      /* clear flag */
      EFLAG = OFF ;
      /* clear */
      TMR1L = 0 ;
      TMR1H = 0 ;
      /* start timer1 */
      T1CON.TMR1ON = ON ;
      /* indicator */
      TOVER = OFF ;
      /* send start trigger */
      TRG = ON ;
      for ( i = 0 ; i < 160 ; i++ ) ;
      TRG = OFF ;
    }
    /* sensor handling */
    if ( SFLAG == ON ) {
      /* clear flag */
      SFLAG = OFF ;
      /* stop timer1 */
      T1CON.TMR1ON = OFF ;
      /* get timer counter */
      dl = TMR1L ;
      dh = TMR1H ;
      xtim = dh * 256 + dl ;
      /* calculate distance 100mm : 588 us */
      xlen = (UBYTE)((32.0 * xtim) / DEFX) ;
      /* upper limiter */
      if ( xlen > 21 ) { xlen = 21 ; }
      /* calculate voltage */
      dac_write(xlen);
    }

 イベント通知フラグEFLAGで、タイマー割込みから計測開始の
 トリガーを貰います。
 EFLAGのトリガーで、次のシーケンスを実行。
  1. Timer1のカウンタクリア
  2. Timer1動作開始
  3. オーバーフローの信号をクリア
  4. TRGのHパルス出力
 イベント通知フラグSFLAGで、計測終了を判断し、カウンタから  値を引き抜いて電圧に換算。  Timer1のカウンタがオーバーフローする可能性があるので  その対応もしておきます。 /* sensor handling */ if ( SFLAG == ON ) { /* clear flag */ SFLAG = OFF ; /* stop timer1 */ T1CON.TMR1ON = OFF ; /* get timer counter */ dl = TMR1L ; dh = TMR1H ; xtim = dh * 256 + dl ; /* calculate distance 100mm : 588 us */ xlen = (UBYTE)((32.0 * xtim) / DEFX) ; /* upper limiter */ if ( xlen > 21 ) { xlen = 21 ; } /* calculate voltage */ dac_write(xlen); } /* sensor handling (overflow) */ if ( OFLAG == ON ) { /* clear flag */ OFLAG = OFF ; /* impress */ TOVER = ON ; } /* execute */ if ( EFLAG == ON ) { /* clear flag */ EFLAG = OFF ; /* clear */ TMR1L = 0 ; TMR1H = 0 ; /* start timer1 */ T1CON.TMR1ON = ON ; /* indicator */ TOVER = OFF ; /* send start trigger */ TRG = ON ; for ( i = 0 ; i < 160 ; i++ ) ; TRG = OFF ; }  Timer1に関係する設定をまとめます。 T1CON = 0x24 ; T1GCON = 0xc0 ; /* select RA4 */ APFCON.T1GSEL = OFF ; /* enable peripheral TMR1GE */ PIE1.TMR1GE = ON ; /* enable TMR1 overflow interrupt */ PIE1.TMR1IE = ON ; /* enable peripheral interrupt */ INTCON.PEIE = ON ;  内蔵クロックの16MHzを利用して、Timer1のカウンタには  クロックとして1MHzを与えます。これで計測の時間分解能  は1usとできます。  T1GがHの間に、ゲートを開いているようにするため  T1GCONレジスタの上位2ビットをセットします。  T1Gは、ピン3、4のどちらかから入力できるので  APFCON.T1GSELビットの論理値で選択。  T1GのH→Lでの割込みとオーバーフロー割込みを  発生させるように、レジスタの該当ビットを指定  しておきます。  計測開始のトリガーを貰うためにTimer0を使います。  Timer0に関係する初期化は以下。 /* 16MHz/4 = 4MHz (Fosc) Fosc/4 = 1MHz 1MHz/4 = 250kHz prescaler = 1:4 */ OPTION_REG = 0x01 ; /* 256 - 250 = 6 */ TMR0 = CNTBEGIN ; /* enable timer0 overflow interrupt */ INTCON.TMR0IE = ON ;  1msごとに割込みが発生するので、割込みの回数を  数えて100msごとにイベント通知フラグをセットと  します。  割込みハンドラは、以下としました。 void interrupt(void) { /* generate trigger 1ms interval */ if ( INTCON.T0IF == ON ) { /* clear flag */ INTCON.T0IF = OFF ; /* initialize */ TMR0 = CNTBEGIN ; /* increment */ xcnt++ ; /* judge */ if ( xcnt == 100 ) { xcnt = 0 ; EFLAG = ON ; } } /* echo handling */ if ( PIR1.TMR1GIF == ON ) { /* clear flag */ PIR1.TMR1GIF = OFF ; /* set flag */ SFLAG = ON ; } /* echo handling (overflow) */ if ( PIR1.TMR1IF == ON ) { /* clear flag */ PIR1.TMR1IF = OFF ; /* set flag */ OFLAG = ON ; } }  計測できたパルス幅から比例配分でD/A変換器の出力電圧を  計算しました。  100mm : 588us : 16 として、100mmでD/A変換器に16を与えます。  D/A変換器は0から31で動作するので、16だと2.5Vくらいを出力。  D/A変換器に31を与えたとしても、OPアンプの出力が電源電圧より  1.5Vほど低い3.5Vになります。受ける側のマイコンのA/D変換部の  破損はないでしょう。  D/A変換器の出力が受ける側の破壊がないようにリミッター  を入れて対応。 /* calculate distance 100mm : 588 us */ xlen = (UBYTE)((32.0 * xtim) / DEFX) ; /* upper limiter */ if ( xlen > 21 ) { xlen = 21 ; } /* calculate voltage */ dac_write(xlen);  D/A変換器の初期化と出力は専用関数で扱います。 void dac_write(UBYTE x) { DACCON1 = (0x1f & x); } void dac_init(void) { /* reference Vdd */ DACCON0.DACPSS = OFF ; /* enable DAC output #1 */ DACCON0.DACOE1 = ON ; /* use DAC */ DACCON0.DACEN = ON ; }  まとめたソースコードは以下。 /* redefine data type */ typedef unsigned char UBYTE ; typedef unsigned int UWORD ; typedef unsigned long ULONG ; typedef union { struct { unsigned B0:1; unsigned B1:1; unsigned B2:1; unsigned B3:1; unsigned B4:1; unsigned B5:1; unsigned B6:1; unsigned B7:1; } BIT ; unsigned char DR ; } FLAGSP ; volatile FLAGSP xflags ; volatile UBYTE xcnt ; volatile UBYTE dh ; volatile UBYTE dl ; volatile UWORD xtim ; volatile UBYTE xlen ; #define EFLAG xflags.BIT.B0 #define SFLAG xflags.BIT.B1 #define OFLAG xflags.BIT.B2 #define OFF 0 #define ON OFF+1 #define CNTBEGIN 6 #define DEFX 588 #define TOVER PORTA.F1 #define ECHO PORTA.F4 #define TRG PORTA.F5 /* function prototype */ void init_usr(void); void dac_write(UBYTE x); void dac_init(void); /* interrupt handler */ void interrupt(void) { /* generate trigger 1ms interval */ if ( INTCON.T0IF == ON ) { /* clear flag */ INTCON.T0IF = OFF ; /* initialize */ TMR0 = CNTBEGIN ; /* increment */ xcnt++ ; /* judge */ if ( xcnt == 100 ) { xcnt = 0 ; EFLAG = ON ; } } /* echo handling */ if ( PIR1.TMR1GIF == ON ) { /* clear flag */ PIR1.TMR1GIF = OFF ; /* set flag */ SFLAG = ON ; } /* echo handling (overflow) */ if ( PIR1.TMR1IF == ON ) { /* clear flag */ PIR1.TMR1IF = OFF ; /* set flag */ OFLAG = ON ; } } void main(void) { UBYTE i ; /* user initialize */ init_usr(); /* endless loop */ while ( ON ) { /* sensor handling */ if ( SFLAG == ON ) { /* clear flag */ SFLAG = OFF ; /* stop timer1 */ T1CON.TMR1ON = OFF ; /* get timer counter */ dl = TMR1L ; dh = TMR1H ; xtim = dh * 256 + dl ; /* calculate distance 100mm : 588 us */ xlen = (UBYTE)((32.0 * xtim) / DEFX) ; /* upper limiter */ if ( xlen > 21 ) { xlen = 21 ; } /* calculate voltage */ dac_write(xlen); } /* sensor handling (overflow) */ if ( OFLAG == ON ) { /* clear flag */ OFLAG = OFF ; /* impress */ TOVER = ON ; } /* execute */ if ( EFLAG == ON ) { /* clear flag */ EFLAG = OFF ; /* clear */ TMR1L = 0 ; TMR1H = 0 ; /* start timer1 */ T1CON.TMR1ON = ON ; /* indicator */ TOVER = OFF ; /* send start trigger */ TRG = ON ; for ( i = 0 ; i < 160 ; i++ ) ; TRG = OFF ; } } } /* define function body */ void init_usr(void) { /* select 16MHz */ OSCCON = (15 << 3) | 0x03 ; /* disable A/D converter */ ADCON0.ADON = OFF ; ADCON2 = 0 ; ANSELA = 0 ; /* initialize D/A converter */ dac_init(); /* disable compare module */ CM1CON0.C1ON = OFF ; CM1CON0.C1OE = OFF ; /* I/O state */ PORTA = 0x00 ; /* I/O directions */ TRISA = 0x1C ; /* bit0,1,5 as output , others as input */ /* pull up */ WPUA = 0x10 ; /* initialize timer 0 */ { /* 16MHz/4 = 4MHz (Fosc) Fosc/4 = 1MHz 1MHz/4 = 250kHz prescaler = 1:4 */ OPTION_REG = 0x01 ; /* 256 - 250 = 6 */ TMR0 = CNTBEGIN ; /* enable timer0 overflow interrupt */ INTCON.TMR0IE = ON ; } /* initialize timer 1 */ { T1CON = 0x24 ; T1GCON = 0xc0 ; /* select RA4 */ APFCON.T1GSEL = OFF ; /* enable peripheral TMR1GE */ PIE1.TMR1GE = ON ; /* enable TMR1 overflow interrupt */ PIE1.TMR1IE = ON ; /* enable peripheral interrupt */ INTCON.PEIE = ON ; } /* enable general interrupt */ INTCON.GIE = ON ; /* clear flags */ xflags.DR = 0 ; /* initialize variables */ xcnt = 0 ; xtim = 0 ; xlen = 0 ; } void dac_write(UBYTE x) { DACCON1 = (0x1f & x); } void dac_init(void) { /* reference Vdd */ DACCON0.DACPSS = OFF ; /* enable DAC output #1 */ DACCON0.DACOE1 = ON ; /* use DAC */ DACCON0.DACEN = ON ; }  浮動小数点の計算が含まれているので、フラッシュROMの  最大容量のうちの63%となりました。  SRAMの容量を増やさないように、イベント通知フラグは  1ビットで扱えるようにします。 typedef union { struct { unsigned B0:1; unsigned B1:1; unsigned B2:1; unsigned B3:1; unsigned B4:1; unsigned B5:1; unsigned B6:1; unsigned B7:1; } BIT ; unsigned char DR ; } FLAGSP ; volatile FLAGSP xflags ; #define EFLAG xflags.BIT.B0 #define SFLAG xflags.BIT.B1 #define OFLAG xflags.BIT.B2  半田付けした基板は、以下。  35mmx45mmにまとめられました。  ISPができるように、6ピンコネクタを  つけ、リセットスイッチも入れました。  IchigoJamのプログラムは、以下。 10 ' test usensor 20 A = ANA(2) 30 ? A 40 WAIT 60 50 GOTO 20 60 END

目次

inserted by FC2 system