BLE_HTS_Demo
This BLE_HTS_Demo program enables you to collect Temperature and Humidity data reading from sensor and transmit to collector device such as smartphone.
Below documents teach you how to install app that can connect and read data from our DELTA-DFCM-NNN40 development board. There are two versions, Android and iPhone.
/media/uploads/Marcomissyou/ios_app_for_environment_sensor_0518.pdf
/media/uploads/Marcomissyou/android_app_for_environment_sensor.pdf
Revision 0:ef0f188a6fdd, committed 2015-06-03
- Comitter:
- Marcomissyou
- Date:
- Wed Jun 03 03:13:27 2015 +0000
- Child:
- 1:a7ecbb0ccc61
- Commit message:
- BLE HTS Demo
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BLE_API.lib Wed Jun 03 03:13:27 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#8c645f5694b2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hts221.cpp Wed Jun 03 03:13:27 2015 +0000
@@ -0,0 +1,157 @@
+/* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *df
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <mbed.h>
+#include "hts221.h"
+
+I2C i2c(p22, p20); //SDA, SCL
+
+/*lint ++flb "Enter library region" */
+
+static const char expected_who_am_i = 0xBCU; //!< Expected value to get from WHO_AM_I register.
+
+uint8_t H0_rH_x2;
+uint8_t H1_rH_x2;
+uint16_t T0_degC_x8;
+uint16_t T1_degC_x8;
+
+int16_t H0_T0_OUT;
+int16_t H1_T0_OUT;
+int16_t T0_OUT;
+int16_t T1_OUT;
+
+float T0_DegC_cal;
+float T1_DegC_cal;
+float H0_RH_cal;
+float H1_RH_cal;
+
+bool hts221_init(void)
+{
+ bool transfer_succeeded = true;
+
+ i2c.frequency(400000);
+ hts221_register_write(0x10 , TRes_4 << 3 | HRes_5);
+ hts221_register_write(0x20 , PD_On | BDU_Off | ODR_1Hz); // Control register 1
+ hts221_register_write(0x21 , NoBoot | HeaterOff | No_OS); // Control register 2
+ hts221_register_write(0x22 , DRDY_H | PP_OD_PP | DRDY_NON); // Control register 3
+
+ // Read and verify product ID
+ transfer_succeeded &= hts221_verify_product_id();
+
+ return transfer_succeeded;
+}
+
+bool hts221_verify_product_id(void)
+{
+ char who_am_i[1];
+ hts221_register_read(ADDRESS_WHO_AM_I, &who_am_i[0], 1);
+ if (who_am_i[0] != expected_who_am_i) return false;
+ else return true;
+}
+
+void hts221_register_write(uint8_t register_address, uint8_t value)
+{
+ char w2_data[2];
+
+ w2_data[0] = register_address;
+ w2_data[1] = value;
+ i2c.write(HTS221_WriteADDE, w2_data, 2);
+
+}
+
+void hts221_register_read(char register_address, char *destination, uint8_t number_of_bytes)
+{
+ i2c.write(HTS221_WriteADDE, ®ister_address, 1, 1);
+ i2c.read(HTS221_WriteADDE, destination, number_of_bytes); //Note by Tsungta, API may have a bug
+
+ //runaboud read function added by Tsungta
+/* if (number_of_bytes == 1) {
+ i2c.write(HTS221_WriteADDE, ®ister_address, 1, 1);
+ i2c.write(HTS221_ReadADDE);
+ *destination = i2c.read(0);
+ i2c.stop();
+ } else {
+ register_address |= 0x80;
+ i2c.write(HTS221_WriteADDE, ®ister_address, 1, 1);
+ i2c.write(HTS221_ReadADDE);
+ while (number_of_bytes-- > 0)
+ *destination++ = i2c.read(0);
+ i2c.stop();
+ }*/
+}
+
+void HTS221_Calib(void)
+{
+ char cal_data[16];
+
+ hts221_register_read(0xB0, cal_data, 16);
+
+ H0_rH_x2 = cal_data[0];
+ H1_rH_x2 = cal_data[1];
+ T0_degC_x8 = ((cal_data[5] & 0x03) << 8) + cal_data[2]; //MSB + LSB in
+ T1_degC_x8 = ((cal_data[5] & 0x0C) << 6) + cal_data[3]; // MSB
+
+ H0_T0_OUT = (cal_data[7] << 8) + cal_data[6];
+ H1_T0_OUT = (cal_data[11] << 8) + cal_data[10];
+ T0_OUT = (cal_data[13] << 8) + cal_data[12];
+ T1_OUT = (cal_data[15] << 8) + cal_data[14];
+
+ // convert negative 2's complement values to native negative value
+ if (H0_T0_OUT&0x8000) H0_T0_OUT = -(0x8000-(0x7fff&H0_T0_OUT));
+ if (H1_T0_OUT&0x8000) H1_T0_OUT = -(0x8000-(0x7fff&H1_T0_OUT)); //((~H1_T0_OUT)+1);//
+ if (T0_OUT&0x8000) T0_OUT = -(0x8000-(0x7fff&T0_OUT));
+ if (T1_OUT&0x8000) T1_OUT = -(0x8000-(0x7fff&T1_OUT));
+
+ T0_DegC_cal = (float) T0_degC_x8/8;
+ T1_DegC_cal = (float) T1_degC_x8/8;
+ H0_RH_cal = (float) H0_rH_x2/2;
+ H1_RH_cal = (float) H1_rH_x2/2;
+
+}
+
+void HTS221_ReadTempHumi( float *pTemp , float *pHumi)
+{
+ char sensor_data[4];
+ int16_t H_OUT;
+ int16_t T_OUT;
+
+ hts221_register_read(0xA8, sensor_data, 4);
+
+ H_OUT = (sensor_data[1] << 8) + sensor_data[0];
+ T_OUT = (sensor_data[3] << 8) + sensor_data[2];
+
+ // convert negative 2's complement values to native negative value
+ if (H_OUT&0x8000) H_OUT = -(0x8000-(0x7fff&H_OUT)); //((~H_OUT)+1);;
+ if (T_OUT&0x8000) T_OUT = -(0x8000-(0x7fff&T_OUT));
+
+ *pTemp = linear_interpolation(T0_OUT, T0_DegC_cal, T1_OUT, T1_DegC_cal, T_OUT);
+ *pHumi = linear_interpolation(H0_T0_OUT, H0_RH_cal, H1_T0_OUT, H1_RH_cal, H_OUT);
+ // Constraint for measurement after calibration
+ if ((int)*pHumi>MaxHumi-1 | (int)*pHumi==-72) *pHumi = MaxHumi;
+ if ((int)*pHumi<MinHumi ) *pHumi = MinHumi;
+ if ((int)*pTemp>MaxTemp-1) *pHumi = MaxTemp;
+ if ((int)*pHumi<MinTemp ) *pHumi = MinTemp ;
+}
+
+float linear_interpolation(int16_t x0, float y0, int16_t x1, float y1, float mes)
+{
+ float a = (float) ((y1 - y0) / (x1 - x0));
+ float b = (float) -a*x0 + y0;
+ float cal = (float) a * mes + b;
+ return cal;
+}
+
+/*lint --flb "Leave library region" */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hts221.h Wed Jun 03 03:13:27 2015 +0000 @@ -0,0 +1,99 @@ +/* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved. + * + * The information contained herein is property of Nordic Semiconductor ASA. + * Terms and conditions of usage are described in detail in NORDIC + * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. + * + * Licensees are granted free, non-transferable use of the information. NO + * WARRANTY of ANY KIND is provided. This heading must NOT be removed from + * the file. + * + */ + +#ifndef HTS221_H +#define HTS221_H + +/*lint ++flb "Enter library region" */ + +#include <stdbool.h> +#include <stdint.h> + +#define ADDRESS_WHO_AM_I (0x0FU) //!< WHO_AM_I register identifies the device. Expected value is 0xBC. + +#define HTS221_WriteADDE 0xBE +#define HTS221_ReadADDE 0xBF +#define HTS221_TempHumi_OUT 0x28 +#define HTS221_CALIB 0x30 + +#define MaxTemp 120 +#define MinTemp -40 +#define MaxHumi 100 +#define MinHumi 0 + +// Humidity and temperature resolution mode, to ocnfigure sample average +#define TRes_1 000 // Number of temperature samples take 2^1, TRes_2 take 2^2, and so forth. +#define TRes_2 001 +#define TRes_3 010 +#define TRes_4 011 +#define TRes_5 100 +#define TRes_6 101 +#define TRes_7 102 +#define TRes_8 103 + +#define HRes_2 000 // Number of humidity samples take 2^2, HRes_3 take 2^3, and so forth. +#define HRes_3 001 +#define HRes_4 010 +#define HRes_5 011 +#define HRes_6 100 +#define HRes_7 101 +#define HRes_8 102 +#define HRes_9 103 + +// Control register 1 +#define PD_On 0x80 // Power down mode +#define PD_Off 0x00 // Active mode + +#define BDU_On 0x04 // Block data update, this feature prevents the reading of LSB and MSB related to different samples. +#define BDU_Off 0x00 +// Define output data rate +#define ODR_OneShot 0x00 +#define ODR_1Hz 0x01 +#define ODR_7Hz 0x02 +#define ODR_12_5Hz 0x03 +// Control register 2 +#define Boot 0x80 +#define NoBoot 0x00 +#define HeaterOn 0x02 +#define HeaterOff 0x00 +#define New_OS 0x01 // One shot, a single acquisition of temperature and humidity is started +#define No_OS 0x00 +// Control register 3 +#define DRDY_H 0x00 // Data Ready output signal active high(default) +#define DRDY_L 0x80 // Data Ready output signal active low +#define PP_OD_PP 0x00 // Push-pull on PIN3(DRDY)(default) +#define PP_OD_OD 0x40 // Open Drain on PIN3(DRDY) +#define DRDY_EN 0x04 // Data Ready enable +#define DRDY_NON 0x00 // Data Ready disable(default) + +// Status register +#define H_DA_On 0x02 // Humidity data avialable, set to 1 whenever a new humidity sample is available. +#define H_DA_Off 0x00 +#define T_DA_On 0x01 // Temperature data avialable, set to 1 whenever a new humidity sample is available. +#define T_DA_Off 0x00 + +bool hts221_init(void); + +void hts221_register_write(uint8_t register_address, const uint8_t value); + +void hts221_register_read(char register_address, char *destination, uint8_t number_of_bytes); + +bool hts221_verify_product_id(void); + +void HTS221_Calib(void); + +void HTS221_ReadTempHumi( float *pTemp , float *pHumi); + +float linear_interpolation(int16_t x0, float y0, int16_t x1, float y1, float mes); + +#endif /* HTS221_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Wed Jun 03 03:13:27 2015 +0000
@@ -0,0 +1,183 @@
+
+
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mbed.h"
+#include "BatteryService.h"
+#include "DeviceInformationService.h"
+#include "BLEDevice.h"
+
+#include "hts221.h"
+#include "uvis25.h"
+#include "nrf_gpio.h"
+
+#include "nrf51_bitfields.h"
+
+#define NEED_CONSOLE_OUTPUT 1 /* Set this if you need debug messages on the console;
+ * it will have an impact on code-size and power consumption. */
+
+#if NEED_CONSOLE_OUTPUT
+Serial pc(p25, p23);
+#define DEBUG(...) { pc.printf(__VA_ARGS__); }
+#else
+#define DEBUG(...) /* nothing */
+#endif /* #if NEED_CONSOLE_OUTPUT */
+
+BLEDevice ble;
+
+InterruptIn Button0_LowInt(p7);
+
+DigitalOut led0(p4);
+DigitalOut led1(p5);
+DigitalOut led2(p6);
+
+static const uint8_t UUID_HUMI_AND_UVI[] = {0xf5, 0x59, 0xa2, 0x49, 0xbe, 0xb1, 0x4c, 0x54, 0xa1, 0x0a, 0xc7, 0x95, 0x7e, 0x17, 0xf8, 0x67};
+uint8_t wrs_HumiUVI_payload[11] = {0, };
+uint8_t htsTempPayload[7] = {0,};
+/* Health Thermometer Service */
+/* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.heart_rate.xml */
+/* Temperature Measurement: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml */
+GattCharacteristic htsTemp ( GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR, htsTempPayload, 6, 13, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE);
+GattCharacteristic wrs_HumiUVI ( UUID_HUMI_AND_UVI, wrs_HumiUVI_payload, 1, 7, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE);
+GattCharacteristic *htsChars[] = {&htsTemp, &wrs_HumiUVI};
+GattService htsService ( GattService::UUID_HEALTH_THERMOMETER_SERVICE, htsChars, sizeof(htsChars) / sizeof(GattCharacteristic *));
+
+float tempCelsius = 25.50;
+int32_t tempCelsius_ix100;
+int8_t exponent = -2;
+uint8_t UTC[7] = { 222, 7, 9, 11, 13, 42, 59 };
+float humi = 55;
+int32_t humi_ix100;
+uint8_t uvi = 8;
+uint32_t counter = 0;
+
+const static char DEVICE_NAME[] = "WRS_d7";
+static const uint16_t uuid16_list[] = {GattService::UUID_BATTERY_SERVICE,
+ GattService::UUID_DEVICE_INFORMATION_SERVICE};
+static volatile bool triggerSensorPolling = false;
+
+/**************************************************************************/
+/*!
+ @brief This custom class can be used to override any GattServerEvents
+ that you are interested in handling on an application level.
+*/
+/**************************************************************************/
+//
+void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
+{
+ DEBUG("Disconnected!\n\r");
+ DEBUG("Restarting the advertising process\n\r");
+ ble.startAdvertising();
+}
+
+void periodicCallback(void)
+{
+ led0 = !led0; /* Do blinky on LED1 while we're waiting for BLE events */
+
+ /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
+ * heavy-weight sensor polling from the main thread. */
+ triggerSensorPolling = true;
+}
+
+void LowInt() {
+ led0 = !led0;
+}
+/**************************************************************************/
+/*!
+ @brief Program entry point
+*/
+/**************************************************************************/
+
+int main(void)
+{
+ nrf_gpio_cfg_output(19); // SWIO
+ nrf_gpio_pin_clear(19);
+
+ Button0_LowInt.fall(&LowInt);
+
+ if (hts221_init() ) //led2=1;
+// else led2=0;
+ HTS221_Calib();
+ /* Setup blinky: led1 is toggled in main, led2 is toggled via Ticker */
+// led1=1;
+// led2=0;
+
+ Ticker ticker;
+ ticker.attach(periodicCallback, 2);
+
+ ble.init();
+ ble.onDisconnection(disconnectionCallback);
+
+ /* Setup auxiliary services. */
+ BatteryService battery(ble);
+ DeviceInformationService deviceInfo(ble, "Delta", "NNN40_1.0", "SN", "EVB_1.0", "B230-n80-m92", "T_0128b");
+
+ /* Setup advertising. */
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
+ ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+ ble.setAdvertisingInterval(1600);
+ ble.startAdvertising();
+
+ ble.addService(htsService);
+
+ while (true) {
+ // if (triggerSensorPolling ) {
+// triggerSensorPolling = false;
+
+ HTS221_ReadTempHumi(&tempCelsius, &humi);
+ uvi = UVIS25_ReadUVI();
+ /* Update the Temperature measurement */
+ /* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml */
+ tempCelsius_ix100 = tempCelsius * 100;
+ htsTempPayload[0] = 0x02; // flag
+ htsTempPayload[1] = tempCelsius_ix100%0xff;
+ htsTempPayload[2] = tempCelsius_ix100/0xff;
+ htsTempPayload[3] = tempCelsius_ix100/0xffff;
+ htsTempPayload[4] = exponent;
+ for (int i = 0; i < 7; i++) htsTempPayload[i+5] = UTC[i];
+ ble.updateCharacteristicValue(htsTemp.getValueAttribute().getHandle(), htsTempPayload, 12);
+
+ ble.waitForEvent();
+ wait(1);
+ //humi_ix100 = humi * 100;
+ wrs_HumiUVI_payload[0] = 0x03; // flag
+ memcpy(&wrs_HumiUVI_payload[1],&humi,4);
+ //wrs_HumiUVI_payload[1] = humi_ix100%0xff;
+// wrs_HumiUVI_payload[2] = humi_ix100/0xff;
+// wrs_HumiUVI_payload[3] = humi_ix100/0xffff;
+// wrs_HumiUVI_payload[4] = exponent;
+ wrs_HumiUVI_payload[5] = uvi;
+
+ ble.updateCharacteristicValue(wrs_HumiUVI.getValueAttribute().getHandle(), wrs_HumiUVI_payload, 6);
+ ble.waitForEvent();
+ DEBUG("%f,%f,%d\r\n", tempCelsius, humi, counter++);
+ wait(1);
+
+ //} else {
+// ble.waitForEvent();
+// }
+ }
+
+}
+
+// Gill modify
+// 20150331 change humi data format to float
+// 20150408 diable triggerSensorPolling function, using while loop and wait
+// 20150428 change external clock to internal RC
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-src.lib Wed Jun 03 03:13:27 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-src/#c83ebf47c0ae
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nRF51822.lib Wed Jun 03 03:13:27 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#bdc690669431
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/uvis25.cpp Wed Jun 03 03:13:27 2015 +0000
@@ -0,0 +1,66 @@
+/* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *df
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <mbed.h>
+#include "uvis25.h"
+
+I2C i2c_uvi(p22, p20); //SDA, SCL
+
+static const char uvis25_expected_who_am_i = 0xCAU; //!< Expected value to get from WHO_AM_I register.
+
+bool uvis25_init(void)
+{
+ bool transfer_succeeded = true;
+
+ i2c_uvi.frequency(400000);
+ uvis25_register_write(0x20 , 0x01);
+
+ // Read and verify product ID
+ transfer_succeeded &= uvis25_verify_product_id();
+
+ return transfer_succeeded;
+}
+
+bool uvis25_verify_product_id(void)
+{
+ char who_am_i[1];
+ uvis25_register_read(UVIS25_ADDRESS_WHO_AM_I, &who_am_i[0], 1);
+ if (who_am_i[0] != uvis25_expected_who_am_i) return false;
+ else return true;
+}
+
+void uvis25_register_write(uint8_t register_address, uint8_t value)
+{
+ char w2_data[2];
+
+ w2_data[0] = register_address;
+ w2_data[1] = value;
+ i2c_uvi.write(UVIS25_WriteADDE, w2_data, 2);
+
+}
+
+void uvis25_register_read(char register_address, char *destination, uint8_t number_of_bytes)
+{
+ i2c_uvi.write(UVIS25_WriteADDE, ®ister_address, 1, 1);
+ i2c_uvi.read(UVIS25_WriteADDE, destination, number_of_bytes);
+}
+
+
+uint8_t UVIS25_ReadUVI(void)
+{
+ char UVI_reading;
+ uvis25_register_read(0x28, &UVI_reading, 1);
+ return (uint8_t) UVI_reading;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uvis25.h Wed Jun 03 03:13:27 2015 +0000 @@ -0,0 +1,39 @@ +/* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved. + * + * The information contained herein is property of Nordic Semiconductor ASA. + * Terms and conditions of usage are described in detail in NORDIC + * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. + * + * Licensees are granted free, non-transferable use of the information. NO + * WARRANTY of ANY KIND is provided. This heading must NOT be removed from + * the file. + * + */ + +#ifndef UVIS25_H +#define UVIS25_H + +/*lint ++flb "Enter library region" */ + +#include <stdbool.h> +#include <stdint.h> + + + +#define UVIS25_ADDRESS_WHO_AM_I (0x0FU) //!< WHO_AM_I register identifies the device. Expected value is 0xCA. + +#define UVIS25_WriteADDE 0x8E +#define UVIS25_ReadADDE 0x8F +#define UVIS25_UVI_OUT 0x28 + +bool uvis25_init(void); + +void uvis25_register_write(uint8_t register_address, const uint8_t value); + +void uvis25_register_read(char register_address, char *destination, uint8_t number_of_bytes); + +bool uvis25_verify_product_id(void); + +uint8_t UVIS25_ReadUVI(void); + +#endif /* UVIS25_H */