P_20151023_193727_LL
簡単にBLEを使えるモジュールとしてmbed HRM1017やBlendMicroがありますが、値段がお高いので躊躇してしまいます。microchipのRN4020はマイコンが付かない代わりに値段が8ドル程度とお安くなっています。低価格の8ビットマイコン等と組み合わせれば千数百円で同等の機能が実現できてしまいます。今回は手元にあったmbedと繋いでiPhoneとのBLE通信をテストしてみました。

RN4020は側面に端子が出ていますので細いワイヤーなら直にはんだ付けできます。結線は、
 RN4020 – mbed
・vcc——3.3V
・gnd——gnd
・rx——-tx(p28)
・tx——-rx(p27)
・wake_hw–p5
・cmd/mldp-p6
・wake_sw–p7
・rts
  |
 cts (追記)
となります。wake_hw, cmd/mldpはGND、wale_swはVCCでも可です。

Service UUIDとCharacteristic UUID(2個)を用意します。Characteristic UUIDはRead/Notify用とWrite用です。
Readは、モジュール側でCharacteristicにwriteしたものをiPhoneがReadしに来ます。Notifyはモジュール側でCharacteristicにwriteしそれをiPhoneにNotifyします。WriteはiPhoneがモジュールのCharacteristicにwriteしてそれをモジュール側で読み出します。ReadとWriteの主語はiPhoneで、Notifyの主語はモジュールです。

はじめにマイコンからモジュールにコマンドを送って設定を行ないます。
“S-,RN4020\r” //名前を設定
“SR,20006000\r” //フィーチャー設定 Auto Advertise & iOS Mode & Server Only
“SS,80000001\r” //サービス設定 Device Information & User Defined Private Service
“ST,0010,0002,0064\r” //コネクションパラメータ iOS用の設定
“PZ\r” //Private Serviceの設定をクリア
“PS, suuid\r” //Private ServiceのUUIDを設定
“PC, cuuid0,12,01\r” //Private CharacteristicのUUIDを設定 Read/Notify
“PC, cuuid1,08,01\r” //Private CharacteristicのUUIDを設定 Write
“R,1\r” //Reboot

データの読み出しはiPhoneからWrite用のCharacteristicに書き込まれたものをread_characteristic関数内で”SUR,cuuid1\r”を使って読み出します。16進数の文字列で来るので1byteのデータでも2回読み出します。サンプルコードでは受け取ったデータの下4桁をLEDに表示しています。

iPhoneに送るデータはwrite_characteristic関数内で”SUW,cuuid0,data\r”を使って書き込みます。この場合もデータは2桁の16進文字列に変換します。PCコマンドでNotifyを設定しているので自動的にiPhone側に通知されます。1秒ごとの割り込みで0〜255のデータをwriteしています。

iPhone側はLightBlueというアプリで確認できます。

#include "mbed.h"
#include "string"

DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);

Serial rn(p28, p27);
DigitalOut wakeHw(p5);
DigitalOut cmdMldp(p6);
DigitalOut wakeSw(p7);

Ticker flipper;

char suuid[] = "8d8987059e3b42a59637456f786cad8a";
char cuuid0[] = "4b753e33faac44ed81a6dece7bb01283";
char cuuid1[] = "0add21c0de8b406391218f657b1c67a4";

char num = 0;
char tick = 0;

char wait_response(char* value) {
    char s[128];
    while(!rn.readable()){};
    if(strcmp(rn.gets(s,3), value))return 1;
    else return 0;
}

void send_cmd(string cmd) {
    rn.printf(cmd.c_str()); 
}

char write_characteristic(string uuid, string data) {
    string str;
    str = "SUW,";
    str += uuid;
    str += ",";
    str += data;
    str += "\r";
    send_cmd(str);
    return wait_response("AOK");
}

char read_characteristic(string uuid) {
    char s[2];
    string str;
    str = "SUR,";
    str += uuid;
    str += "\r";
    send_cmd(str);
    while(!rn.readable()){};
    s[0] = rn.getc();
    if(s[0]>'9')s[0]=s[0]-'a'+10;
    else s[0]=s[0]-'0';
    s[1] = rn.getc();
    if(s[1]>'9')s[1]=s[1]-'a'+10;
    else s[1]=s[1]-'0';
    return s[0]*16+s[1];
}

void setup_ble() {
    string str;
    wakeHw = 0;
    cmdMldp = 0;
    wakeSw = 1;
    
    send_cmd("S-,RN4020\r");
    wait_response(" ");
    send_cmd("SR,20006000\r");
    wait_response(" ");
    send_cmd("SS,80000001\r");
    wait_response(" ");
    send_cmd("ST,0010,0002,0064\r");    //for iOS
    wait_response(" ");
    send_cmd("PZ\r");
    wait_response(" ");
    str = "PS,";
    str += suuid;
    str += "\r";
    send_cmd(str);
    wait_response(" ");
    str = "PC,";
    str += cuuid0;
    str += ",12,01\r";
    send_cmd(str);
    wait_response(" ");
    str = "PC,";
    str += cuuid1;
    str += ",08,01\r";
    send_cmd(str);
    wait_response(" ");
    send_cmd("R,1\r");
    while(!wait_response("CMD")){}
}

void flip() {
    tick = 1;
}

int main() {
    
    myled1=myled2=myled3=myled4=0;
    rn.baud(115200);
    rn.format(8, Serial::None, 1);
    
    setup_ble();
    
    flipper.attach(&flip, 1.0); 
    
    while(1) {
        //read characteristicの動作確認
        char c[2] = {0,0};
        char cc;
        cc=read_characteristic(cuuid1);
        //characteristicから読んだ値(下の位)をLEDで表示
        if(cc & 0x08)myled1=1;
        else myled1=0;
        if(cc & 0x04)myled2=1;
        else myled2=0;
        if(cc & 0x02)myled3=1;
        else myled3=0;
        if(cc & 0x01)myled4=1;
        else myled4=0;
        
        if(tick){
            //write characteristicの動作確認 1秒ごとに数値を書き込む
            num++;
            if(num > 255)num = 0;
            sprintf(c, "%02X", num);
            write_characteristic(cuuid0, string(c));
            tick = 0;
        }
    }
}