アクセスカウンタ

プロフィール

ブログ名
迷える子羊の苦悩
ブログ紹介
1日が早いので、何もできない・・・
zoom RSS

BLE + 温湿度・気圧センサー + 照度センサー

2016/07/30 12:24
CY8CKIT-042-BLE に 前回も使用した温湿度と気圧が測れる BME280 と
照度センサー TSL2561 を繋げて、
環境センサーを作成しました。

PSoC Creatorには、多くのサンプルプログラムがあり、
これをベースにして簡単に作成できるようです

環境センサーについても、Environmental sensingというサンプルコードがあります。

このサンプルコードを参考にして、修正していきました。

TopDesignは、こんな感じに。
画像

I2Cを追加して、BME280を追記しています。BME280のブロックは、
TopDesignに書いても書かなくても関係ないです
照度のTSL2561は実際には接続していますが、TopDesignには書いてません。

サンプルではLED三色使用していますが、後で何かに使うかもしれないので、
1個に減らしました

ピン配は、I2Cをどこでもいいみたいですが一応並べて配置。
画像
アナログピンの場合は少し制限があるみたいです。
LED、SW、Debug用UARTは下のボードとの
兼ね合いで決まってますので、変更できないでしょう

BLEのプロファイルは、
画像
のようにDescriptorを3つだけにしました。

プログラムの構成を大幅に変更しました。
画像


main関数の最初は、コールバックの設定と各種初期化です。
1:CyGlobalIntEnable;
2:
3:/* Start CYBLE component and register generic event handler */
4:CyBle_Start(BLE_Component_CallBack);
5:
6:/* Configure button interrupt */
7:Wakeup_Interrupt_StartEx(&ButtonPressInt);
8:
9:#if (DEBUG_UART_ENABLED == ENABLED)
10:UART_DEB_Start();
11:#endif /* (DEBUG_UART_ENABLED == ENABLED) */
12:
13:I2C_1_scl_SetDriveMode(I2C_1_scl_DM_RES_UP);
14:I2C_1_sda_SetDriveMode(I2C_1_sda_DM_RES_UP);
15:I2C_1_Start();
16:
17:BME280_Init();
18:TSL2561_Init();
19:DBG_PRINTF("TSL2561_ReadId()=%02x\r\n", TSL2561_ReadId());
20:
21:ESS_Init();
22:
23:/* Global Resources initialization */
24:WDT_Start();
25:BLE_InitStateLeds();

I2Cは、内部ブルアップ抵抗を使用して、部品点数削減です。
データシートには、内部抵抗じゃない方がいいよってありますが
100kbpsなら問題ないようです。

main関数のループ部分は、
1:while(1)
2:{
3: /* CyBle_ProcessEvents() allows BLE stack to process pending events */
4: CyBle_ProcessEvents();
5:
6: /* To achieve low power in the device */
7: BLE_LowPowerImplementation();
8:
9: /* Handle advertising LED blinking */
10: BLE_HandleStateLeds();
11:
12: /* */
13: BME280_Handle();
14: TSL2561_Handle();
15:
16: state = CyBle_GetState();
17: if (state == CYBLE_STATE_CONNECTED)
18: {
19: /* */
20: ESS_Handle();
21: }
22:
23: /* button */
24: if (isButtonPressed == YES)
25: {
26: isButtonPressed = NO;
27: DBG_PRINTF("Pressed button\r\n");
28: }
29:
30: /* Store bonding data to flash only when all debug information has been sent */
31: #if (DEBUG_UART_ENABLED == ENABLED)
32: if((cyBle_pendingFlashWrite != 0u) &&
33: ((UART_DEB_SpiUartGetTxBufferSize() + UART_DEB_GET_TX_FIFO_SR_VALID) == 0u))
34: #else
35: if(cyBle_pendingFlashWrite != 0u)
36: #endif /* (DEBUG_UART_ENABLED == ENABLED) */
37: {
38: uint8 apiResult = CyBle_StoreBondingData(0u);
39: DBG_PRINTF("Store bonding data, status: %x \r\n", apiResult);
40: }
41:}
CyBle_ProcessEvents関数が、BLEのイベントを処理してくれる
(たぶん、Callbackしてくれる?)関数なので、これ必須。
BLE_LowPowerImplementationは、必要ない時にLowPowerになってくれるようです
サンプルコードそのままです
あとは、なんちゃらHandle関数で、自分の好きな処理をしています。
この中では、WDTの時間を使って、周期的に処理をしています。

WDTと聞くと、ハングアップしたときにリセット入れるためのものと思いましたが、
どうやら、動作モードが何種類かあるらしく、
単なるタイマーとして使用することができるようです。
通常のタイマーとの違いは、ソースのクロックということになるでしょう。
WDTなら低周波数なので、低消費電力になると思います

BME280のソースコードは、ESP8266で作成したものをほぼ流用しています。
I2Cアクセス部分のみ異なります。
レジスタの書き込み関数は、割り込みベースの書き方で
1:static bool BME280i_WriteRegister(uint8 addr, uint8 data)
2:{
3: bool ret = false;
4: uint32 sts;
5: uint8 buff[2] = {addr, data};
6:
7: sts = I2C_1_I2CMasterWriteBuf((uint32)BME280_SLAVE_ADDR, buff, 2, I2C_1_I2C_MODE_COMPLETE_XFER);
8: if (sts != I2C_1_I2C_MSTR_NO_ERROR)
9: {
10: DBG_PRINTF("BME280:W:Write error:0x%lx\r\n", sts);
11: return ret;
12: }
13:
14: /* Waits until master completes write transfer */
15: while ((I2C_1_I2CMasterStatus() & I2C_1_I2C_MSTAT_WR_CMPLT) == 0) continue;
16:
17: /* Displays transfer status */
18: if (I2C_1_I2CMasterStatus() & I2C_1_I2C_MSTAT_ERR_XFER)
19: {
20: DBG_PRINTF("BME280:W:Status err\r\n");
21: }
22: else
23: {
24: ret = true;
25: }
26: I2C_1_I2CMasterClearStatus();
27:
28: return ret;
29:}


