In diesem FAQ wird ein Android Smartphone mit einem Arduino über Bluetooth verbunden. Es werden Nachrichten in beide Richtungen übertragen.

 

 

Benötigte Bauteile:
# Bezeichnung ~Preis
1 Bluetooth-Seriell Modul RS232 (ebay) 6,00 €
1 LED 0,05 €
1 Widerstand 200 Ohm 0,01 €
    ~ 6 €

 

Benötigte Werkzeuge:
# Bezeichnung
1 Arduino
1 Breadboard
1 Android Smartphone
(Beispiel: Mindestens API Level 10 = Android 2.3.3 )

 

Aufbau:

Als erstes muss das Bluetooth Modul mit Strom versorgt werden. VCC an 5V und GND an GND.

Dann RX des Moduls an Arduino PIN 2 und TX des Moduls an Arduino PIN3:

 

Ansicht von oben:

Optional kann noch eine LED in Reihe mit einem 220 Ohm Widerstand an Arduino PIN 13 geschaltet werden oder die im Board integrierte verwendet werden.

 

Folgendes Codeschnippsel (beispiel_bluetooth.ino) leitet die seriellen Eingaben an das Bluetooth Modul weiter und umgekehrt. Jedes mal, wenn ein Zeichen empfangen wird, wird die Status LED ein- oder ausgeschaltet.

 

/* -------------------------------------------
/* Bluetooth Seriell senden und empfangen
/* www.frag-duino.de
/* -------------------------------------------
/* Befehle:
/* Sendet alles, was eingegeben wird
/* Empfaengt alles, was gesendet wurde
 ------------------------------------------- */

// Konstanten
#define PIN_RECEIVE 2
#define PIN_SEND 3
#define PIN_STATUS 13
#define SPEED_BLUETOOTH 9600
#define SPEED_SERIAL 9600

// INEX BT Board 9600
// Linkmatic 115200

// Includes
#include <SoftwareSerial.h>

// Variablen
SoftwareSerial blueSerial(PIN_RECEIVE, PIN_SEND);
int zustand_status = HIGH;

void setup()  
{
  Serial.begin(SPEED_SERIAL);
  Serial.println("Bluetooth Serial initialisiert");
  pinMode(PIN_STATUS, OUTPUT); 

  // auf seriellen Port horchen
  blueSerial.begin(SPEED_BLUETOOTH); 
  blueSerial.println("Bluetooth Serial Verbindung hergestellt");
}

void loop()
{
  // Sendet alles, was eingegeben wird.
  if (Serial.available())
    blueSerial.write(Serial.read());

  // Gibt alles aus, was empfangen wird:
  if (blueSerial.available()){
    Serial.write(blueSerial.read());
    if(zustand_status == HIGH)
      zustand_status=LOW;
    else zustand_status=HIGH;
  }
  digitalWrite(PIN_STATUS,zustand_status);
}

Im nächsten Schritt muss die MAC-Adresse des Bluetooth-Adapters ermittelt werden. Das geht z.B. indem man es in Windows koppelt (Code: 0000 oder 1234) und dann die Eigenschaften des Geräts einsieht ("Eindeutige ID"):

Auf Android-Seite, hilft die folgende Activity (blueActivity.java).

