テキスト送受信

ここではArduinoからデータを送り、Android側でデータを受け取るという形式で連携してみたいと思います。

Arduino設定

まずはArduino側の設定を行います。
回路については「1.事前準備」で作成した回路を使用します。
Arduino UNOとArduino MEGAでは回路とスケッチが異なりますので別々に記載します。

回路ができましたらスケッチを書いてみましょう。
スケッチはArduino IDEを起動して行います。


Arduino UNO

回路 (Arduino Uno)

スケッチ (Arduino UNO)

#include <SoftwareSerial.h>

SoftwareSerial android(2,3);
// SoftwareSerial android(12,13); // Fabo Brick使用時

void setup(){
  // Bluetooth用のシリアルのポートを設定
  android.begin(115200);
  // arduinoのシリアルモニタ用
  Serial.begin(9600); 

  Serial.write("init");
}

void loop(){

  if(android.available()){
    Serial.println(android.read());
  } 

  if(Serial.available()){
    android.write(Serial.read());
  } 

}

Arduino Mega

回路 (Arduino Mega)


スケッチ (Arduino Mega)

Arduino MegaではSoftserialがうまく動かないので18, 19番ピンを使用します。

18,19番ピンは

Serial1.begin(速度);

で呼び出せます。

Bluetoothモジュールと、Android間はデフォルトで、115200の速度なので

Serial1.begin(115200);

とします。

変更後はこちら

void setup(){
  // Bluetooth用のシリアルのポートを設定
  Serial1.begin(115200);
  // arduinoのシリアルモニタ用
  Serial.begin(9600); 

  Serial.write("init");
}

void loop(){

  if(Serial1.available()){
    Serial.println(Serial1.read());
  } 

  if(Serial.available()){
    Serial1.write(Serial.read());
  } 

}

AndroidのProject作成

次にAndroid側のアプリを作成します。
Androidのアプリ作成には「Android Studio」を使用します。
Android Studioを起動し、Quick Startの一番上にある「Start a new Android Studio project」を選択します。

New Projectのウィンドウが表示されます。
Application nameにアプリ名「MyBluetooth」を入力し、「Next」ボタンを押下します。

ここは変更せずに「Next」ボタンを押下します。

Blank Activityを選択し、「Next」ボタンを押下します。

Activityの名前を入力し、「Finish」ボタンを押下します。
今回は名前を変更せずに進めます。

プロジェクトが作成されました。

ビューの表示形式を変更します。
画面左上にある「Android」という箇所をクリックすると、すぐ下に「Project」という項目が表示されるので、そちらを選択します。

ビューの表示形式が変更されました。

Bluetooth認識設定

次にBluetoothの認識設定を行います。
[app]>[src]>[main]>[res]内のAndroidManifest.xmlを開き、下記の内容を追加します。

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

AndroidManifest.xml

変更後はこのような状態になります。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="gclue.com.mybluetooth" >

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

プログラム作成

[src]>[main]>[res]>[layout]内にあるactivity_main.xmlを変更します。
このファイルは画面レイアウトの設定するファイルになります。
activity_main.xmlファイルを開くとレイアウトが表示されるので、画面右下のタブから「Text」のタブを選択することでコードが入力できる状態になります。

activity_main.xml

<?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" >

    <Button android:id="@+id/connectButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Connect" />

    <TextView
        android:id="@+id/statusValue"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        />

    <TextView
        android:id="@+id/inputValue"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        />

    <Button android:id="@+id/writeButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Write" />

</LinearLayout>

次に[src]にある「MainActivity.java」を開き、プログラムを入力します。
1行目のpackageの箇所は環境によって異なりますので、初期状態から変更せずそのままの状態にしてください。

また、"RNBT-205F"は「1.BLUETOOTH 事前準備」のペアリング時にでてきたデバイス名となりますので、それに合わせて変更して下さい。

MainActivity.java

package gclue.com.mybluetooth;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
//import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;

//public class MainActivity extends ActionBarActivity implements Runnable, View.OnClickListener {
public class MainActivity extends AppCompatActivity implements Runnable, View.OnClickListener {
    /* tag */
    private static final String TAG = "BluetoothSample";

    /* Bluetooth Adapter */
    private BluetoothAdapter mAdapter;

    /* Bluetoothデバイス */
    private BluetoothDevice mDevice;

    /* Bluetooth UUID(固定) */
    private final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    /* デバイス名 環境に合わせて変更*/
    private final String DEVICE_NAME = "RNBT-205F";

    /* Soket */
    private BluetoothSocket mSocket;

    /* Thread */
    private Thread mThread;

    /* Threadの状態を表す */
    private boolean isRunning;

    /** 接続ボタン. */
    private Button connectButton;

    /** 書込みボタン. */
    private Button writeButton;

    /** ステータス. */
    private TextView mStatusTextView;

    /** Bluetoothから受信した値. */
    private TextView mInputTextView;

    /** Action(ステータス表示). */
    private static final int VIEW_STATUS = 0;

    /** Action(取得文字列). */
    private static final int VIEW_INPUT = 1;

    /** Connect確認用フラグ */
    private boolean connectFlg = false;

    /** BluetoothのOutputStream. */
    OutputStream mmOutputStream = null;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        // Layoutにて設定したビューを表示
        setContentView(R.layout.activity_main);

