3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IoTLT (IoTや電子工作ネタなど)Advent Calendar 2024

Day 13

推しのマイコンPSoCの使い方 超音波距離計

Last updated at Posted at 2024-12-12

はじめに

PSoCというマイコンが好きです。PSoCは、センサーを創るのに適しています。今回は、例として、超音波距離計を作ってみましょう。
オシロスコープがあったら楽しいです。
書き込み部と本体を切り離していな状態で使うことを前提にしています。(接続部のピン以外にUARTが接続されています。)

はじめに

気温を20℃と仮定し、測定距離5m以内、精度1cm程度の距離計を作ってみましょう。

音速の近似式 S=331.5+0.61T (T=20℃の時343.7m/s)
image.png
image.png

スピーカー・マイクから障害物までの距離xは、超音波を出してマイクに帰ってくるまでの時間差tより x = St / 2 です(Sは音速)。
5m場合の時間差は t = 2x / S より 2 * 5 / 343.7 = 29.1 [ms] です。
1cm計測するのに要する時間を 同様に計算すると 2 * 0.01 / 343.7 = 58.2 [μs] となり、1 / (58.2 * 10-6) [s] = 17.2 * 103[Hz]から、時間差tを17.2 [kHz]以上の周波数の信号でカウントすれば1cm以上の精度で計測できます。今回は20kHzでカウントします。20KHzでカウントすると5mは29.1msなので、29.1 * 10-3 * 20 * 103 = 582 [Count]
なお、今回の測定器の周期Tは250[ms]、発振時間Tsは60[μs]とします。また、計測用カウンターは230[ms]でリセットします。
※なお、今回は計算中の遅れ等は考慮していません。

超音波スピーカー・マイク

使用する超音波スピーカー・マイクは以下の製品です。
image.png
https://akizukidenshi.com/catalog/g/g117716/
超音波センサ(送受信セット)秋月電子 (I-00120)
主な仕様
◎送信側(UT1612MPR)
・音圧レベル:115dBmin(0dB =0.02mPa)  測定条件:入力10Vrms、測定距離30cm
・最大入力電圧:20Vp-p
◎受信側(UR1612MPR)
・感度:-65dBA(0dB=1V/ubar)
◎共通仕様
・中心周波数:40k±1kHz
・-6dB 角:50度

超音波を発信するのに、スピーカーに40KHzの信号を入れる必要があります。スピーカーの回路は、信号(振幅・音量)を大きくするため交互に信号を入力します。なお、直流電圧がかかると故障するので、使っていない時は両端子ともOFFにする必要があります。
image.png

返ってきた超音波を受信する回路は、マイクで受けた信号を増幅した後、Band Pass Filter(BPF)を通して、コンパレータで検知します。
image.png

アプリケーションの作成

それでは作っていきましょう。

接続案

この時点では、まだ接続しませんが、想定してプログラムを作成します。

名称 PSoC側 備考
スピーカー(TX) P1[7] 極性なし
スピーカー(TX) P1[6] 極性なし
マイク(RX) P1[5] 極性なし
マイク(RX) P1[4] 極性なし
UART(RX) P12[6] 指定
UART(TX) P12[7] 指定

プロジェクトの作成

PSoC Creatorを起動し、プロジェクトを作成します。
デバイスは、前回のCY8CKIT-059を使用するので、CY8C5888LTI-LP097にしてください。TempleteはEmptyです。

ハードウェア

クロック部

まずは、クロックを指定します。Clocksをダブルクリックします。
image.png

今回は時間がシビアだと思うので最高速の48MHzにBus Clockを設定します。ただし、直接IMOを48MHz(±5%)に設定すると、偏差がUARTの範囲内に入らないので以下の様に設定します。(PSoCの内部クロックで利用)

No Clock種別 設定
1 IMO OSC 12MHz ± 3%
2 PLL Enable, INPUT:IMO(12MHz), Desired 48MHz
3 Master Clock INPUT: PLL_OUT(48MHz), Divider: 1
4 Bus Clock Divider: 1

以下の画面で設定する項目(どれでも良いです)をダブルクリックするとClockのFlowが表示されます。GUIで上記の設定をしていきます。
image.png

