3ピンのDYP-ME007TXをArduino UNOで使う

![DYP-ME007](https://images-na.ssl-images-amazon.com/images/I/51a5gfOXwwL._SX425_.jpg)
[DYP-ME007TX]https://www.amazon.co.jp/dp/B008AFFC9G/
amazonでやすかったので購入したのですが、
4ピンのDYP-ME007に関する情報はちょくちょくある（というか割と素直に使いやすいTrig/Echo方式）のですが、
3ピンのものに関する情報が中々見つからず、
しらべてみたところ、こやつ1方向でシリアル出力しているようでした(なんじゃそりゃ)。


# とりあえず使ってみる

色々見てみると、Tindieで販売しているこれが発売元っぽかったです。
Specのところにパケットのフォーマット書いてました。
[Serial Ultrasonic Distance Sensor]https://www.tindie.com/products/upgradeindustries/serial-ultrasonic-distance-sensor/

```
Data[0] = 0xFF: Packet Header
Data[1]= 0x0-0xFF: Data Most Significant Byte (MSB)
Data[2]= 0x0-0xFF: Data Least Significant Byte (LSB)
Data[3]= 0x0-0xFF: Data Checksum: = (0XFF + MSB + LSB) & 0xFF

Data is in MILLIMETERS
16 bit value in mm = Data[1] >> 8 | Data[2]
```


というわけで、4byteのシリアルデータを受信するコードをかけばいけました。
**※ Arduino Megaで動かす場合、デジタルピンで一部動作しないことが確認されました。当方ではA8などのアナログ入力ピンを使うことで解決しました。(https://garretlab.web.fc2.com/arduino_reference/libraries/standard_libraries/SoftwareSerial/index.html)**

```cpp:sensor.rb
#include <SoftwareSerial.h>

#define PING_RX_PIN 6
#define PING_TX_PIN 7 // dummy

SoftwareSerial mySerial(PING_RX_PIN, PING_TX_PIN);

long inches = 0, mili = 0;
byte mybuffer[4] = {0};
byte bitpos = 0;

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
}

void loop() {
  bitpos = 0;
  while (mySerial.available()) {
    if (bitpos < 4) {
      mybuffer[bitpos++] = mySerial.read();
    } else break;
  }
  mySerial.flush();

  mili = mybuffer[1] << 8 | mybuffer[2];
  inches = 0.0393700787 * mili;
  Serial.print("PING: ");
  Serial.print(inches);
  Serial.print("in, ");
  Serial.print(mili);
  Serial.println("mili");

  delay(100);
}
```


ピンアサインは下記です。

| Arduino      | DYP-ME007   |
|:-------------|------------:|
| 5V           | VCC         |
| D6           | OUT         |
| GND          | GND         |


# 複数のDYP-ME007を扱う場合

SoftwareSerialでは、複数のポートを同時にアクセスすることができません。
やり方としては、ターゲットのポートをlistenして、しばらくしてからreadしてあげる形。
もろもろまとめると、下記のような感じになります。

```cpp:sensor_multi.ino
#include<SoftwareSerial.h>

long showTimer;

#define NUM_SENSORS 7
#define MAX_RANGE 4000

SoftwareSerial mySerial[NUM_SENSORS] = {
  SoftwareSerial(A8,5),
  SoftwareSerial(A9,6),
  SoftwareSerial(A10,7),
  SoftwareSerial(A11,8),
  SoftwareSerial(A12,9),
  SoftwareSerial(A13,10),
  SoftwareSerial(A14,11),
};

int currentSensorIndex = 0;
long millimeters[NUM_SENSORS];
long waitTimer;

void setup () {
  Serial.begin(115200);

  for (int i=0;i<NUM_SENSORS;i++) {
    mySerial[i].begin(9600);
    millimeters[i] = 0;
  }
}

void loop() {
  if (currentSensorIndex < NUM_SENSORS) {
    if (waitTimer == 0) {
      mySerial[currentSensorIndex].listen();
      waitTimer = millis();
    }
    else if (millis() - waitTimer > 100) {
      readSerial(&mySerial[currentSensorIndex], currentSensorIndex);
      waitTimer = 0;
      currentSensorIndex++;
    }
  }
  else {
    currentSensorIndex = 0;
  }

  if (millis() - showTimer > 100) {
    for (int i=0;i<NUM_SENSORS;i++) {
      Serial.print(millimeters[i]);
      Serial.print("\t");
    }
    Serial.println();

    showTimer = millis();
  }
}

void readSerial(SoftwareSerial *s, int idx) {
  if (s->available() > 3) {
    byte myByte = s->read();
    byte myBuffer[2] = {0};
    if (myByte == 0xFF)
    {
      myBuffer[0] = s->read();
      myBuffer[1] = s->read();
      s->flush();
    }

    long mm = myBuffer[0] << 8 | myBuffer[1];
    if (mm > 0 && mm < MAX_RANGE) {
      millimeters[idx] = mm;
    }
  }
}
```

めでたしめでたし。

# おまけ(スペック)

| Left align       | Left align       |
|:-----------------:|:------------------:|
| Interface | RS-232 / UART (constant output) |
| Serial Format | 9600 Baud No Parity 8 bits per byte 1 Stop Bit (output) |
| Range | up to 4m |
| Accuracy | 1mm |
| Sound Frequency | 40 kHz |
| Output Rate | 10 Hz |
| Response Envelope | &lt; 30 deg |
| Supply voltage | 5V |
| Supply current | 15mA typical |