        // TextViewの設定(Layoutにて設定したものを関連付け)
        mInputTextView = (TextView)findViewById(R.id.inputValue);
        mStatusTextView = (TextView)findViewById(R.id.statusValue);

        // Buttonの設定(Layoutにて設定したものを関連付け)
        connectButton = (Button)findViewById(R.id.connectButton);
        writeButton = (Button)findViewById(R.id.writeButton);

        // ボタンのイベント設定
        connectButton.setOnClickListener(this);
        writeButton.setOnClickListener(this);

        // Bluetoothのデバイス名を取得
        // デバイス名は、RNBT-XXXXになるため、
        // DVICE_NAMEでデバイス名を定義
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mStatusTextView.setText("SearchDevice");
        Set< BluetoothDevice > devices = mAdapter.getBondedDevices();
        for ( BluetoothDevice device : devices){

            if(device.getName().equals(DEVICE_NAME)){
                mStatusTextView.setText("find: " + device.getName());
                mDevice = device;
            }
        }
    }

    // 別のアクティビティが起動した場合の処理
    @Override
    protected void onPause(){
        super.onPause();

        isRunning = false;
        connectFlg = false;

        try{
            mSocket.close();
        }
        catch(Exception e){}
    }

    // スレッド処理(connectボタン押下後に実行)
    @Override
    public void run() {
        InputStream mmInStream = null;

        Message valueMsg = new Message();
        valueMsg.what = VIEW_STATUS;
        valueMsg.obj = "connecting...";
        mHandler.sendMessage(valueMsg);

        try{

            // 取得したデバイス名を使ってBluetoothでSocket接続
            mSocket = mDevice.createRfcommSocketToServiceRecord(MY_UUID);
            mSocket.connect();
            mmInStream = mSocket.getInputStream();
            mmOutputStream = mSocket.getOutputStream();

            // InputStreamのバッファを格納
            byte[] buffer = new byte[1024];

            // 取得したバッファのサイズを格納
            int bytes;
            valueMsg = new Message();
            valueMsg.what = VIEW_STATUS;
            valueMsg.obj = "connected.";
            mHandler.sendMessage(valueMsg);

            connectFlg = true;

            while(isRunning){

                // InputStreamの読み込み
                bytes = mmInStream.read(buffer);
                Log.i(TAG,"bytes="+bytes);
                // String型に変換
                String readMsg = new String(buffer, 0, bytes);

                // null以外なら表示
                if(readMsg.trim() != null && !readMsg.trim().equals("")){
                    Log.i(TAG,"value="+readMsg.trim());

                    valueMsg = new Message();
                    valueMsg.what = VIEW_INPUT;
                    valueMsg.obj = readMsg;
                    mHandler.sendMessage(valueMsg);
                }
            }
        }
        // エラー処理
        catch(Exception e){

            valueMsg = new Message();
            valueMsg.what = VIEW_STATUS;
            valueMsg.obj = "Error1:" + e;
            mHandler.sendMessage(valueMsg);

            try{
                mSocket.close();
            }catch(Exception ee){}
            isRunning = false;
            connectFlg = false;
        }
    }

    // ボタン押下時の処理
    @Override
    public void onClick(View v) {
        if(v.equals(connectButton)) {
            // 接続されていない場合のみ
            if (!connectFlg) {
                mStatusTextView.setText("try connect");

                mThread = new Thread(this);
                // Threadを起動し、Bluetooth接続
                isRunning = true;
                mThread.start();
            }
        } else if(v.equals(writeButton)) {
            // 接続中のみ書込みを行う
            if (connectFlg) {
                try {
                    // Writeボタン押下時、'2'を送信
                    mmOutputStream.write("2".getBytes());
                    // 画面上に"Write:"を表示
                    mStatusTextView.setText("Write:");
                } catch (IOException e) {
                    Message valueMsg = new Message();
                    valueMsg.what = VIEW_STATUS;
                    valueMsg.obj = "Error2:" + e;
                    mHandler.sendMessage(valueMsg);
                }
            } else {
                mStatusTextView.setText("Please push the connect button");
            }
        }
    }

    /**
     * 描画処理はHandlerでおこなう
     */
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            int action = msg.what;
            String msgStr = (String)msg.obj;
            if(action == VIEW_INPUT){
                mInputTextView.setText(msgStr);
            }
            else if(action == VIEW_STATUS){
                mStatusTextView.setText(msgStr);
            }
        }
    };
}

Android端末での実行設定

アプリケーション実行、及び確認
準備が完了しましたので、作成したアプリケーションを実行してみましょう。

AndroidのConnectボタンを押すと、1〜3秒ほどで赤点滅から緑の点灯にかわります。
これでデータが送受信できる状態になりました。

Connectが完了しましたら、次にAndroidのWriteボタンを押します。

Arduino側のシリアルモニタを確認すると、50(2のasciiコード)が転送されます。
※Arduino側でSerial.write(取得値)とするか、char型の変数に格納してから出力すると「2」が出力されます。

ArduinoのSerial Consoleで、文字を入力し、送信を押すと、Androidに文字が送られ画面に表示されます。 Arduino側で文字を入力し、送信ボタンを押下します。

Android側に文字が表示されました。