image.png

全体のタイミング

Counter_1はスケジュールをつかさどるカウンターです。100Hzでカウントし0の時に距離カウンターとマイクをスタートさせます。23の時に距離カウンターのリセットをかけます。25で繰り返します。
Counter_2は超音波を発してから、帰ってくるまでの時間を計測します。
image.png

作成

それでは、実際に作成していきましょう。
TopDesignを開き
Digital-->Function-->Counterを2つ置きます。
Digital-->Logicn-->ANDを1つ置きます。
Digital-->Logicn-->logic low '0'を1つ置きます。
Digital-->Logicn-->SR Flip Flapを1つ置きます。
Port and Pins --> Digital Output を2つ置きます。
System --> Clock を5個置きます。
Sheet Connector image.png(左にあります)を2つ置きます。
こんな感じになります。
image.png

設定していきましょう。
Counter_1:UDBを使用します。25で繰り返し23の時にCompare信号(Counter_2のReset信号)を立ち上げます。
image.png
image.png

Clock_1:IMOから100Hzを作ります。Counter_1のカウントクロックになります。
image.png

BUS_CLK(Nameが違うだけなので以後省略):48MHzのバスクロックを利用します。(Clock_2,3,4,5は別で使うので他の名前にしましょう)
image.png

配線:他の回路と接続するためには、配線の名前を指定します。配線上で右クリックしEdit Name and Widthを選択します。"Use computed name and width"のチェックを外し、名前を指定します。配線に名前が表示されます。
image.png
image.png

ここまでで、こんな感じにできました。
image.png

SR-FF回りも同様にしていきます。こんな感じになりますね。
image.png

Counter_2:UDBを使用します。出力はプログラムでカウント数を読むだけです。Periodは Clock ModeをUp Counterにした後で Max ボタンを押します。なお、繰り返すのはReset信号が入った時だけですのでOn TCのチェックは外します。
image.png
image.png

Clock_2:IMOから100kHzを作ります。計測用のカウントクロックになります。
image.png

全体タイミング部が出来ました。
image.png

スピーカー部

スピーカーはStart信号が来てから60μsの間、ONにします。またスピーカーは40kHzの信号を入れる必要があります。今回は、前述したように音を大きくするため、交互にONになるような配線をしています。
image.png

作成

では作っていきましょう。
まず回路図のページを追加します。回路図のページのタグで右クリックし、"Add Schematic Page"を選択します。
image.png
新しいページが出来たので、ここに描いていきます。

Digital-->Function-->Counterを1つ置きます。
Digital-->Logicn-->Notを1つ置きます。
Port and Pins --> Digital Output を3つ置きます。
System --> Clock を3個置きます。

Off-chip タブに移り Electro-Mechanical-->Sperker を1つ置きます。
image.png

こんな感じになります
image.png

Counter_3:スピーカーの音を出す時間を決定しています。Start信号が来て最初の60μsほどオンにします。(Compare Valueで設定)
UDBを使います。RunモードはOne Shotです。ReloadしないのでOnTCのチェックは外します。
image.png
image.png

Clock_3:Counter_3のカウンタクロック信号を作ります。1MHzにします。1周期が1μsになります。
image.png

Clock_4:超音波スピーカーの超音波40kHzを作るための信号を生成します。
image.png

BUS_Clockは前回と同様です。

Digital OutputのPortの名前をSP_OUT0、SP_OUT1にし、HW connection、Output enable にチェックをします。Output enableにCounter_3からの信号を入力することでスピーカーのON-OFFの制御を行っています。External terminalは、外部回路を描くためにチェックしています。
image.png

Pin_0_5:信号確認用の端子です。
image.png

接続していきます。
最後にSheet Connectorの配線の名前を"start"に変更します。(上手くいかない時は一旦1ページの名前を削除して、再度両方の名前を指定してください。)
できました。
image.png

マイク部

