The jonki

呼ばれて飛び出てじょじょじょじょーんき

【Arduino/Android】SoftwareSerialでAndroidとArduionoの間でシリアル通信する

前回こんな記事を書きましたが、USBのシリアル通信でなくSoftwareSerialを使いました。

SoftwareSerialを使うことでUSBをPC側に繋いだまま開発ができます。またシリアル線ができたので他のマイコンなどにも使えて便利そうです。またVCCがあるのでPCとのUSBを外してもAndroid側から電力を供給できます。

用意するもの

Arduino

SoftwareSerialシリアル通信をソフト側でやろうというものです。USBケーブル内でやってる配線を簡単にArduino側の配線に繋げるイメージでしょうか。FTDIの変換アダプターはTX・RX・VCC・GNDArduino側とつなげます。TXとRXは送信と受信ですが、Arduino側のRX(10ピン)はアダプタ側のTX、TX(11ピン)はアダプタ側のRXと逆になるので注意してください。送る側に付けるのは受ける側、受ける側に繋がっているのは送る側ですからね。
Serial受信時はわかりやすいように13ピンのLEDを点灯させるようにしました。またSoftwareSerialのボーレートはこれより低いとメッセージの取りこぼしがありました。

#include "SoftwareSerial.h"

#define StringMaxLength 32

int ledNum = 13;
SoftwareSerial mySerial(10, 11); // RX, TX
char data[StringMaxLength];
int counter = 0;

void setup() {                
    Serial.begin(14400);
    pinMode(ledNum, OUTPUT);
    
    // set the data rate for the SoftwareSerial port
    mySerial.begin(9600);
    mySerial.println("Hello from Arduino SoftwareSerial!");
}

void loop() {
    if(mySerial.available()) {
        Serial.println("available");
        digitalWrite(ledNum, HIGH);
        data[counter] = mySerial.read();
        counter++;
        if(data[counter] == '\0' || counter == StringMaxLength) {
            data[counter] == '\0';
            Serial.println(data);
            mySerial.print("Hi from Arduino "); 
            mySerial.println(data);
            counter = 0; 
            digitalWrite(ledNum, LOW);
        }
    }
}

Android

ベースはFTDriverのサンプルとほぼ同じです。レイアウト変えたのと、TextViewをクリアするボタンをつけた感じです。Android側から固定のStringを送っていますが、テキストエリアから自在にメッセージを送るように作っても良いと思います。

アクティビティ
package net.jonki.serialapplication;

import jp.ksksue.driver.serial.FTDriver;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
    FTDriver mSerial;
    
    // [FTDriver] Permission String
    private static final String ACTION_USB_PERMISSION =
            "jp.ksksue.tutorial.USB_PERMISSION";
    
    Button btnBegin,btnRead,btnWrite,btnEnd;
    TextView tvMonitor;
    StringBuilder mText = new StringBuilder();;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnBegin = (Button) findViewById(R.id.btnBegin);
        btnRead = (Button) findViewById(R.id.btnRead);
        btnWrite = (Button) findViewById(R.id.btnWrite);
        btnEnd = (Button) findViewById(R.id.btnEnd);
        
        btnRead.setEnabled(false);
        btnWrite.setEnabled(false);
        btnEnd.setEnabled(false);
        
        tvMonitor = (TextView) findViewById(R.id.tvMonitor);
        
        // [FTDriver] Create Instance
        mSerial = new FTDriver((UsbManager)getSystemService(Context.USB_SERVICE));

        // [FTDriver] setPermissionIntent() before begin()
        PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(
                ACTION_USB_PERMISSION), 0);
        mSerial.setPermissionIntent(permissionIntent);
        
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();

        // [FTDriver] Close USB Serial
        mSerial.end();
    }
    
    public void onBeginClick(View view) {
        // [FTDriver] Open USB Serial
        if(mSerial.begin(FTDriver.BAUD9600)) {
            btnBegin.setEnabled(false);
            btnRead.setEnabled(true);
            btnWrite.setEnabled(true);
            btnEnd.setEnabled(true);
            
            Toast.makeText(this, "connected", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "cannot connect", Toast.LENGTH_SHORT).show();
        }
    }
    
    public void onReadClick(View view) {
        int i,len;

        // [FTDriver] Create Read Buffer
        byte[] rbuf = new byte[4096]; // 1byte <--slow-- [Transfer Speed] --fast--> 4096 byte

        // [FTDriver] Read from USB Serial
        len = mSerial.read(rbuf);
        mText.append("\n-------\n");
        for(i=0; i<len; i++) {
            mText.append((char) rbuf[i]);
        }
        tvMonitor.setText(mText);
    }
    
    public void onWriteClick(View view) {
        String wbuf = "Hello! I'm jonki.";
        mSerial.write(wbuf.getBytes());
    }
    
    public void onEndClick(View view) {
        // [FTDriver] Close USB Serial
        mSerial.end();
        
        btnBegin.setEnabled(true);
        btnRead.setEnabled(false);
        btnWrite.setEnabled(false);
        btnEnd.setEnabled(false);
        
        Toast.makeText(this, "disconnect", Toast.LENGTH_SHORT).show();
    }
    
    public void onClearClick(View view) {
    	mText.setLength(0);
    	tvMonitor.setText("");
    }
}
レイアウトファイル
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

	    <Button
	      android:id="@+id/btnBegin" 
	      android:layout_width="wrap_content"
	      android:layout_height="wrap_content"
		  android:textSize="12sp"
		  android:onClick="onBeginClick"
	      android:text="Begin"/>
	    <Button
	      android:id="@+id/btnRead" 
	      android:layout_width="wrap_content"
	      android:layout_height="wrap_content"
		  android:textSize="12sp"
		  android:onClick="onReadClick"
	      android:text="Read"/>
	    <Button
	      android:id="@+id/btnWrite" 
	      android:layout_width="wrap_content"
	      android:layout_height="wrap_content"
		  android:textSize="12sp"
		  android:onClick="onWriteClick"
	      android:text="Write"/>
	    <Button
	      android:id="@+id/btnEnd" 
	      android:layout_width="wrap_content"
	      android:layout_height="wrap_content"
		  android:textSize="12sp"
		  android:onClick="onEndClick"
	      android:text="End"/>
	    <Button
	      android:id="@+id/btnClear" 
	      android:layout_width="wrap_content"
	      android:layout_height="wrap_content"
		  android:textSize="12sp"
		  android:onClick="onClearClick"
	      android:text="Clear"/>

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >


    <TextView
        android:id="@+id/tvMonitor"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="" />

    </LinearLayout>
</LinearLayout>

まとめ

次は小さいATTinyでこれをやろうと思います。