📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

編集の要約なし
 
(同じ利用者による、間の6版が非表示)
20行目: 20行目:
下図右のように、HC-06のバージョンを確認する場合は、<code>AT+VERSION</code>を送信する。<br>
下図右のように、HC-06のバージョンを確認する場合は、<code>AT+VERSION</code>を送信する。<br>
このように、<code>AT+<コマンド></code>という形式のデータを送信することで、モジュールの設定を行うことができる。<br>
このように、<code>AT+<コマンド></code>という形式のデータを送信することで、モジュールの設定を行うことができる。<br>
 
[[ファイル:Arduino Bluetooth 1.jpg|フレームなし|中央]]
<br>
<br>
まず、デバイス名をMYBTに設定するため、以下のコマンドを送信する。<br>
まず、デバイス名をMYBTに設定するため、以下のコマンドを送信する。<br>
44行目: 44行目:
下図に、回路図および配線図を示す。<br>
下図に、回路図および配線図を示す。<br>
下図右では、ArduinoからのTXを分圧している抵抗器が接続されている。<br>
下図右では、ArduinoからのTXを分圧している抵抗器が接続されている。<br>
 
[[ファイル:Arduino Bluetooth 2.jpg|フレームなし|中央]]
<br>
<br>
以下に、Arduinoのサンプルコードを記述する。<br>
以下に、Arduinoのサンプルコードを記述する。<br>
151行目: 151行目:
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
== HC-06とクライアント ==
上記のセクションに記載したArduinoで温度データを送信するデバイス・ソフトウェアにおいて、<br>
Bluetoothを使用してPCまたはスマートフォンと接続して、温度データを受信するPCまたはスマートフォンのソフトウェアの作成手順を記載する。<br>
<br>
==== PCのソフトウェア ====
ソフトウェアの開発は、Visual Studio 2019のコンソールを用いている。<br>
予め、HC-06とペアリングする必要がある。PINは、0000または1234のいずれかである。<br>
<br>
標準ライブラリにあるBluetoothのAPIはUWP専用であるため、NuGetからコンソールでも使用できる<code>UwpDesktop</code>をインストールする。<br>
Visual Studioの[プロジェクト]メニューバー - [NuGet パッケージの管理]を選択して、UwpDesktopと入力してインストールする。<br>
<br>
以下に、Bluetooth通信の手順を大まかに記載する。<br>
* 周囲のBluetoothデバイスをスキャンする。
* 見つかったデバイスから、接続・通信を行う端末かどうかを確認して、データの受信を行う。
<br>
まず、周囲のBluetoothデバイスをスキャンする。<br>
Bluetoothデバイスは、アドバタイズパケットという自身の場所を伝えるためのデータを発信するため、<br>
そのパケットをスキャンすることでBluetoothデバイスを認識して接続することができる。<br>
<br>
以下の例では、<code>BluetoothLEAdvertisementWatcher</code>クラスのプロパティの値を設定した後、Startメソッドを実行してスキャンしている。<br>
<syntaxhighlight lang="c#">
using System;
using System.Threading;
using Windows.Devices.Bluetooth.Advertisement;
class Program
{
    private static BluetoothLEAdvertisementWatcher advWatcher;
    static async void Main(string[] args)
    {
      Console.WriteLine("Start");
      advWatcher = new BluetoothLEAdvertisementWatcher();
      advWatcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(1000);
      advWatcher.ScanningMode = BluetoothLEScanningMode.Passive;
      advWatcher.Received += WatcherReceived;
      advWatcher.Start();
      await Task.Delay(60000);
      advWatcher.Stop();
      Console.WriteLine("Stop");
    }
}
</syntaxhighlight>
<br>
次に、スキャンして見つかったデバイスにおいて、接続・通信を行うデバイスかどうか確認する。<br>
<code>WatcherReceived</code>メソッドからスキャンされたデバイスの情報を受信するので、その情報を元に確認する。<br>
# スキャンして見つかったデバイスが持つUUIDと、接続・通信を行うデバイスのUUIDを比較する。
# 同じなら、スキャンを停止してそのデバイスと接続する。
# 接続したデバイスから、サービスのUUIDとキャラクタリスティックのUUIDを用いて目的のデータにアクセスする。
# アクセスに成功した後、コールバックを設定して、目的のデータの受信する。<br>以下のサンプルコードにおいて、<code>CharacteristicChangedVroomController</code>メソッド(ユーザ自身が作成したメソッド)は、<br>受信したデータ(バイト列)に対して、任意の処理を行うメソッドである。
<br>
UUIDを確認する理由は、Bluetooth通信で使用されるデータフォーマットGATTがあるためである。<br>
GATTは、<u>サービス</u>と<u>キャラクタリスティック</u>の2つから構成されており、各々がUUIDで設定されている。<br>
サービスがフォルダ、キャラクタリスティックがファイルに相当する。<br>
<br>
GATTに則っているBluetoothデバイスは、必ずこの形式でデータを送受信するため、UUIDを確認することで目的のデバイスを判別できる。<br>
UUIDを知る方法は、販売元が公開している場合や自身で全パケットを確認する方法がある。<br>
<syntaxhighlight lang="c#">
private GattDeviceService gattService;
private GattCharacteristic vroomService;
private readonly String serviceGuid = "00001101-0000-1000-8000-00805f9b34fb";
private async Task WatcherReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
    bool find = false;
    var bleServiceUUIDs = args.Advertisement.ServiceUuids;
    foreach (var uuidone in bleServiceUUIDs)
    {
      // serviceGuid : デバイス固有のGUID
      if (uuidone == serviceGuid)
      {
          // 発見
          find = true;
          break;
      }
    }
    if (find)
    {
      try
      {
          // スキャンの停止
          advWatcher.Stop();
          // デバイスと接続
          BluetoothLEDevice device = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
          // UUIDを用いて目的のデバイスを取得
          gattService = device.GetGattService(serviceGuid);
          // キャラクタリスティックUUIDを用いて目的のキャラクタリスティックを取得
          var characteristics = gattService.GetCharacteristics(new Guid("キャラクタリスティックのGuid"));
          // 戻り値の配列が空かどうか確認
          if (characteristics.Count > 0)
          {
            vroomService = characteristics.First();
            if (vroomService == null)
            {
                throw new Exception("Not Exist Service");
            }
            // 読み取り可能な場合、キャラクタリスティックにアクセスしてコールバックを設定
            if (vroomService.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Read))
            {
                vroomService.ValueChanged += CharacteristicChangedVroomController;
                Console.WriteLine("Connect");
                await vroomService.ReadClientCharacteristicConfigurationDescriptorAsync();
            }
          }
      }
      catch (Exception ex)
      {
          Console.WriteLine($"Exception...{ex.Message})");
      }
    }
}
</syntaxhighlight>
<br>
==== スマートフォン(Android)のソフトウェア ====
クライアントからサーバに接続する時、RFCOMMチャネルを作成してBluetoothSocketを作成する必要があるが、<br>
この時に指定するUUIDは、SPP(シリアルポートプロファイル)のUUIDである00001101-0000-1000-8000-00805f9b34fbを指定する。<br>
<br>
また、デバイス名はMYBTとしているため、BondedリストからBluetoothDeviceを探す際の名前も変更する。<br>
<br>
Bluetooth通信を使用するパーミッションを設定する。<br>
ディスカバリは行わないため、LOCATIONのパーミッションは設定しない。<br>
<syntaxhighlight lang="xml">
<!-- AndroidManifest.xmlファイル -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.keicode.android.testapps.bttest1c">
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:supportsRtl="true"
      android:theme="@style/AppTheme"
    >
      <activity android:name=".MainActivity" android:configChanges="orientation">
            <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
      </activity>
    </application>