Counter_4、Clock_5でマイクからの直接ノイズを外す時間を設定しています。
Vdda/2(約2.5V)をAGNDとするため、Opamp_1を介してアナログ系(PGA_1、ADC_Delsig_1)の基準電圧に入力しています。帯域通過フィルター(Band Pass Filter:BPF)はミニDSPのFilterにデータを入れるためのADコンバータ、計算エンジンのFilter、出力電圧を作成するDA変換器から構成しています。今回はADコンバータとFilterの間はDMA(Direct Memory Access)をFilterとDA変換器間は割り込みを利用しています。FilterからDA変換器(VDAC8_1)を通して出力された信号は、アナログコンパレータ(Comp_1)でVDAC8_2と比較し、信号として出力し、さらにCounter_4の反転信号と論理積をとって、stop信号として出力します。stop信号は、計測終了信号なので割り込みisr_2に入力します。
image.png

作成

前回と同様、回路図のページを追加します。
デジタル側
Digital-->Function-->Counterを1つ置きます。
Digital-->Logicn-->Andを1つ置きます。
Digital-->Logicn-->Notを1つ置きます。
System --> Clock を2個置きます。
System --> Interrupt を1個置きます。

アナログ側
off-chip
Sensor-->Microphone を1個置きます。向きを反転させます。
image.png
Passive-->Registor を1個置きます。90度回転させます。
image.png

Analog-->VRefを1つ置きます。
Analog-->Amplifiers-->Opampを1つ置きます。
Port and Pins --> Analog Pinを4つ置きます。
Analog-->Amplifiers-->PGAを1つ置きます。
Analog-->ADC-->Delta Sigma ADCを1つ置きます。
System --> DMA を1個置きます。
Filters --> Filter を1個置きます。
System --> Interrupt を1個置きます。
Analog-->DAC-->Voltage DACを2つ置きます。
Analog-->Comparators-->Comparatorを1つ置きます。

Seet Connectorを2つ置きます

こんな感じになりました。
image.png

Clock_5:Counter_4のカウンタクロック信号を生成します。1周期は0.1msです。
image.png

BUS_Clkは前と同様に作ります。

Counter_4:スピーカーからの直接音が入る時間を設定し、キャンセルする信号を出します。1ms(0.1ms [Clock_5]が 10回[Compare Value])以下ならcomp出力(キャンセル信号)を出力します。
image.png
image.png

Andゲート後のInterruptの名前はisr_2 にします。(同じ名前があった場合は、先にそちらの名前を変更しておきます)
isr_2:結果が出ると割り込みをかけます。
image.png

デジタルの部分を結線します。
左のSheet Connectorの線はstart
右のSheet Connectorの線はstop
image.png

Analog Pinの名前をMic_1とMic_2にします。
Mic_1,2:マイクの信号を入力します。外部回路を描くためにExternal terminalのチェックを入れています。
image.png

VRef: vdda/2にします。
image.png

Opamp_1:負荷に電圧を加えるときのインピーダンス整合に使います。
image.png

PGA_1:入力信号を増幅します。今回は最大の50dBに設定。
image.png

Pin_2_0:入力し、PGAで増幅した信号を確認用に出力します。
image.png

アナログの入力部が出来ました。
image.png

次はフィルター部です。

ADC_DelSig_1:デルタシグマ式のAD変換器です。これでGainをあげると変換速度が下がるため、前段にPGA_1を利用しています。先にCommonタブでconfiguration数を1に設定します。Config1は、Resolutionを8に落として速度をあげます。Input Range等も調整します。
image.png
image.png

DMA_1:ADC_DelSig_1の出力をDMAに載せるために使用します。Derivedは接続先に応じて自動で変わるモードです。
image.png

Filter:BPFのパラメータを入力しています。左側がパラメータです。参考に最低のBUSクロックが表示されますが、設定はされません。今回のSample Rateは、ADCで設定していますので、その値を入力します。なお、Filter gainは、オーバフローして計算不可になる可能性があるので通常0.25を設定するのですが、今回に限り信号が小さいので20に設定しています。Centerは40kHz、Bandwithは10kHzにしています。
image.png

isr_1:VDAC8_1に値をWriteするためFilterで計算が終わったら呼ばれます。
image.png

VDAC8_1:Filterで計算した値を出力しています。
image.png

