目次
前
次
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のトリガーで、次のシーケンスを実行。
- Timer1のカウンタクリア
- Timer1動作開始
- オーバーフローの信号をクリア
- 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
目次
前
次