今回は、超音波センサSRF-02のコマンドについて調べました。
まず、SRF-02の通信には二つのモードがあり、I2CとUARTがありますが、今回はI2Cに焦点を当てて説明します。
まずは、SRF-02の主な特徴です。
◆主な仕様
・使用マイコン:16F687-I/ML
・測定範囲:16cm~6m.
・電源:5V(消費電流4mA Typ.)
・使用周波数:40KHz.
・アナログゲイン:64段階の自動ゲインコントロール
・接続モード:モード1=I2C、モード2=シリアルバス
・全自動調整機能:電源投入後キャリブレーション不要
・測距タイミング:エコー時間計測、ホストによるタスクコントロール
・測定単位:μS(マイクロ秒)、ミリ、インチ
・サイズ:24mmx20mmx17mm
・入出力端子:5ピン
・重量:4.6グラム
SRF-02の主なコマンド
次に、SRF-02で使用される主なコマンドです。
コマンドの通信方法は、ArduinoのWireライブラリを使って通信します。詳細は、以前のブログを参照してください。
I2Cでの通信方法
SRF02をI2Cモードで使用するには、モードピンをオープンにします。
I2Cの通信では、最大16個まで並列で接続できます。並列でつなぐので、それぞれのSlave(超音波センサ)にアドレスを振り分けます。
SRF02の出荷時のアドレスは0xE0です。アドレスはユーザによって変更することができ、最大16個(E0、E2、E4、E6、E8、EA、EC、EE、F0、F2、F4、F6、F8、FA、FC、FE)のアドレスが使用できます。
レジスタ
SRF-02には6種類のレジスタがあります。
ロケーション | 読む | 書く |
0 | ソフトウェアリビジョン | コマンドレジスタ |
1 | 未使用(0x80を読み取ります) | 該当なし |
2 | 測定値 上位バイト | 該当なし |
3 | 測定値 下位バイト | 該当なし |
4 | オートチューン最小-上位バイト | 該当なし |
5 | オートチューン最小-下位バイト | 該当なし |
6個あるレジスタのうち、Masterから書き込むことができるのは、0番のレジスタのみです。
すべて、0番のレジスタに数値を入れることでSRF-02の様々な設定ができます。
0番から読み出す場合は、ソフトウェアリビジョンを返されます。1番は使用していない空きピンです。
2,3番のレジスタが、測定した数値を返すレジスタです。測定値は最大2byteの容量で返します。レジスタ1個は1byteですので、レジスタが二つ(2,3)必要なわけです。この測定値は、設定の状態によって、インチ、センチ、マイクロ秒などで返します。
4、5番のレジスタは、16ビットの符号なし最小範囲です。これは、ソナーが測定できるおおよその最も近い範囲です。
つまり最初0番で指定をしたら、あとは2,3番のレジスタで測定値を参照すればよいということです。
SRF-02のコマンド
下記が、SRF-02の0番に指定するコマンドです。
2進数 | 16進数 | 動作 |
80 | 0x50 | Real Ranging Mode – Result in inches |
81 | 0x51 | Real Ranging Mode – Result in centimeters |
82 | 0x52 | Real Ranging Mode – Result in micro-seconds |
86 | 0x56 | Fake Ranging Mode – Result in inches |
87 | 0x57 | Fake Ranging Mode – Result in centimeters |
88 | 0x58 | Fake Ranging Mode – Result in micro-seconds |
92 | 0x5C | Transmit an 8 cycle 40khz burst – no ranging takes place |
96 | 0x60 | Force Autotune Restart – same as power-up. You can ignore this command. |
160 | 0xA0 | 1st in sequence to change I2C address |
165 | 0xA5 | 3rd in sequence to change I2C address |
170 | 0xAA | 2nd in sequence to change I2C address |
必要に応じて、上記のコマンドを1番のコマンドレジスタに書き込み、必要な時間待機して結果を読み取ります。エコーバッファは、各レンジングの開始時にクリアされます。レンジングは最大66m秒持続します。この後、測定値を2,3番のレジスタから読み取ります。
SRF-02の命令方法
MasterからSRF-02に命令する場合、どのようにしたらよいでしょうか。
下記が、参考に、測定値をcmにするプログラムです。
Wire.beginTransmission(226); //通信先のアドレス
Wire.write(0x00); //レジスタを選ぶ
Wire.write(0xA0); //コマンドを選ぶ
Wire.endTransmission();
順番としては、まず Wire.beginTransmission(226); で、Slaveのアドレス(226)を指定。
次に送信するものは、接続するレジスタになります。なにか設定などをする場合は、
0番のレジスタにアクセスするため、Wire.write(0x00);で0を送ります。
次に、送るものが設定するコマンドです。
例えば、測定値をcmで返す設定をする場合は、コマンド0x51を送ればよいので、
Wire.write(0x51);となります。
設定はこれで終了なので、 Wire.endTransmission(); で今回の通信を終わります。
コマンドの内容にもよりますが、基本は、レジスタを指定→そのレジスタのコマンドを送る、の流れです。
SRF-02の測定値を読み出すプログラム
次に、SRF-02から測定値を読み出す方法です。
Wire.beginTransmission(0xE0); // transmit to device #112
Wire.write(byte(0x02)); // sets register pointer to echo #1 register (0x02)
Wire.endTransmission(); // stop transmitting
Wire.requestFrom(0xE0, 2); // request 2 bytes from slave device #112
if (2 <= Wire.available()) // if two bytes were received
{
reading = Wire.read(); // receive high byte (overwrites previous reading)
reading = reading << 8; // shift high byte to be high 8 bits
reading |= Wire.read(); // receive low byte as lower 8 bits
Serial.print(reading); // print the reading
Serial.println("cm");
}
まず、SRF-02から数値を読み出す場合、2番目のレジスタ0x02にアクセスします。それが、3行目までのプログラムです。
次に、SRF-02からデータを受信する準備をします。それが、 Wire.requestFrom(0xE0, 2); です。
これは、アドレスE0のSlaveから、2byteのデータを受け取りますという意味です。
あとは Wire.read();で、データを受け取ることが出来ます。しかし、2byteあるため、そのまま受け取ると下位ビットが上書きされます。そのため、まず、上位8ビットのデータを受け取り( reading = Wire.read(); )、readingのビットを (reading = reading << 8; )8bit高い位にシフトさせてから、次に飛んでくる数値(下位ビット)を ( reading = Wire.read(); ) で受信します。
Slaveで分割されたデータは、上位ビットから書き込まれる
そのまま下位ビットを書き込むと上書きされてしまう
そこで、最初に書き込まれた上位ビットを8ビット上にシフト
そのあとで下位ビットを書き込めばすべて正しく送れる
SRF-02のアドレス指定
次に、SRF-02のアドレス指定手順です。方法は簡単で、上記コマンドの0xA0, 0xAA, 0xA5,を順番に送り、最後に新しいアドレスを送ることで、アドレスを指定するモードになります。例えば、もともとのアドレスE0から新しいアドレスF4に帰る場合は下記のプログラムを動かします。とてもシンプルですよね。
Wire.beginTransmission(0xE0);
Wire.write(0x00);
Wire.write(0xA0); //A0を書き込む
Wire.endTransmission();
Wire.beginTransmission(0xE0);
Wire.write(0x00);
Wire.write(0xAA); //AAを書き込む
Wire.endTransmission();
Wire.beginTransmission(0xE0);
Wire.write(0x00);
Wire.write(0xA5); //A5を書き込む
Wire.endTransmission();
Wire.beginTransmission(0xE0);
Wire.write(0x00);
Wire.write(0xF4); //新しいアドレスF4を書き込む
Wire.endTransmission();
今日は、ここまで。
2021.8.7 ひいらぎ