設定が終わったら配線していきます。
DMA_1,isr_1は配線し辛かったので記号を反転しています。AD-->Filter間はDMA転送、Filter-->VDAC8_1間はプログラム(割り込み)でするので配線は不用です。
このような感じになります。

image.png

最後判定部を作ります。

VDAC8_2:アナログコンパレータ(Comp_1)の比較用の電圧を発生しています。
image.png

Comp_1:VDAC8_1の信号がVDAC8_2で発生した閾値電圧を超えると信号を出力します。
image.png

終わったら配線をします。
最後の出力の配線をstopにします。
image.png

その他の回路

その他の回路として、PCとの通信用にUART_1、確認用にLedPinを設置ています
image.png

作成

前回と同様に回路図を1ページ追加します。

Comminucations-->UART を 1つ置きます。
Ports and Pins --> Digital outputを1つ置きます。

UART_1:UARTの通信速度は9600bpsに設定しています。
image.png

LedPin:ボード上のLED(P2[1])に接続します。ソフトのみの制御なのでHW Connectionのチェックを外します。
image.png

Pins

最終的に以下の様なPinに設定しました。

名称 Port 備考
Mic_1 P1[5] 超音波マイクと接続
Mic_2 P1[4] 超音波マイクと接続(AGND側)
SP_OUT0 P1[7] 超音波スピーカーと接続
SP_OUT1 P1[6] 超音波スピーカーと接続
Rx_1 P12[6] UARTで使用。指定ポート
Tx_1 P12[7] UARTで使用。指定ポート
LedPin P2[1] ボード上のLEDと接続。
Pin_0_0 P0[0] 確認用。全体周期
Pin_0_1 P0[1] 確認用。計測用カウンター(Counter_2)のリセット信号
Pin_0_5 P0[5] 確認用。スピーカーのON信号
Pin_2_0 P2[0] 確認用。BPF前の信号
Pin_2_3 P2[3] 確認用。BPF後の信号

image.png

割込み

割込みの優先度を変更します。Filter関係の優先度をあげないと、BPFが正常に動作しません。優先度は、0が高く、7が低くなります。
image.png
Design Wide Resources --> Interruptsを開きます。 
image.png

出来ました。プログラムを書く準備をするために、Build Designimage.pngをクリックして実行してみましょう。
ーーーーーーーーーーーーーーーーーーーーーーー

ソフトウェア

デザインのビルドが上手くいったらコードを作成します。と言ってもほとんどは、モジュールをスタートさせるだけのプログラムで、Stopの割込みが来たら、時間から距離を求めるだけです。

DMAの設定

DMAの設定のコードは、Tools-->DMA Wizerdで簡単に作成できます。

  1. DMAを選択します。
    image.png
  2. データの行先を設定します。
    image.png
  3. データの長さや受け渡し先、次のTD#を設定します。今回は8bitなので、AH_PTRの方になります。
    image.png
  4. プログラム上に書き加えるコードが表示されるのでコピーします。
    image.png

プログラム(全)

DMA_Config関数内はDMA Wizardで作成したものです。

#include "project.h"
#include "stdio.h"

CY_ISR(filterVDAC)
{
    static int i=0;                                          //for debug
    if(i==0){LedPin_Write(0);i=1;}else{LedPin_Write(1);i=0;} //for debug
    VDAC8_1_SetValue(Filter_1_Read8(Filter_1_CHANNEL_A) + 128u);
   }
CY_ISR(DataRcv)
{
    uint16 t=Counter_2_ReadCounter(); //count
    float t2=(float)t*0.01;  //ms
    float x=343.7*t2/2.0;  //mm
    char str[30];
    sprintf(str,"Count=%3d[Count] x=%3d[mm] \r\n",t,(int)(x+0.5));
    UART_1_PutString(str);
}

