Imaginary Code

from kougaku-navi.net

ProcessingからArduinoへint型のデータを送る

これの逆バージョンの話です。

ヘッダに文字を使う方法

データを分割して送信する際に、先頭に「H」という文字を付けて送る方法です。

Processing
  • int型のデータを上位バイトと下位バイトに分けて送信する
  • データを正しい順序で受信するためにヘッダをつけて送信する
import processing.serial.*;
Serial serial;

void setup() {
  // シリアルポートの番号と通信速度は適宜修正してください。
  serial = new Serial(this, "COM114", 9600);  
}

void draw() {
}

// テストとして、画面をクリックした際に1024という数値を送信
void mousePressed() { 
  sendIntData(1024);
}

// Processingで扱うintは4バイトなのに対し、
// Arduino UnoやLeonardoで扱うintは2バイトなので注意。
// (よって、使う数値は-32768~32767の範囲にとどめておく)

// intデータの送信
void sendIntData(int value) {
  byte high = (byte)((value & 0xFF00) >> 8);
  byte low =  (byte)( value & 0x00FF);
  serial.write('H');  // ヘッダの送信
  serial.write(high); // 上位バイトの送信
  serial.write(low);  // 下位バイトの送信
}

// Arduino側できちんと受信・復元できたかを確認するために
// データを文字列として送り返してもらって、それをコンソールに表示。
// (Processingとの通信中にシリアルモニタが使えないので)

// データの受信
void serialEvent(Serial port) {
  if ( port.available() > 0 ) {
    String data = trim(port.readStringUntil('\n'));
    if ( data != null ) {
      println("data =", data);
    }
  }
}
Arduino
  • 3バイト(ヘッダ+int)以上のデータが着ているか確認
  • データが着てたらまずヘッダがあるか確認
  • ヘッダがあったら、下位バイトと上位バイトを読み取り、その値を合体してint型のデータを復元
void setup() {
  Serial.begin(9600);
}

void loop() {
  if ( Serial.available() >= 3 ) {
    if ( Serial.read() == 'H' ) {
      byte high = Serial.read();
      byte low  = Serial.read();
      int recv_data = high * 256 + low;  // 受信データ

      // 受信確認のために、数値を文字列で送り返す
      Serial.println(recv_data);
    }
  }
}

ProcessingからArduinoに「1024」という数値をバイナリデータとして送信します。Arduino側では、受信確認のために、受け取ったデータをProcessingに文字データとして送り返します。その結果、Processingのコンソールに「data = 1024」という文字が表示されます。

ヘッダに文字を使わない方法

ヘッダに文字を使っていると、その文字コードが数値の一部とたまにかぶってしまう問題があります。それを気にする場合は以下のような方法を採ります。

f:id:kougaku-navi:20141009003929p:plain

この方法を実装したのが以下のプログラムです。デモ内容は先ほどと同様です。

Processing
import processing.serial.*;

Serial serial;

void setup() {
  // シリアルポートの番号と通信速度は適宜修正してください。
  serial = new Serial(this, "COM114", 9600);
}

void draw() {
}

// テストとして、画面をクリックした際に1024という数値を送信
void mousePressed() { 
  sendIntData(1024);
}

// Processingで扱うintは4バイトなのに対し、
// Arduino UnoやLeonardoで扱うintは2バイトなので注意。
// (よって、使う数値は-32768~32767の範囲にとどめておく)

// intデータの送信
void sendIntData(int value) {
  byte low  = (byte)(value & 127);  
  byte high = (byte)((value >> 7) & 127);
  byte head = (byte)(((value >> 14) & 127) + 128);  
  serial.write(head);
  serial.write(high);
  serial.write(low);
}

// Arduino側できちんと受信・復元できたかを確認するために
// データを文字列として送り返してもらって、それをコンソールに表示。
// (Processingとの通信中にシリアルモニタが使えないので)

// データの受信
void serialEvent(Serial port) {
  if ( port.available() > 0 ) {
    String data = trim(port.readStringUntil('\n'));
    if ( data != null ) {
      println("data =", data);
    }
  }
}
Arduino
void setup() {
  Serial.begin(9600);
}

void loop() {
  if ( Serial.available() >= 3 ) {
    byte head = Serial.read();  // 1番目のデータ
    if ( head >= 128 ) {          // 128以上であれば先頭データなので、それに続くデータを読み取る
      byte high = Serial.read();  // 2番目のデータ
      byte low  = Serial.read();  // 3番目のデータ
      int recv_data = ((head - 128) << 14) + (high << 7) + low;  // 受信データ

      // 受信確認のために、数値を文字列で送り返す
      Serial.println(recv_data);
    }
  }
}

以上です。