以前に人体(焦電型赤外線)検出ユニットを作成しましたが、今回は超音波を利用した人体検出ユニットを作成してみました。
超音波を利用した人体検出や距離計は良く見かけますが、結構複雑な回路構成なので作成にあたっては、少し躊躇してしまいます。
そこで、何とかもっと簡単に出来ないものかと考えてみました。
今回は、基本動作の確認もあり、30cm前方の物体(人体)を検出し、LEDを点灯させることのみにしました。
<超音波センサー>
日本セラミック社の送信用(T40-16)、受信用(R40-16)を使用しました。
【特徴】
空中用超音波センサは、振動子として圧電セラミックを用い、超音波を発生、それを空中に放射あるいは逆に空中からの超音波信号を検知するセンサで、物体の存在判別や物体までの距離の測定等広い分野において利用できます。
<送信部分>
PICには、PWM(Pulse Width Modulation)モジュールを内蔵しているものがありますのでこれを利用します。
回路図を見てもお分かりのようにとても簡単です。コンデンサ1本でセンサーに接続するだけです。
40KHzの信号を2msec出力する例です。
Pwm_Init(40000);// 40kHz Pwm_Change_DutyEx((PR2 * 4) / 2);// デューティ比50% Pwm_Start();// 開始 Delay_ms(2);// 2msecスリープ Pwm_Stop();// 終了
<受信部分>
これもまた簡単で、低電圧オーディオ・パワーアンプのLM386を利用します。動作電圧も4V~12Vと手頃ですし、利得も20倍~200倍の設定が可能なので、今回のユニットには丁度良いと考えました。
通常は、この後に検波回路や、コンパレータ(比較)回路を通してから、PICに接続するのですが、今回は省略し、ソフトウエアで処理しました。
<処理の流れ>
タイプA/検波回路不要/最大値版
//********************************************************************** /* <超音波人体検出ユニット> */ //********************************************************************** #define LED PORTA.F2 #define SW PORTA.F3 //********************************************************************** unsigned int measurement() { unsigned int ad, max; unsigned char cnt; // max = 0; for (cnt = 0; cnt < 10; cnt++) { ad = Adc_Read(1); max = max < ad ? ad : max; } return (max); } //********************************************************************** void Pwm_Change_DutyEx(unsigned int duty_ratio) { CCPR1L = duty_ratio >> 2; CCP1CON.F6 = duty_ratio & 0b00000001; CCP1CON.F7 = (duty_ratio & 0b00000010) >> 1; } //********************************************************************** void main() { unsigned int ad, ave, offset; unsigned char buf[10], cnt, tmp; // OSCCON = 0b01110000; // クロックは8Mhz CMCON = 0b00000111; // コンパレータは使用しない。 ANSEL = 0b00000010; // AD1を使用する。 TRISA = 0b00111010; TRISB = 0b00001110; // Lcd_Custom_Config(&PORTB, 4, 5, 6, 7, &PORTA, 0, 7, 6); Lcd_Custom_Cmd(LCD_CURSOR_OFF); Lcd_Custom_Out(1, 1, "UltraSoundV2 "); Lcd_Custom_Out(2, 1, " JF3SFB 2007.12"); Delay_ms(1000); Lcd_Custom_Cmd(LCD_CLEAR); // Pwm_Init(40000); // 40kHz Pwm_Change_DutyEx((PR2 * 4) / 2); Pwm_Stop(); // LED = 0; offset = 512; // 1024÷2 // while (1) { // 40KHzの超音波を2msec間出力する。 Pwm_Start(); Delay_ms(2); Pwm_Stop(); Delay_ms(2); // 反射波を測定する。 ad = measurement(); // 測定値を表示する。 WordToStr(ad, buf); Lcd_Custom_Out(1, 1, buf); // 測定値をバー表示する。 tmp = ad / 57; for (cnt = 0; cnt < 16; cnt++) { if (tmp > cnt) Lcd_Custom_Chr(2, cnt + 1, 0xFF); else Lcd_Custom_Chr(2, cnt + 1, ' '); } // 測定値をオフセット値と比較し、検出していればLEDを1秒点灯する。 WordToStr(offset, buf); Lcd_Custom_Out(1, 9, buf); if (ad > (offset + 100)) { LED = 1; Delay_ms(1000); LED = 0; } // SWが押されていればオフセット値をセットする。 if (SW == 0) { offset = ad; } } } //**********************************************************************
タイプB/検波回路必要/平均値版
//********************************************************************** /* <超音波人体検出ユニット> */ //********************************************************************** #define LED PORTA.F2 #define SW PORTA.F3 //********************************************************************** unsigned int measurement() { unsigned int ad; unsigned char cnt; // ad = 0; for (cnt = 0; cnt < 50; cnt++) { ad += Adc_Read(1); } return (ad / 50); } //********************************************************************** void Pwm_Change_DutyEx(unsigned int duty_ratio) { CCPR1L = duty_ratio >> 2; CCP1CON.F6 = duty_ratio & 0b00000001; CCP1CON.F7 = (duty_ratio & 0b00000010) >> 1; } //********************************************************************** void main() { unsigned int ad, ave, offset; unsigned char buf[10], cnt, tmp; // OSCCON = 0b01110000; // クロックは8Mhz CMCON = 0b00000111; // コンパレータは使用しない。 ANSEL = 0b00000010; // AD1を使用する。 TRISA = 0b00111010; TRISB = 0b00001110; // Lcd_Custom_Config(&PORTB, 4, 5, 6, 7, &PORTA, 0, 7, 6); Lcd_Custom_Cmd(LCD_CURSOR_OFF); Lcd_Custom_Out(1, 1, "UltraSoundV2 "); Lcd_Custom_Out(2, 1, " JF3SFB 2007.12"); Delay_ms(1000); Lcd_Custom_Cmd(LCD_CLEAR); // Pwm_Init(40000); // 40kHz Pwm_Change_DutyEx((PR2 * 4) / 2); Pwm_Stop(); // LED = 0; offset = 512; // 1024÷2 // while (1) { // 40KHzの超音波を2msec間出力する。 Pwm_Start(); Delay_ms(2); Pwm_Stop(); Delay_ms(2); // 反射波を測定する。 ad = measurement(); // 測定値を表示する。 WordToStr(ad, buf); Lcd_Custom_Out(1, 1, buf); // 測定値をバー表示する。 tmp = ad / 57; for (cnt = 0; cnt < 16; cnt++) { if (tmp > cnt) Lcd_Custom_Chr(2, cnt + 1, 0xFF); else Lcd_Custom_Chr(2, cnt + 1, ' '); } // 測定値をオフセット値と比較し、検出していればLEDを1秒点灯する。 WordToStr(offset, buf); Lcd_Custom_Out(1, 9, buf); if (ad > (offset + 50)) { LED = 1; Delay_ms(1000); LED = 0; } // SWが押されていればオフセット値をセットする。 if (SW == 0) { offset = ad; } } } //**********************************************************************
いつものようにブレッドボード上で確認しました。
超音波センサー(送信&受信)は、小さな基板に固定し、ブレッドボードに差込めるようにしてあります。
左から、【超音波センサー】【PIC】【LCD】の順です。
超音波センサー部分を拡大した所です。(左側が受信、右側が送信)

PICとLCDの接続部分です。
LCDの1行目の左の数値は現在値、右はオフセット値です。
2行目は現在値をバー表示したものです。
上の波形は、送信波形です。2msec送信していますが、その後少し減衰しながら残存しています。
下の波形は、受信波形です。反射が無いので殆ど変化がありません。
超音波センサーの手前(約30cm)に物を翳してみた所です。
2msec後の受信波形では、約2V以上の変化があります。
この時に人体を検出したと判断し、LEDを1秒間点灯させます。
如何ですか?
とても簡単な回路ですが、当初の目的は達成できました。
これを応用して物体(人体)との距離を測定できるように改善強化していきたく考えております。