void DMA_Config(void)
{
/* Defines for DMA_1 */
#define DMA_1_BYTES_PER_BURST 1
#define DMA_1_REQUEST_PER_BURST 1
#define DMA_1_SRC_BASE (CYDEV_PERIPH_BASE)
#define DMA_1_DST_BASE (CYDEV_PERIPH_BASE)
/* Variable declarations for DMA_1 */
/* Move these variable declarations to the top of the function */
    uint8 DMA_1_Chan;
    uint8 DMA_1_TD[1];
/* DMA Configuration for DMA_1 */
    DMA_1_Chan = DMA_1_DmaInitialize(DMA_1_BYTES_PER_BURST, DMA_1_REQUEST_PER_BURST, 
        HI16(DMA_1_SRC_BASE), HI16(DMA_1_DST_BASE));
    DMA_1_TD[0] = CyDmaTdAllocate();
    CyDmaTdSetConfiguration(DMA_1_TD[0], 1, DMA_1_TD[0], 0);
    CyDmaTdSetAddress(DMA_1_TD[0], LO16((uint32)ADC_DelSig_1_DEC_SAMP_PTR), LO16((uint32)Filter_1_STAGEAH_PTR));
    CyDmaChSetInitialTd(DMA_1_Chan, DMA_1_TD[0]);
    CyDmaChEnable(DMA_1_Chan, 1);
}

int main(void)
{
    DMA_Config();
    isr_1_StartEx(filterVDAC);
    isr_2_StartEx(DataRcv);
    Filter_1_Start();
    Filter_1_Write24(Filter_1_CHANNEL_A,0x000000);
    UART_1_Start();
    Counter_1_Start();
    Counter_2_Start();
    Counter_3_Start();
    Counter_4_Start();
    Opamp_1_Start();
    PGA_1_Start();
    ADC_DelSig_1_IRQ_Start();
    ADC_DelSig_1_Start();
    VDAC8_1_Start();
    VDAC8_2_Start();
    Comp_1_Start();
    ADC_DelSig_1_StartConvert();
    CyGlobalIntEnable; /* Enable global interrupts. */
    UART_1_PutStringConst("Program Start \n\r");
    for(;;)
    {
        CyDelay(500);
    }
}

接続・確認・調整

最後に動かして調整しましょう。

回路

こんな感じで作成しました。抵抗は10kΩです。
image.png
image.png

スピーカへの入力信号

スルーホール基板との接続は秋月電子のこの線が便利ですよね。
https://akizukidenshi.com/catalog/g/g109830/

スピーカ(TX)はP1.7とP1.6で出力されます。 こんな感じの40kHz波形が出ていました。
P1.6,P1.7は出力ピンですのでオシロとはP1.6-GND、P1.7-GNDで接続する必要があります。
image.png
image.png
接続します。
image.png

マイクの接続

マイク(RX)は、P1.4とP1.5に接続します。
image.png

TeraTerm等でシリアル通信(9600bps)で接続し、上手くいっていれば数値が出てきています。
image.png
たまに0が出ているのは、スピーカの反射の音を取っているのではなく、直接音を拾っていたり、空気中の反射音以外の音を拾っているからです。これは後のマイクの無音時間を調整します。

送受信の波形の確認

スピーカの出力はP0.5、マイクのフィルター後の信号はP2.3に出力しているので確認してみましょう。
黄色がスピーカの送信、水色がマイクで拾って処理した後のアナログ信号です。
※オシロの性能が悪く見えませんが、本来は黄色の部分のOnの間に40kHzの信号があります。
image.png

マイクの無音時間

スピーカーとマイクを一緒に設置すると音を出すと基板を伝わったり、机からの反射など様々な音を拾います。マイクとスピーカーの距離の影響や何回か反射する影響で、実際の音を出している時間よりも長くなります。その時はCounter_4の値を調整します。

コンパレータの比較電圧の設定

P2[3]の信号をオシロスコープのTrig電圧を変化させ確認しながら閾値を検討します。閾値が決まったらVDAC8_2の値を変更します。
出力がGND中心でないことに注意が必要です。
image.png

備考

コードで色々なパラメータを動的に変更できます。

本プログラムでは

  • 温度
  • Filterの計算遅れ
    を考慮していません。

おわりに

自分は、こんなことが出来るマイコンはPSoCしか知りません。他のマイコンなど紹介して頂ければ幸いです。
どうですか。PSoC面白いでしょう。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?