</manifest>
</syntaxhighlight>
<br>
状態を表示するためのTextViewとArduinoおよびHC-06から送信される文字を表示するためのTextViewの計2つのTextViewを並べている。<br>
<syntaxhighlight lang="xml">
<!-- res/layout/activity_main.xmlファイル -->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.keicode.android.testapps.bttest1c.MainActivity">
    <TextView
        android:id="@+id/btStatusTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Not connected" />
    <TextView
        android:id="@+id/tempTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="(unknown)"
        android:layout_below="@id/btStatusTextView"
        android:textSize="24sp"/>
</RelativeLayout>
</syntaxhighlight>
<br>
以下のサンプルコードでは、ワーカースレッド用に1つのクラスを定義しているだけである。<br>
例外が発生した場合、その状況をHandlerを介してUI側にフィードバックしている。<br>
<syntaxhighlight lang="java">
// MainActivity.java
package com.keicode.android.testapps.bttest1c;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Set;
public class MainActivity extends AppCompatActivity
{
    static final String TAG = "BTTEST1";
    BluetoothAdapter bluetoothAdapter;
    TextView btStatusTextView;
    TextView tempTextView;
    BTClientThread btClientThread;
    final Handler handler = new Handler()
    {
      @Override
      public void handleMessage(Message msg)
      {
          String s;
          switch(msg.what)
          {
            case Constants.MESSAGE_BT:
                s = (String) msg.obj;
                if(s != null)
                {
                  btStatusTextView.setText(s);
                }
                break;
            case Constants.MESSAGE_TEMP:
                s = (String) msg.obj;
                if(s != null)
                {
                  tempTextView.setText(s);
                }
                break;
          }
      }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
      Log.d(TAG, "onCreate");
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      // Find Views
      btStatusTextView = (TextView) findViewById(R.id.btStatusTextView);
      tempTextView = (TextView) findViewById(R.id.tempTextView);
      if(savedInstanceState != null)
      {
          String temp = savedInstanceState.getString(Constants.STATE_TEMP);
          tempTextView.setText(temp);
      }
      // Initialize Bluetooth
      bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
      if( bluetoothAdapter == null )
      {
          Log.d(TAG, "This device doesn't support Bluetooth.");
      }
    }
    @Override
    protected void onResume()
    {
      super.onResume();
      btClientThread = new BTClientThread();
      btClientThread.start();
    }
    @Override
    protected void onPause()
    {
      super.onPause();
      if(btClientThread != null)
      {
          btClientThread.interrupt();
          btClientThread = null;
      }
    }
    @Override
    protected void onSaveInstanceState(Bundle outState)
    {
      super.onSaveInstanceState(outState);
      outState.putString(Constants.STATE_TEMP, tempTextView.getText().toString());
    }
    public class BTClientThread extends Thread
    {
      InputStream inputStream;
      OutputStream outputStrem;
      BluetoothSocket bluetoothSocket;
      public void run()
      {
          byte[] incomingBuff = new byte[64];
          BluetoothDevice bluetoothDevice = null;
          Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();
          for(BluetoothDevice device : devices)
          {
            if(device.getName().equals(Constants.BT_DEVICE))
            {
                bluetoothDevice = device;
                break;
            }
          }
          if(bluetoothDevice == null)
          {
            Log.d(TAG, "No device found.");
            return;
          }
          try
          {
            bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(Constants.BT_UUID);
            while(true)
            {
                if(Thread.interrupted())
                {
                  break;
                }
                try
                {
                  bluetoothSocket.connect();
                  handler.obtainMessage(Constants.MESSAGE_BT, "CONNECTED " + bluetoothDevice.getName()).sendToTarget();
                  inputStream = bluetoothSocket.getInputStream();
                  outputStrem = bluetoothSocket.getOutputStream();
                  while(true)
                  {
                      if(Thread.interrupted())
                      {
                        break;
                      }
                      // Send Command
                      String command = "GET:TEMP";
                      outputStrem.write(command.getBytes());
                      // Read Response
                      int incomingBytes = inputStream.read(incomingBuff);
                      byte[] buff = new byte[incomingBytes];
                      System.arraycopy(incomingBuff, 0, buff, 0, incomingBytes);
                      String s = new String(buff, StandardCharsets.UTF_8);
                      // Show Result to UI
                      handler.obtainMessage(Constants.MESSAGE_TEMP, s).sendToTarget();
                      // Update again in a few seconds
                      Thread.sleep(3000);
                  }
                }
                catch(IOException e)
                {
                  // connect will throw IOException immediately
                  // when it's disconnected.
                  Log.d(TAG, e.getMessage());
                }
                handler.obtainMessage(Constants.MESSAGE_BT, "DISCONNECTED").sendToTarget();
                // Re-try after 3 sec
                Thread.sleep(3 * 1000);
            }
          }
          catch(InterruptedException e)
          {
            e.printStackTrace();
          }
          catch(IOException e)
          {
            e.printStackTrace();
          }
          if(bluetoothSocket != null)
          {
            try
            {
                bluetoothSocket.close();
            }
            catch(IOException e)
            {
            }
            bluetoothSocket = null;
          }
          handler.obtainMessage(Constants.MESSAGE_BT, "DISCONNECTED - Exit BTClientThread").sendToTarget();
      }
    }
}
</syntaxhighlight>
<br>
<syntaxhighlight lang="java">
// Constants.java
package com.keicode.android.testapps.bttest1c;
import java.util.UUID;
public interface Constants
{
    public static final String BT_DEVICE = "MYBT";
    public static final UUID BT_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
    public static final String STATE_TEMP = "STATE_TEMP";
    public static final int MESSAGE_BT = 0;
    public static final int MESSAGE_TEMP = 2;
}
</syntaxhighlight>
<br>
次に、環境設定を行う。<br>
ここでは、デバイス名はMYBTとしているが、これをあらかじめペアリングする。<br>
以上の変更を行い、Arduinoとスマートフォンの両方を起動することで自動的にBluetooth接続して、スマートフォンの画面に温度が表示される。<br>
[[ファイル:Arduino Bluetooth 3.jpg|フレームなし|中央]]
<br><br>
<br><br>
   
   
__FORCETOC__
__FORCETOC__
[[カテゴリ:Arduino]]
[[カテゴリ:Arduino]]