<概要>
ここではPICマイコンをBLESerial経由でAndroid端末につないでみます。
Androidの場合、BLEに対応していないものがたくさんありますので、pm
list featuresを確認してください。
<注意>
ここでご紹介するプログラムはあくまでもサンプルプログラムとなります。個別のご質問などにはお答えできませんのでご了承下さい。
機種やOSのバージョン違いや環境の違いなどにより動作しない可能性もあります。また、今後のOSバージョンアップなどに対しての動作も定かではありません。
紹介動画
<BLE対応しているかの確認方法(Android端末の場合)>
ADB接続時にコンソールから adb shell pm list
features を実行してください。
featureの中に、android.hardware.bluetooth_le
があれば動作します。最後に「_le]が付いたbluetoothが無いと動きません。
<ブロック図>
PICマイコンボード(浅草ギ研製PIColo)からは一定周期でセンサー読み取り値(8bit値)が送信されつづけます。マイコンボードが0x01を受信するとLEDを点灯、0x00で消灯します。
<接続図>
PIC側接続詳細
■電源部
Picolo(PIC16F1936マイコンボード)は1.8〜5.5Vで動きます。
BLESerialは5V動作ですが、内部は3.3Vで動作しており、ドロップアウト電圧が1Vの3.3Vレギュレータが搭載されています。つまり、4.3V以上あれば動作させることができます。
よって、ここでは単三乾電池x3個で4.5Vをつくり、動作させています。
■LED
LEDはアノードをRB7端子、カソードを電流制限抵抗経由でGNDにつないでいますので、RB7をHiにするとLEDが点灯し、Loにすると消灯します。
■センサー
今回はセンサーダミーとしてスライドボリュームをつけてみました。電圧変化型のセンサーなら同じように値を読み取ることができます。
<PIC側プログラム説明>
開発環境はMPLABv8.90、コンパイラはHI-TECH Cを使用しました。どちらも無償で入手できます。PIC側のプロジェクト全体を圧縮したものはこちら。
WiMaster_test4.zip
送信、受信、両方のデモを行うため、センサー値を送信し、受信した値によりLEDを点灯させるプログラムを作りました。
■初期設定
初期設定部分は次のようになります。
//////////////////////////////////////
// define
// //////////////////////////////////////
#define LED PORTBbits.RB7
#define ON 1
#define OFF 0
//////////////////////////////////////
// initial setting //
//////////////////////////////////////
void init_IO(){
//clock
OSCCON = 0b11110000; //32MHz(4xPLL=enable FOSC=8MHz OSCSetting=CONFIGbit)
//IO
ANSELA = 0b00000000; //1:Analog, 0:Digital
ANSELB = 0b00100000; //1:Analog, 0:Digital *RB5 is analog
TRISB = 0b01111111; //0:output 1:input *TB7 is outout
//UART
SPBRG = 51; //9600bps (FOSC=8MHz (without PLLx4))
TXEN = 1;
SYNC = 0;
SPEN = 1;
CREN=1;
RCIE=1; //RC intrrupt enable
//ADC setting
ADCON0 = 0b00110101; //AN13 select, DONE=0, ADON=1
ADCON1 = 0b00100000; //Left, FOSC/2, VREF-=VSS, VREF+=AVDD
//Intrrupt
PEIE=1;
GIE=1;
}
内部8MHz駆動で、UARTは9600bps、LED用にRB7をデジタル出力へ設定、センサー用にRB5(AN13)をanalog入力ポートに設定しています。
受信は割り込みで受けるので、割り込みも有効に設定しています。
■データ受信
//////////////////////////////////////
// interrupt //
//////////////////////////////////////
static void interrupt
isr(void){
//受信割り込み
if(RCIF == 1){
unsigned char getData;
RCIF = 0;
getData = RCREG;
//LED判定
if(getData==0x01){
LED=ON;
}else if(getData==0x00){
LED=OFF;
}
}
}
受信は割り込みで受けて、0x01ならLEDをON、0x00ならオフしています。HI-TECH Cの場合、割り込み後にどのフラグが立ったかで何の割り込みかを判定しています。UARTの受信割り込み発生時にはRCIFフラグがたちます。このフラグはRCIF
= 0;のようにプログラムでリセットする必要があります。
■メイン(一定周期でセンサーデータを読んで送信)
//////////////////////////////////////
// main //
//////////////////////////////////////
void main(){
//初期設定
init_IO();
//300mSごとにセンサーデータを送る。受信は割り込みで処理。
while(1){
TXREG=readADC();
wait_ms(100);
}
}
readADC( )はADCで読んだ値を返す関数です。 wait_ms( )は引数mS間ウェイトする関数です。中身はソースを参照願います。TXREGに値をセットすると自動で送信されます。
メインループでは一定周期でセンサーデータを送っているだけです。受信は先の割り込みルーチンで処理されます。
<Android側プログラム説明>
Eclipse上で作成したAndroidのJavaアプリを圧縮したものがこちらになります。
BLESerial_test_Android.zip
本記事を執筆時点で、Androidが正式にBLEに対応してからまだ3ヶ月しか経過しておりませんので、Android側に若干バグが存在します。よって今回のプログラムはそれらを回避したプログラムになっていますので、一般的なBLEのプログラムとは段取りが若干異なります。ご注意下さい。
特に、普通はサービスUUIDを指定して接続するのですが、ライブラリのサービスIDを指定しての接続が現在版では動作しないので、このサンプルプログラムではSSID(BLESerialという名称)からMACアドレスを取得し、アドレス指定で接続を行っています(ので段取りがやや増えている)。
画面イメージ
起動すると3秒間スキャンをします。右上の「スキャンする」を押しても3秒間スキャンします。
アドバタイズメントしているBLE装置を見つけると、画面にリスト表示します。リストをクリックすると次の画面になり、接続します。
LED_ONボタンを押すと、BLESerialを経由してArduinoに0x01が送られ、ArduinoのLEDが点灯します。LED_OFFボタンで0x00が送られ、LEDは消えます。
Arduinoからは常にセンサー(スライドボリューム)の値が送られ続けます。この値は「センサー値」の下に表示されます。
画面レイアウトはXMLで記述しています。詳細はソースを参照願います。
AndroidのBLE対応は4.3以降になりますので、プロジェクトを作るときはターゲットバージョンを4.3以上にします。
■プロジェクトの構成
プロジェクトには3つのファイルがあり、
BLEScanActivity : 初めに開く画面。スキャンを行い、リスト表示する。
SerialComActivity : スキャン画面からリストを押したときに開く画面。Arduinoと通信してLED操作やセンサー値表示
BluetoothLeService : BLESerialとの通信を制御するサービス。バックグランドで動作。
となっています。
また、Bluetooth及びBLEを使用するので、Manifestにパーミッション設定を行います。
■ID
BLEには「サービス」と「キャラクタリスティック」という概念があります。それぞれには固有のIDがつけられます。Bluetoothの団体で決められたIDもありますが、128bit値の個別IDを使うこともできます。
BLESerialはバーチャルシリアルポート(VSP)というオリジナルサービスが搭載されています。
受信(Androidから見て受信:Android<-BLESerial)と、送信(Androidから見て送信:Android->BLESerial)の2つのキャラクタリスティックを持ち、各IDは次の通りとなります。(BluetoothLeService.java内に記述)
//BLESerial サービスUUID
public static String UUID_BLESERIAL_SERVICE = "569a1101-b87F-490c-92cb-11ba5ea5167c";
// BLESerial 受信UUID (Notify)
public static String UUID_BLESERIAL_RX = "569a2000-b87F-490c-92cb-11ba5ea5167c";
// BLESerial 送信UUID (write without response)
public static String UUID_BLESERIAL_TX = "569a2001-b87F-490c-92cb-11ba5ea5167c";
キャラクタリスティックの設定を行うUUIDは固定値で次のようになっています。
// キャラクタリスティック設定UUID
public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
1パケット20バイトまで送受信可能です。フロー制御をしていない場合は、連続で20バイト超過をやりとりするとデータ漏れが発生する場合がありますので注意してください。
■起動〜スキャン
Arduinoの電源を入れると、接続されたBLESerialにも電源が供給され、アドバタイズメント状態に正常に移行できた後にBLESerial上の赤LEDが点灯します。
Androidアプリ(本サンプルアプリ)を起動すると、BLEScanActivityが起動し、onCreate時にまずAndroid端末がBLEに対応しているかをチェックします。また、BluetoothAdapterのインスタンスmBluetoothAdapterを生成しています。基本的にはこのアダプタを通じて設定などを行います。詳細はソースを参照願います。
次にonResume(画面が出るときに実行)が動作し、スキャンを開始します。
スキャンを行うメソッドの部分です。
行158〜165は、指定した時間(ここでは3秒)後にスキャンを停止する記述です。ここが最後に実行されることになります。
スキャンを開始するのは行175の BluetoothAdapter#startLeScanメソッドになります。
startLeScanメソッドは、AndroidDeveloperの説明によると、サービスUUIDを指定して、そのサービスを持っているデバイスのみをスキャンする、ということができる、と書いてありますが、コメントにもあるとおり、2013年11月現在ではバグがあり動きません。よって、ここではデバイス名とMACアドレス、電場強度をとりあえず保持し、後でMACアドレス指定で接続することにしています。
(ちなみに、8月の4.3の発表から何度かビルドが更新されていますが、新しいビルドでもまだこのバグは解消されていないようです。)
スキャン中にデバイス(相手側のBLE装置:ここではBLESerial)が発見されたらBluetoothAdapter.LeScanCallbackが発生しますので、発見したデバイス情報を保持(ここではリストアダプタに追加。自動的に画面にもリストが追加される。)します。下がそのコールバック部になります。
■接続、受信
スキャン画面でリストをクリックすると、そのデバイス情報を付加したインテントでSerialComActivityが起動されます。起動部分はつぎのような感じです。
引継ぎしたデバイス名が mDeviceName に、アドレスが
mDeviceAddress に引継ぎされています。
接続は画面が表示されるタイミング(onResume時)に行っています。
BluetoothLeService#connect(行74)で接続します。このとき、アドレスを指定すると、そのアドレスのBLE機器に接続を試みます。
接続後のイベントは、AndroidOSよりブロードキャストされますので、ブロードキャストレシーバで受け取ります。
Arduinoからは常にセンサーデータが送信されていますので、接続後すぐに受信イベントが発生しつづけます。行147のACTION_DATA_AVAILABLEは受信済みデータがあることを知らせるイベント、つまり受信イベントです。受け取ったインテントからデータを抽出して画面に結果表示をさせています。
■送信
画面上の各ボタンを押すと裏で動いているBluetoothLeService(3個目のファイルで書いているクラス)のsendDataメソッドを使ってデータを送信します。
接続や通信に関しては裏で動かしているBluetoothLeServiceが制御しています。
BLEにはいろいろな通信プロトコルがありますが、BLESerialはGATTを使っています。Android4.3からはBluetoothGattクラスが追加され、これを使ってサービスやキャラクタリスティックの管理ができるようになっています。
BluetoothLeServiceの部分を詳細説明しようとするとBLEについての説明からする必要があり、大変長くなりますので説明を割愛しますが、ネット上のBLEの情報を見ながらソースを読んでみてください。
iPhoneでも同じように、同じハードウェアを動かすことができます。BLESerialのページのサンプルプログラムの節、他のデバイスでの例を掲載しています。
以上
|