レジスタ読み込み関数は、ローモード(?)的な書き方で
1:static bool BME280i_ReadRegister(uint8 addr, uint8 *data, sint32 length)
2:{
3: bool ret = false;
4: uint32 sts;
5:
6: do
7: {
8: sts = I2C_1_I2CMasterSendStart(BME280_SLAVE_ADDR, I2C_1_I2C_WRITE_XFER_MODE);
9: if (sts != I2C_1_I2C_MSTR_NO_ERROR)
10: {
11: DBG_PRINTF("BME280:R:Write slave addr error:0x%lx\r\n", sts);
12: break;
13: }
14:
15: sts = I2C_1_I2CMasterWriteByte(addr);
16: if (sts != I2C_1_I2C_MSTR_NO_ERROR)
17: {
18: DBG_PRINTF("BME280:R:Error when write addr:0x%lx\r\n", sts);
19: break;
20: }
21:
22: sts = I2C_1_I2CMasterSendRestart(BME280_SLAVE_ADDR, I2C_1_I2C_READ_XFER_MODE);
23: if (sts != I2C_1_I2C_MSTR_NO_ERROR)
24: {
25: DBG_PRINTF("BME280:R:Error when write slave addr2:0x%lx\r\n", sts);
26: break;
27: }
28:
29: while(length > 0)
30: {
31: if (--length > 0)
32: {
33: *data++ = (uint8)I2C_1_I2CMasterReadByte(I2C_1_I2C_ACK_DATA);
34: }
35: else
36: {
37: *data++ = (uint8)I2C_1_I2CMasterReadByte(I2C_1_I2C_NAK_DATA);
38: }
39: }
40: ret = true;
41: } while(false);
42:
43: I2C_1_I2CMasterSendStop();
44:
45: return ret;
46:}
ローモードだと、ほとんどI2C APIの名前を変えるだけで行けます

main関数のループ呼び出す、BME280_Handle関数は、
先のWDTの時間を使用して、周期的に処理をしています。
1:void BME280_Handle(void)
2:{
3: sint32 temperature;
4: uint32 humidity;
5: uint32 pressure;
6: uint32 baro;
7:
8: if (WDT_IsTimeout(&timer))
9: {
10: BME280_ForceMeasure();
11: if (BME280_MeasureData(&temperature, &humidity, &pressure))
12: {
13: baro = pressure * 10;
14: CyBle_EsssSetCharacteristicValue(CYBLE_ESS_TEMPERATURE, 0, 2, (uint8*)&temperature);
15: CyBle_EsssSetCharacteristicValue(CYBLE_ESS_HUMIDITY , 0, 2, (uint8*)&humidity );
16: CyBle_EsssSetCharacteristicValue(CYBLE_ESS_PRESSURE , 0, 4, (uint8*)&baro );
17: DBG_PRINTF("BME280:%ld.%02ld, %lu.%02lu, %lu.%03lu\r\n",
18: temperature / 100, temperature % 100,
19: humidity / 100, humidity % 100,
20: pressure / 1000, pressure % 1000);
21: }
22: else
23: {
24: DBG_PRINTF("BME280:measure error\r\n");
25: }
26: }
27:}
設定された時間が経過したらtrueを返すWDT_IsTimeout関数を作成しました。
測定結果をBLEのCharacteristicに書き込んでいます。

TSL2561については、このICのデータシートに載っているソースコードを参考に作成。
レジストの書き込みと読み込みはBME280とほぼ同じでOK。
というか、アドレスしか違わない。あとでまとめた方がよさそう。

main関数のループ呼び出す、TSL2561_Handle関数では、
1:void TSL2561_Handle(void)
2:{
3: uint16 lux, irr;
4: if (WDT_IsTimeout(&timer))
5: {
6: lux = TSL2561_GetLux();
7: DBG_PRINTF("TSL2561:lux=%u\r\n", lux);
8: irr = (lux * 10) / 685;
9: CyBle_EsssSetCharacteristicValue(CYBLE_ESS_IRRADIANCE, 0, 2, (uint8*)&irr);
10: }
11:}
照度(lux)は、BLEでは放射照度(Irradiance)を使用するのでしょうか?
このCharactristicは0.1W/m2単位で格納する必要があるので、
luxを変換して代入しています。
lux⇔W/m2変換は、波長によって変わるようですが、まぁ、いいんでしょう
だけど、単位が荒すぎないですか?
お家では、0か1、がんばって2なんですが。。。
用途違いなのでしょうか。。。

センサー側のログ
画像
1分ごとに各データをNotificationsしています。

データ取得側は、CySmartを使用して、下のログを見るとNotificationを
受信していることが分かります。Notificationを受信すると上側の値も変化します。
画像


照度が納得いってませんが
BLEセンサーは非常に簡単に作成できました
さすが、Cypressですね
記事へブログ気持玉 / トラックバック / コメント


続きを見る

トップへ

月別リンク

迷える子羊の苦悩/BIGLOBEウェブリブログ
文字サイズ:       閉じる