LPC810メモ:SCTの例その3(超音波距離センサ)
SCTの、event発生時点のタイマの値を記録するcapture機能を試してみたくて考えてみた例。
前提とする環境はこちら→LPC810メモ 共通の準備
SCT全般のメモはこちら→LPC810メモ:SCTimer/PWM (SCT)について
- amazonで500円くらいで買ったこのHC-SR04というセンサを使う。
- http://akizukidenshi.com/catalog/g/gM-08762/
- でもリンクは秋月。データシートダウンロードできるし。
- このセンサが5vなので、この昇圧コンバータも使う。
- このセンサは、超音波を発して、音が反射して戻ってくるまでの経過時間を返してくれるので、音速で除算すれば距離がわかる、という仕組み。
- trigger端子を10μsHIGHにしてやると超音波を発する。
- → SCTの出力で、triggerを10μsだけHIGHにしてやればいい。
- 経過時間は、「echo端子がHIGHになっている時間」という形で表現される。
- → SCTの入力にechoをつなぎ、立ち上がり/下がりの時間をcaptureで記録して、引き算すればよい。
- trigger端子を10μsHIGHにしてやると超音波を発する。
- より具体的にはこうしてみた。
- 1ms経過後にtriggerへの出力(2番pin)をHIGHに(event0)
- その10μs後にtriggerへの出力(2番pin)をLOWに(event1)
- echo(3番pin)が立ち上がったらその時間を記録(event3)
- echo(3番pin)が立ち下がったらその時間を記録(event4)
- 検知できずに30ms経過したら諦める(event2)
- event4の値からevent3の値 を引いて距離測定。
- 連続的に距離を測定して、「近いほど速くLチカ」してみる。
サンプルコード
#include "LPC8xx.h" // SCTの設定 void setSct() { // SWMのclockを有効化 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7); // 3番pin(PIO_3)にSCT入力の0番(CTIN_0) を設定 // UM10601 9.5.6 Pin assign register 5 LPC_SWM->PINASSIGN5 = 0x03ffffffUL; // 2番pin(PIO_4)にSCT出力の0番(CTOUT_0) を設定 // UM10601 9.5.7 Pin assign register 6 LPC_SWM->PINASSIGN6 = 0x04ffffffUL; // RESET 以外の無効化 LPC_SWM->PINENABLE0 = 0xffffffbfUL; // UM10601 10.3 Basic configuration // に従った準備 // SCTのclockを有効化(UM10601 4.6.13 System clock control register) LPC_SYSCON->SYSAHBCLKCTRL |= (1<<8); // Clear the SCT peripheral reset using the PRESETCTRL register (Table 19). LPC_SYSCON->PRESETCTRL &= ~(0x1<<8); LPC_SYSCON->PRESETCTRL |= (0x1<<8); // 今回は割り込みは使わない // UM10601 3.4.1 Interrupt Set Enable Register 0 register // NVIC->ISER[0] = (0x1 << 9); // 以下、SCTの動作の設定 // UM10601 10.6.1 SCT configuration register // 今回は16bit一本(L)のみを使う。 // UNIFY = 0でAUTOLIMITも使わないので、 LPC_SCT->CONFIG の設定は不要 // UM10601 10.6.2 SCT control register LPC_SCT->CTRL_L |= (12 - 1 ) << 5; // PRE_L = 12 -> 12clock(1μ秒)で1カウント // match/captureレジスタの3,4番は、capture用に設定。 // センサからの入力を受け取る。 // UM10601 10.6.10 SCT match/capture registers mode register LPC_SCT->REGMODE_L = 1 << 3 | 1 << 4; // カウンタにmatchする値を定義 // UM10601 10.6.20 SCT match reload registers 0 to 4 (REGMODEn bit = 0) LPC_SCT->MATCH[0].L = 1000; // 開始1ms後(ここで出力をHIGHにする) LPC_SCT->MATCH[1].L = 1010; // 開始1ms + 10μs後(ここで出力をLOWにする) LPC_SCT->MATCH[2].L = 30000; // 開始30ms(測定のタイムアウト) // limitは使わないので、MATCHRELでなく、MATCHそのものに設定している。 // event0番(match 0、開始1ms後に発生) // 10.6.22 SCT event state mask registers 0 to 5 // 10.6.23 SCT event control registers 0 to 5 LPC_SCT->EVENT[0].STATE = 0x01; // state0で発生 LPC_SCT->EVENT[0].CTRL = (0 << 0) // MATCHSEL = 0 -> match0に対応 | (0 << 4) // HEVENT = 0 -> タイマLに対応 | (1 << 12); // COMBMODE = 1 -> match だけに対応 // event1番(match 1、開始1ms + 10μs後に発生、state1に移行) // 10.6.22 SCT event state mask registers 0 to 5 // 10.6.23 SCT event control registers 0 to 5 LPC_SCT->EVENT[1].STATE = 0x01; // state0で発生 LPC_SCT->EVENT[1].CTRL = (1 << 0) // MATCHSEL = 0 -> match0に対応 | (0 << 4) // HEVENT = 0 -> タイマLに対応 | (1 << 12) // COMBMODE = 1 -> match だけに対応 | (1 << 14) // STATELD = 1 -> 状態をSTATEVに設定 | (1 << 15); // STATEV = 1 // event2番(match 2、タイムアウト。state 0に戻る。) // 10.6.22 SCT event state mask registers 0 to 5 // 10.6.23 SCT event control registers 0 to 5 LPC_SCT->EVENT[2].STATE = 0x02; // state1で発生 LPC_SCT->EVENT[2].CTRL = (2 << 0) // MATCHSEL = 2 -> match2に対応 | (0 << 4) // HEVENT = 0 -> タイマLに対応 | (1 << 12) // COMBMODE = 1 -> match だけに対応 | (1 << 14) // STATELD = 1 -> 状態をSTATEVに設定 | (0 << 15); // STATEV = 0 // event3番(state1で、入力1の立下りで発生) LPC_SCT->EVENT[3].STATE = 0x02; // state1で発生 LPC_SCT->EVENT[3].CTRL = (0 << 4) // HEVENT = 0 -> タイマLに対応 | (0 << 6) // IOSEL 入力1に対応 | (1 << 10) // IOCOND riseに対応 | (2 << 12); // COMBMODE = 2 -> I/O condition だけに対応 // event2番(state1で、入力1の立下りで発生。state0に戻る。) LPC_SCT->EVENT[4].STATE = 0x02; // state1で発生 LPC_SCT->EVENT[4].CTRL = (0 << 4) // HEVENT = 0 -> タイマLに対応 | (0 << 6) // IOSEL 入力1に対応h | (2 << 10) // IOCOND fallに対応 | (2 << 12) // COMBMODE = 2 -> I/O condition だけに対応 | (1 << 14) // STATELD = 1 -> 状態をSTATEVに設定 | (0 << 15); // STATEV = 0 // event3,4番が発生したら、それぞれcaptureの3,4番にタイマの値を記録 // センサからの入力。 // UM10601 10.6.21 SCT capture control registers 0 to 4 (REGMODEn bit = 1) LPC_SCT->CAPCTRL[3].L = 1 << 3; LPC_SCT->CAPCTRL[4].L = 1 << 4; // 出力の定義 // event0で出力0をHIGHにし、1でLOWにする。 // センサに対するトリガ。 // UM10601 10.6.24 SCT output set registers 0 to 3 // UM10601 10.6.25 SCT output clear registers 0 to 3 LPC_SCT->OUT[0].SET = (1 << 0); LPC_SCT->OUT[0].CLR = (1 << 1); // event2,4番でhalt LPC_SCT->HALT_L = 1 << 4 | 1 << 2; } // SCTを使った距離測定 int16_t getDistance() { // カウンタをゼロに戻す // UM10601 10.6.7 SCT counter register LPC_SCT->COUNT_L = 0; // capture3,4をゼロに戻す // UM10601 10.6.19 SCT capture registers 0 to 4 (REGMODEn bit = 1) LPC_SCT->CAP[3].L = 0; LPC_SCT->CAP[4].L = 0; // haltを解除してstart /// UM10601 10.6.2 SCT control register LPC_SCT->CTRL_L &= ~(1 << 2); // HALT_L = 0 // haltになるまで待つ while((LPC_SCT->CTRL_L & (1 << 2)) == 0) {} // capture地を読んで距離測定 uint16_t rise = LPC_SCT->CAP[3].L; // 入力の立ち上がり時間 uint16_t fall = LPC_SCT->CAP[4].L; // 入力の立ち下がり時間 int16_t ret; if(fall == 0 || rise == 0) { // どちらかゼロなら測定失敗 ret = -1; } else { // HIGHだった時間を求める ret = fall - rise; if(ret < 0) { ret = 0; // 何かの間違いで0未満になったら測定失敗扱い } else { ret = ret / 58; // cm単位に変換。58で割ればよいらしい。 } } return ret; } int main(void) { // SCTの設定 setSct(); // GPIOに対してclockを有効化 // UM10601 4.6.13 System clock control register LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6); // PIO0_0(8番pin)をoutputに設定 // UM10601 27.1 Packages より、PIO0_0は8番 // UM10601 7.6.3 GPIO port direction registers LPC_GPIO_PORT->DIR0 |= (1<<0); while(1) { // SCTで距離測定 int16_t distance = getDistance(); if(distance == -1 || distance > 20) { distance = 20; } // 測定エラーまたは20cm以上は、20cm扱い。 // 距離が長いほどwaitを長くしてLEDを点滅2回。 for(int i = 0; i < 4; i++) { // PIO0_0の出力をtoggle // UM10601 7.6.9 GPIO port toggle registers LPC_GPIO_PORT->NOT0 |= (1<<0); for(volatile int i = 0; i < 10000 * (distance + 1); i++) {} } } return 0 ; }
接続
- 左上のが超音波距離センサ
- 上から、VDD,trigger,echo,GND
- trigger,echoは、それぞれLPC810の2,3番に接続。
- http://akizukidenshi.com/catalog/g/gM-08762/
- 上の方は無駄に複雑だが昇圧コンバータで5vを作っているだけ
- 電源onで測定開始、手を近づけるとLEDの点滅が早くなる。
補足/雑感
- LPC_SCT->REGMODE_Lの設定、'1 << 3 | 1 << 4;'でなくなぜか'1 << 3 | | 1 << 4;'と書いていて気づけず、ものすごくハマった。