SSブログ

BLE Beacon を探そう [PSoC]このエントリーを含むはてなブックマーク#

BLEセンサ5個セット

PSoC Advent Calendar 2016の5日目の記事です。

3日目の記事で作成した BLE Beacon は Advertisement パケットを発信します。 発信されたパケットは、 Central または Observer 役のデバイスが「スキャン」することによって受信します。 今回の記事では、 CYALKIT-E03 Solar-Powered BLE Sensor 5 Pack から発信された BLE Beacon パケットを受信する Observer 役のアプリケーションを作成します。

使用するハードウェア

BLE開発キット

この記事では、上記のセンサキットに加えて、 CY8CKIT-042-BLE Bluetooth® Low Energy (BLE) Pioneer Kit も使用します。 CY8CKIT-042-BLE のベースボードにドータボード CY8CKIT-142: PSoC 4 BLE Module を搭載し、受信したパケットの情報を UART で出力し、 KitProg の仮想シリアルを通じて PC で観測します。

回路図

回路図

必要なコンポーネントは、 BLE と UART だけです。 あとは、ファームウェアで BLE を制御し、取得した情報を UART で表示させます。

クロック設定

高速クロックの設定

CY8CKIT-142 モジュールには、 24MHz と 32.768kHz の二つの水晶が搭載されています。 このアプリケーションでは、高速クロックとして、 24MHz 水晶で作ったクロックをそのまま使用します。 内蔵クロックの IMO は使用しないので、止めてしまっています。


低速クロックの設定

低速クロックも外部水晶で作ったクロックを使用します。 内蔵クロックの ILO は止めています。 このアプリケーションでは、低速タイマは使用していません。

BLE コンポーネントの設定

Generalタブ

先に述べたように、 BLE コンポーネントは、 "Observer" 役として作成します。 General タブで、 "Broadcaster/Observer" を選択し、さらに "Observer" を選択します。 これで、 "Observer" 役のデバイスを作成できるようになります。

この時に「GAP Settings の内容を削除しても良いか」というダイアログが現れますが、このプロジェクトでは必要ありませんので削除されても大丈夫です。


GAP Settings - General

次は、 "GAP Settings" タブの "General" ノードを設定します。 ここでは、 "Device name" を設定できますが、 "Observer" 役は電波を受信するだけで送信する事がありません。 したがって、ここに何らかの名前を入れても使われる事がありません。 使われないとはわかっていますが、 "Observer" と入れてみました。


GAP Settings - Scan settings

"Scan settings" ノードでは、 Advertisement パケットの「スキャン」を行う際の設定を行います。

"Scanning state" は "Active" として、常にスキャンを行わせます。 また、 "Filter policy" は、 "All" として、すべての Advertisement パケットを受信できるようにします。 受信したパケットを使うか否かは、ファームウェアで判断します。

"Fast scan parameters" で "Scan timeout" のチェックをはずすと、永遠に "Fast scan" が実行されるようになります。 この時、どのようなタイミングで受信機を動作させるかを表すのが "Scan window" と "Scan interval" です。 これらの時間を調整する事で、スキャンのタイミングを制御する事ができます。


Advancedタブ

"Advanced" タブでは、 "Use BLE low power mode" のチェックを外します。 ここで作成するアプリケーションでは消費電力など考えず、動き続ける事を目的としているので、 "low power mode" に入らないようにしておきます。

以上で、 BLE コンポーネントの設定は終わりです。

UART コンポーネントの設定

UART Basicタブ

UART コンポーネントの "UART Basic" タブでは、通信に使われるフォーマットを指定します。 ボーレートには、最近よく使われる 115200bps を使用しています。

このダイアログでは、 "Oversampling" の項目も変更しています。 "Oversampling" は、デフォルトでは 12 に設定されているのですが、 12 のままだと実際のボーレートが 117647bps (+1.2%) となってしまい、 UART で通信するには誤差が大きくなってしまいます。

そこで、 "Oversampling" を 16 に設定しました。 これにより、ボーレートは 115385bps (+0.2%) となっています。


UART Advancedタブ

"UART Advanced" タブでは、バッファのサイズと割り込みの使用方法を設定します。 まず、 "TX buffer size" を 64 に設定します。 これは、受信したパケットの情報を表示する間も BLE の通信を継続させるためです。 これにより、長いメッセージを表示させる場合でも、 UART の通信を待つことがなくなります。 一方、 "RX buffer size" は、デフォルトの 8 のままにしておきます。

"TX buffer size" を設定する事で、割り込みのモードが "None" から "Internal" に変わります。 これは、バッファの処理に内部で定義した割り込み処理ルーチンを使うためです。 アプリケーションでは、割り込みを使いませんので、 "Interrupt sources" のすべてのチェックをはずしておきます。

端子の設定

端子の設定

割り当てを設定しなくてはならない端子は、 UART の RX/TX だけです。 それぞれ P1[4]/P1[5] に割り当てます。 これらの端子は、 CY8CKIT-042-BLE キットに搭載された KitProg の UART 信号に接続されています。 これで、 KitProg の仮想シリアルを使って通信を行う事ができます。