package de.fragduino.bluetest;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class blueActivity extends Activity {

	/*
	 * Arduino Bluetooth-Modul. Android Test-Applikation www.frag-duino.de
	 */

	// UUID fuer Kommunikation mit Seriellen Modulen
	private UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
	private static final String LOG_TAG = "FRAGDUINO";

	// Variablen
	private BluetoothAdapter adapter = null;
	private BluetoothSocket socket = null;
	private OutputStream stream_out = null;
	private InputStream stream_in = null;
	private boolean is_connected = false;
	private static String mac_adresse; // MAC Adresse des Bluetooth Adapters

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		Log.d(LOG_TAG, "Bluetest: OnCreate");

		// Textfeld setzen
		((TextView) findViewById(R.id.text_uuid)).setText("UUID: " + uuid);

		// Verbindung mit Bluetooth-Adapter herstellen
		adapter = BluetoothAdapter.getDefaultAdapter();
		if (adapter == null || !adapter.isEnabled()) {
			Toast.makeText(this, "Bitte Bluetooth aktivieren",
					Toast.LENGTH_LONG).show();
			Log.d(LOG_TAG,
					"onCreate: Bluetooth Fehler: Deaktiviert oder nicht vorhanden");
			finish();
			return;
		} else
			Log.d(LOG_TAG, "onCreate: Bluetooth-Adapter ist bereit");
	}

	public void verbinden(View v) {
		mac_adresse = ((EditText) findViewById(R.id.text_adresse)).getText()
				.toString();
		Log.d(LOG_TAG, "Verbinde mit " + mac_adresse);

		BluetoothDevice remote_device = adapter.getRemoteDevice(mac_adresse);

		// Socket erstellen
		try {
			socket = remote_device
					.createInsecureRfcommSocketToServiceRecord(uuid);
			Log.d(LOG_TAG, "Socket erstellt");
		} catch (Exception e) {
			Log.e(LOG_TAG, "Socket Erstellung fehlgeschlagen: " + e.toString());
		}

		adapter.cancelDiscovery();

		// Socket verbinden
		try {
			socket.connect();
			Log.d(LOG_TAG, "Socket verbunden");
			is_connected = true;
		} catch (IOException e) {
			is_connected = false;
			Log.e(LOG_TAG, "Socket kann nicht verbinden: " + e.toString());
		}

		// Socket beenden, falls nicht verbunden werden konnte
		if (!is_connected) {
			try {
				socket.close();
			} catch (Exception e) {
				Log.e(LOG_TAG,
						"Socket kann nicht beendet werden: " + e.toString());
			}
		}

		// Outputstream erstellen:
		try {
			stream_out = socket.getOutputStream();
			Log.d(LOG_TAG, "OutputStream erstellt");
		} catch (IOException e) {
			Log.e(LOG_TAG, "OutputStream Fehler: " + e.toString());
			is_connected = false;
		}

		// Inputstream erstellen
		try {
			stream_in = socket.getInputStream();
			Log.d(LOG_TAG, "InputStream erstellt");
		} catch (IOException e) {
			Log.e(LOG_TAG, "InputStream Fehler: " + e.toString());
			is_connected = false;
		}

		if (is_connected) {
			Toast.makeText(this, "Verbunden mit " + mac_adresse,
					Toast.LENGTH_LONG).show();
			((Button) findViewById(R.id.bt_verbinden))
					.setBackgroundColor(Color.GREEN);
		} else {
			Toast.makeText(this, "Verbindungsfehler mit " + mac_adresse,
					Toast.LENGTH_LONG).show();
			((Button) findViewById(R.id.bt_verbinden))
					.setBackgroundColor(Color.RED);
		}
	}

	public void senden(View v) {
		String message = ((EditText) findViewById(R.id.text_eingabe)).getText()
				.toString();
		byte[] msgBuffer = message.getBytes();
		if (is_connected) {
			Log.d(LOG_TAG, "Sende Nachricht: " + message);
			try {
				stream_out.write(msgBuffer);
			} catch (IOException e) {
				Log.e(LOG_TAG,
						"Bluetest: Exception beim Senden: " + e.toString());
			}
		}
	}

	public void empfangen(View v) {
		byte[] buffer = new byte[1024]; // Puffer
		int laenge; // Anzahl empf. Bytes
		String msg = "";
		try {
			if (stream_in.available() > 0) {
				laenge = stream_in.read(buffer);
				Log.d(LOG_TAG,
						"Anzahl empfangender Bytes: " + String.valueOf(laenge));

				// Message zusammensetzen:
				for (int i = 0; i < laenge; i++)
					msg += (char) buffer[i];

				Log.d(LOG_TAG, "Message: " + msg);
				Toast.makeText(this, msg, Toast.LENGTH_LONG).show();

			} else
				Toast.makeText(this, "Nichts empfangen", Toast.LENGTH_LONG)
						.show();
		} catch (Exception e) {
			Log.e(LOG_TAG, "Fehler beim Empfangen: " + e.toString());
		}
	}

	public void trennen(View v) {
		if (is_connected && stream_out != null) {
			is_connected = false;
			((Button) findViewById(R.id.bt_verbinden))
					.setBackgroundColor(Color.RED);
			Log.d(LOG_TAG, "Trennen: Beende Verbindung");
			try {
				stream_out.flush();
				socket.close();
			} catch (IOException e) {
				Log.e(LOG_TAG,
						"Fehler beim beenden des Streams und schliessen des Sockets: "
								+ e.toString());
			}
		} else
			Log.d(LOG_TAG, "Trennen: Keine Verbindung zum beenden");
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		Log.d(LOG_TAG, "onDestroy. Trenne Verbindung, falls vorhanden");
		trennen(null);
	}
}

Dafür muss in der Android.manifest noch das Bluetooth-Recht gegeben werden:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="de.fragduino.bluetest"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="10"
        android:targetSdkVersion="10" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name="de.fragduino.bluetest.blueActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

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

</manifest>

Die Main.xml gestaltet das rudimentäre UI:

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

    <TextView
        android:id="@+id/text_uuid"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="UUID" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="MAC Adresse des Bluetooth Devices:" />

    <EditText
        android:id="@+id/text_adresse"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:text="00:11:12:14:00:35" >
    </EditText>

    <Button
        android:id="@+id/bt_verbinden"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="verbinden"
        android:text="Verbinden" />

    <Button
        android:id="@+id/bt_verbinden"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="trennen"
        android:text="Trennen" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Eingabe:" />

    <EditText
        android:id="@+id/text_eingabe"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:text="Test 123" >

        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/bt_senden"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="senden"
        android:text="Senden" />

    <Button
        android:id="@+id/bt_empfangen"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="empfangen"
        android:text="Empfangen" />

</LinearLayout>

Zur Benutzung:

Bevor die Android-App gestartet wird, muss Bluetooth aktiviert worden sein und ein Paring mit dem Gerät geschehen. Bei meinem Dongle ("linvor") musste ich den Pin "1234" verwenden.

Das UI sieht folgendermaßen aus:

Als erstes muss die oben ermittelte MAC Adresse des Moduls eingetragen werden und der Button "Verbinden" gedrückt werden. War die Verbindung erfolgreich, ändert sich die Farbe des Buttons auf Grün:

Auftretende Fehler können unter dem Logtag "FRAGDUINO" eingesehen werden.

Ist die Verbindung erst hergestellt, kann eine Nachricht im Feld "Eingabe:" gemacht werden und mit "Senden" abgesendet werden.

Das Resultat auf Arduino-Seite (hier in der Arduino IDE im Serial Monitor) sieht dann so aus:

 

Um den umgekehrten Weg zu testen, muss eine Nachricht in der seriellen Konsole eingegeben und "Senden" geklickt werden. Die Nachricht erscheint dann in der Android-App, nachdem man den "Empfangen"-Button gedrückt hat:

Diese Vorgang könnte auch in einem eigenen Thread automatisiert werden.

Die Beispiel-Dateien gibt es hier:

bluetest.zip