「Pro MicroとRaspberry Pi 3でUSBを使ったシリアル転送」でPro MicroとRaspberry Pi 3間でシリアル転送を行いましたが、今回はつぎのような機能を持つバイナリシリアル転送を行います。
- Pro MicroとRaspberry Pi 3でUSBを使ったバイナリシリアル転送を行います。
- Raspberry Pi 3の要求によって、Pro Microが保存しているデータをバイナリシリアル転送します。
- Pro MicroとRaspberry Pi間で通信手順によりデータを転送します。
- 送信されたデータは、Raspberry Piでバイナリファイルとして保存します。
Pro MicroとRaspberry Pi 間の接続
RaspberryPiとArduinoをUSBケーブルで接続します。RaspberryPiにはUSB端子が4つありますが、どれでも構いません。
Pro MicroがRaspberry Pi 3に接続されているかを次のコマンドで確認します。コマンドの実行結果で「Arduino SA Leonardo」が表示されています。
$ lsusb Bus 001 Device 004: ID 2341:8036 Arduino SA Leonardo (CDC ACM, HID) Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. SMC9514 Hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
なお、Raspberry Pi 3のシリアルポートは、コンソールとして使用する設定になっているため、解除する必要があります。詳細な手順は「Pro MicroとRaspberry Pi 3でUSBを使ったシリアル転送」を参照してください。
Pro MicroとRaspberry Pi 間の通信手順
- 転送の種類としては、ヘッダーを転送するヘッダー転送とテータを転送するデータ転送の2種類があり、Raspberry Pi からPro Microに対して転送要求を行い、その要求に従って、Pro MicroからRaspberry Piに対応するデータを転送します。
- ヘッダ転送の要求コードは「1」とし、ヘッダにはヘッダID「0x11」と2バイト長(バイト配置はリトルエンディアン)の転送バイト数が含まれます。
- データ転送の要求コードは「2」とし、データにはPro Microに保存してあるデータとそのチェックサムが含まれます。チェックサムはデータを加算していき、その下位から8ビット分を作成したデータの次に転送します。
Pro Micro側プログラムの作成
Pro MicroからRaspberry Pi 3にシリアルデータを送信するスケッチ「loger.ino」を次に示します。
- 17行目でRaspberry Pi 3からの要求を受信しているかを確認します。
- 23行目以降でヘッダーを作成します。33行目以降でデータを作成します。
38行目でチェックサムを出力します。
loger.ino
#define DATASIZE 12 byte input = 0; byte header[3] ; unsigned int size = DATASIZE; byte data[DATASIZE] ; byte chksum = 0; void setup() { Serial.begin(9600); for (int i = 0; i < DATASIZE; i++) { data[i] = i; } } void loop() { if (Serial.available() > 0) { input = Serial.read(); // get request } if (input == 1) { // header request input = 0; header[0] = 0x11; header[1] = size & 0xFF; header[2] = (size >> 8) & 0xFF; for (int i = 0; i < 3; i++) { Serial.write(header[i]); } } else if (input == 2) { // data request input = 0; chksum = 0; for (int i = 0; i < size; i++) { Serial.write(data[i]); chksum += data[i]; } Serial.write(chksum); } else { } }
Raspberry Pi側プログラムの作成
Raspberry Pi 3でPro Microからシリアルデータを受信するプログラム「loger.py」を次に示します。
- 11行目でヘッダ転送要求コード、12行目でデータ転送要求コードをそれぞれ取得します。
- 16行目から26行目でヘッダ転送の処理を行い、26行目でヘッダから転送バイト数を取得します。
- 29行目から42行目でデータ転送の処理を行い、受信したデータの保存とチェックサムを計算します。
- 44から48行目で計算したチェックサムと取得したチェックサムを比較します。
- 49行目で作成日時からファイル名を作成します。50行目から52行目で受信したデータを保存します。ただしチェックサムは除きます。
loger.py
import serial import struct import datetime x = [0x01, 0x02] headerbuf = [] databuf = [] def main(): headerreq = struct.pack("B", x[0]) datareq = struct.pack("B", x[1]) ser = serial.Serial('/dev/ttyACM0', 9600) ser.write(headerreq) for num in range(3): while True: if ser.in_waiting > 0: break recv_data = ser.read(1) a = struct.unpack_from("B", recv_data, 0) headerbuf.append(a) print(headerbuf[num]) datasize = int.from_bytes(headerbuf[1], byteorder='little') print(datasize) ser.write(datareq) checksum = 0 for num in range(datasize + 1): while True: if ser.in_waiting > 0: break recv_data = ser.read(1) a = struct.unpack_from("B", recv_data, 0) databuf.append(a) checksum = checksum + databuf[num][0] print(databuf[num]) print(databuf[datasize]) print(checksum) comp = (checksum - databuf[datasize][0]).to_bytes(2, byteorder="little")[0] if comp == databuf[datasize][0]: print(" ok") else: print(" ng") filename='log/log' + datetime.datetime.now().strftime('%Y%m%d%H%M%S')+'.bin' with open(filename, "wb") as f: for num in range(datasize): f.write(struct.pack("B", databuf[num][0])) if __name__ == '__main__': main()
Pro MicroとRaspberry Pi間のデータ転送
Pro Microのシリアル転送スケッチ「loger.ino」とRaspberry Pi 3のシリアル転送プログラム「loger.py」を実行すると、次のメッセージがRaspberry Pi 3に表示されます。
$ python3 loger.py (17,) (12,) (0,) 12 (0,) (1,) (2,) (3,) (4,) (5,) (6,) (7,) (8,) (9,) (10,) (11,) (66,) (66,) 132 ok
作成日時をファイル名に持つ次の内容のバイナリファイルが、フォルダ「log」に作成されます。