ファームウェア

ファームウェア

ユーザのファームウェアは、いつものように main.c にまとめられています。

#include <project.h>
#include <stdio.h>

// Beaconのパケット構造体
struct BeaconPacket {
    uint8   length1;            // 02
    uint8   adType1;            // 01
    uint8   adData1;            // 04
    uint8   length2;            // 1A
    uint8   adType2;            // FF
    uint8   companyId[2];       // 4C 00
    uint8   deviceType;         // 02
    uint8   length3;            // 15
    uint8   uuid[16];           // 00 05 00 01 00 00 10 00 80 00 00 80 5F 9B 01 31
    uint8   major[2];           // 00 xx
    uint8   minor[2];           // xx xx
    uint8   rssi;               // xx
};

最初に Beacon パケットの構造体を宣言しています。 このアプリケーションでは、この構造体のフォーマットにそったパケットのみを取り扱います。 これ以外の長さやフォーマットのパケットは無視されます。 パケットの詳細は、 CYALKIT-E02 Solar-Powered BLE Sensor Beacon Reference Design Kit (RDK) の関連文書を参照してください。

// Advertisementパケットの情報を格納する変数
CYBLE_GAPC_ADV_REPORT_T advReport;
                
// 受信したパケットを格納する変数
struct BeaconPacket     beaconPacket;

Advertisement パケットを受信した時、パケットの中身以外にパケットの送信元などの情報が引き渡されます。 ここでは、その情報を受け取るための変数として advReport を宣言しています。 さらに、 beaconPacket として、パケットの中身を受け取る変数も宣言しています。

// 探すべきUUID
const uint8 targetUuid[16] = {
    0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00,
    0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x01, 0x31
};

// 探すべきID(major)
uint8   id = 0;             // 着目するID

受信したパケットが、目的の Beacon から送られてきたものか否かを判断するために、 UUID と ID を確認します。 ここで宣言された targetUuid と受信したパケットの uuid とが比較されます。 一方の ID は、8ビットの変数になっています。 このアプリケーションでは、 ID を0から255までの値に限定しており、 UART から指定する事ができます。

// Reportの中身を格納する変数群
volatile CYBIT  reportUpdated = 0;  // Report更新フラグ
uint8           temp;               // 温度データ
uint8           humid;              // 湿度データ
int8            rssi;               // RSSIデータ

パケットを受信したら、そこから必要な情報を取り出して、これらの変数に格納しておきます。 そして reportUpdated フラグをセットして、変数が更新されたことをメインループに通知します。

// BLEのイベントを処理するハンドラ
void StackEventHandler(uint32 event, void *eventParam) {
    switch (event) {
        //======================================================
        //  必須イベント
        //======================================================
        case CYBLE_EVT_STACK_ON:
            // BLEスタックが構築された
    		// 高速なBLEスキャンを開始する。スキャンは止まらない。
    		CyBle_GapcStartScan(CYBLE_SCANNING_FAST);
            break;

BLE のスタックからイベントを受け取り、処理を行うハンドラです。 BLE スタックが構築されたら、イベント CYBLE_EVT_STACK_ON が発行されます。 ここでは、 Advertisement パケットを受信する「スキャン」動作を開始します。 このアプリケーションでは、一度始めた「スキャン」は、止めません。 電源の続く限り、「スキャン」を行い、 Advertisement パケットを探し続けます。

        //======================================================
        //  GAPイベント
        //======================================================
        case CYBLE_EVT_GAPC_SCAN_START_STOP:
            // BLEスキャンが開始・停止された
            // 何もしない
            break;

GAP 関連のイベント CYBLE_EVT_GAPC_SCAN_START_STOP は、「スキャン」動作が開始または停止された時に発行されます。 このアプリケーションでも、「スキャン」が開始された時にこのイベントが発行されますが、特に何も行いません。

        case CYBLE_EVT_GAPC_SCAN_PROGRESS_RESULT:
            // BLEスキャンがデバイスを見つけた
            {
                // Reportデータをコピーする
                advReport = *(CYBLE_GAPC_ADV_REPORT_T *)eventParam;
                
                // Reportパケットの長さが期待される長さであるか確認する
                if (advReport.dataLen == sizeof beaconPacket) {
                    // Reportパケットをバッファにコピーする
                    memcpy(&beaconPacket, advReport.data, advReport.dataLen);
                    
                    // 見つけたBeaconが着目しているBeaconか確認する
                    // UUIDフィールドとMAJORフィールドだけを検証する
                    if (
                        (memcmp(beaconPacket.uuid, targetUuid, sizeof targetUuid) == 0)
                        && (beaconPacket.major[0] == 0x00)
                        && (beaconPacket.major[1] == id)
                    ) {
                        // 取り出したい情報をコピーする
                        rssi = advReport.rssi;
                        humid = beaconPacket.minor[0];
                        temp = beaconPacket.minor[1];
                        // Report更新フラグをセットする
                        reportUpdated = 1;
                    }
                }
            }
            break;

Advertisement パケットを受信した時に発行されるのが、イベント CYBLE_EVT_GAPC_SCAN_PROGRESS_RESULT です。 受信したパケットに関する情報は、ハンドラの引数 eventParam で渡されます。 着目している Beacon から発信されたパケットである事を確認したら、必要な情報を変数にコピーして、更新フラグをセットします。

        //======================================================
        //  汎用イベント
        //======================================================
        case CYBLE_EVT_TIMEOUT:
            // 時間切れイベント
            // 何もしない
            break;
            
        //======================================================
        //  処理されないイベント
        //======================================================
        default:
            // その他のイベントは単に無視する
            break;
    }       
}

その他のイベントが発行される事もありますが、処理せずにハンドラを終えます。 イベントの処理は、これだけです。

int main(void) {
    // 割り込みを許可する
    CyGlobalIntEnable;

    // UARTを起動する
    UART_Start();
        
    // BLEを起動する
    {
        CYBLE_API_RESULT_T apiResult;
        apiResult = CyBle_Start(StackEventHandler);
        // BLEスタックの初期化が成功したか確認する
        CYASSERT(apiResult == CYBLE_ERROR_OK);
    }
    
    // 初期メッセージを表示する
    UART_UartPutString("Beacon Observer\r\n");

main() 関数の冒頭では、割り込みを許可し、 UART コンポーネントと BLE コンポーネントの初期化を行います。 次に、最初のメッセージを UART に出力します。

    for(;;) {
        // BLEスタックのイベントを処理する
        CyBle_ProcessEvents();
        
        // Reportパケットが到着したか確認する
        if (reportUpdated) {
            char buffer[64];    // UART出力のバッファ
            int16 t, h;         // 温度と湿度を格納する変数
            // 更新フラグをクリアする
            reportUpdated = 0;
            // 温度と湿度を1/10単位の整数で計算する
            t = ((17572L * temp) / 256 - 4685 + 5) / 10;
            h = ((12500L * humid) / 256 - 600 + 5) / 10;
            // Reportパケットの内容を表示する
            sprintf(buffer, "ID=%d TEMP=%d.%d HUMID=%d.%d RSSI=%d\r\n",
                id, t/10, t%10, h/10, h%10, rssi);
            UART_UartPutString(buffer);            
        }

メインループの前半では、 BLE スタックに関連した処理を行い、着目した Advertisement パケットが見つかった場合は、 UART への出力処理を行います。 Beacon から届いたパケットには、温度と湿度の情報がセンサから取り出したままのデータが含まれています。 このまま表示されても人間には理解できませんので、センサの仕様にしたがって摂氏温度とパーセント湿度を計算して表示しています。

出力には、 RSSI という電波強度を示す数値も表示されます。

        // 着目するBeaconのIDを変更する
        {
            uint32 ch = UART_UartGetChar();
            if (ch) {
                // UARTから有効な文字を検出した
                char buffer[64];
                // IDを計算して格納する
                // 0..9 が有効 その他の文字も使おうと思えば使える
                id = ch - '0';
                // 新しいIDを表示する
                sprintf(buffer, "SET ID=%d\r\n", id);
                UART_UartPutString(buffer);
            }
        }
    }
}

UART の入力を使って、着目するセンサの ID が変更できるようになっています。 ID を計算するために、単純に文字コードから '0' ($30) を減じています。 このため、 '1' を入れると ID=1 に設定され、 'A' を入れると ID=17 に設定されます。 ID が設定されたら、設定後の ID が表示されます。

実行結果

実行結果

実行すると、仮想シリアルにこのようなレポートが上がってきます。 この例では、1から6まで UART から文字を送り、それぞれのセンサの値を取得しています。

プロジェクトアーカイブ

この記事で作成したプロジェクトは、このファイルの拡張子を "zip" に変更すると再現できます。

参考サイト

CY8CKIT-042-BLE Bluetooth® Low Energy (BLE) Pioneer Kit
この記事で使用した開発キットです。 BLE 関連アプリケーションの作成が可能です。
CY8CKIT-142: PSoC 4 BLE Module
上記のキットに含まれているドータボードです。 今回は、 PSoC 4 BLE を使ってアプリケーションを作成していますが、 PRoC BLEEZ-BLE モジュールでも使用できます。
CYALKIT-E02 Solar-Powered BLE Sensor Beacon Reference Design Kit (RDK)
Wireless Sensor Node (WSN) の実験に使用できるリファレンスキットです。 このキットには、センサーノードがひとつ入っています。 このノードには、 ID=1 が付いています。
CYALKIT-E03 Solar-Powered BLE Sensor 5 Pack
上記キットのセンサーノードだけを5個パックにしたキットです。 ID=2 から ID=6 までが、あらかじめ割り当てられています。

参考商品

PSoC 4 BLE

PSoC 4 BLE

  • 出版社/メーカー: スイッチサイエンス
  • メディア: エレクトロニクス

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。