使用手机BLE连接VEML6075的可穿戴平台紫外检测功能开发 文档编号
| TN_TEMPLATE0101_A0
| 关键字
| BLE,VEML6075,可穿戴,紫外检测
| 摘要
| 本技术笔记对使用手机BLE连接VEML6075的可穿戴平台紫外检测功能开发进行说明
|
Mars4zhu 目 录 1 总述 1 2 紫外线检测及其传感器VEML6075介绍 1 2.1 紫外线及其检测介绍 1 2.2 VEML6075介绍 1 3 VEML6075在FRDM-KW41Z上的移植 2 3.1 Driver例程修改 2 3.1.1 原例程运行结果与代码分析 3 3.1.2 i2c_polling_transfer例程修改适配VEML6075 4 3.2 BLE例程修改 8 4 版本历史(Revision History) 14 插图索引 图 21 紫外UVA与UVB频谱分布 1 图 22 VEML6075的命令协议格式 2 图 23 VEML6075的命令代码与寄存器描述 2 图 31 i2c_polling_transfer例程硬件连线 3 图 32 不连接I2C1(master)和I2C0(slave)接线的i2c_polling_transfer运行结果 3 图 33 连接I2C1(master)和I2C0(slave)接线的i2c_polling_transfer运行结果 4 图 34 i2c_polling_transfer例程修改后读取VEML6075紫外检测结果 8 图 35 FRDM-KW41Z和VEML6075的连线 9 图 36 BLE例程blood_pressure_sensor修改后的截图界面 12 图 37 blood_pressure_sensor例程修改后读取VEML6075并在手机App显示紫外指数截图 13 表格索引 错误!未找到目录项。 1 总述为了评估可穿戴设备的紫外检测,使用Vishay出品的VEML6075紫外检测传感器芯片,并利用具备低功耗蓝牙BLE连接功能的开发板FRDM-KW41Z,实现从手机、平板等便携终端的BLE连接到可穿戴平台,显示紫外线指数检测结果的功能。 2 紫外线检测及其传感器VEML6075介绍2.1 紫外线及其检测介绍紫外线主要包括365nm波长(320-400nm,3dB带宽为350--375nm)的UVA区域和330nm波长(280--4430nm,3dB带宽为315--340nm)的UVB区域, 图 21 紫外UVA与UVB频谱分布 UVB波长较短伤害较大,不过仅占太阳能的0.1%,而UVA虽然波长长单个光子伤害低,但是能量丰富,占了太阳能的4.5%。 2.2 VEML6075介绍VEML6075是一个紫外检测传感器芯片,提供标准的I2C接口,并提供多种命令来设置或读取传感器参数。其读写格式和命令列表如下: 图 22 VEML6075的命令协议格式 图 23 VEML6075的命令代码与寄存器描述 3 VEML6075在FRDM-KW41Z上的移植FRDM-KW41Z是具备多协议无线功能的开发板,特别支持低功耗蓝牙BLE 4.2。为了实现在FRDM-KW41Z上移植VEML6075传感器,需要参照LPC824_VEML6075例程,对FRDM-KW41Z的例程进行修改。 3.1 Driver例程修改出于简单起见,先使用i2c-river例程修改,这里选择i2c_polling_transfer例程。 3.1.1 原例程运行结果与代码分析首先运行i2c-polling_transfer例程,注意例程运行过程前,需要分别连接I2C0和I2C1的SCL和SDA引脚。连接线如下图: 图 31 i2c_polling_transfer例程硬件连线 运行结果如下: 图 32 不连接I2C1(master)和I2C0(slave)接线的i2c_polling_transfer运行结果 图 33 连接I2C1(master)和I2C0(slave)接线的i2c_polling_transfer运行结果 3.1.2 i2c_polling_transfer例程修改适配VEML6075根据VEML6075的数据手册,采用I2C1作为I2C-Master来设置和读取VEML6075的参数。 原有的LPC824_VEML6075例程的代码主体结构不需要变化,只需要修改适配最终的I2C通讯相关的代码部分,即SetupXferRecAndExecute函数。并且复制delay和delay_Long函数。 #define VEML6075_I2C_ADDR_7BIT (0x10) #define I2C_ADDR_7BIT VEML6075_I2C_ADDR_7BIT static uint8_t txData[16]; static uint8_t rxData[16]; static int txSize, rxSize; void delay(unsigned int n) { while(n!=0){n--;} } void delay_Long(unsigned long n) { unsigned int i; for(i=0;i<n;i++) delay(100); } /* Function to setup and execute I2C transfer request */ static void SetupXferRecAndExecute(uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize, uint8_t *rxBuffPtr, uint16_t rxSize) { memset(&masterXfer, 0, sizeof(masterXfer)); masterXfer.slaveAddress = VEML6075_I2C_ADDR_7BIT; masterXfer.direction = kI2C_Write; masterXfer.subaddress = 0; masterXfer.subaddressSize = 0; masterXfer.data = txBuffPtr; masterXfer.dataSize = txSize; masterXfer.flags = kI2C_TransferNoStopFlag; I2C_MasterTransferBlocking(EXAMPLE_I2C_MASTER_BASEADDR, &masterXfer); memset(&masterXfer, 0, sizeof(masterXfer)); masterXfer.slaveAddress = VEML6075_I2C_ADDR_7BIT; masterXfer.direction = kI2C_Read; masterXfer.subaddress = 0; masterXfer.subaddressSize = 0; masterXfer.data = rxBuffPtr; masterXfer.dataSize = rxSize; masterXfer.flags = kI2C_TransferRepeatedStartFlag; I2C_MasterTransferBlocking(EXAMPLE_I2C_MASTER_BASEADDR, &masterXfer); } 需要注意的是在读参数的时候,整个I2C协议帧包括先写命令和再读参数两部分,两部分的I2C中间不需要STOP,即第一部分的写命令的I2C为 kI2C_TransferNoStopFlag,第二个的flags为kI2C_TransferRepeatedStartFlag。否则会出现一直停留在I2C协议帧的第二部分代码里。 Main函数的代码修改为如下: #define DEBUGOUT PRINTF #define printf PRINTF int main(void) { BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); PRINTF("rnI2C example -- MasterPolling_VEML6075rn"); /*2.Set up i2c master to send data to slave*/ /* * masterConfig.baudRate_Bps = 100000U; * masterConfig.enableStopHold = false; * masterConfig.glitchFilterWidth = 0U; * masterConfig.enableMaster = true; */ I2C_MasterGetDefaultConfig(&masterConfig); masterConfig.baudRate_Bps = I2C_BAUDRATE; sourceClock = I2C_MASTER_CLK_FREQ; I2C_MasterInit(EXAMPLE_I2C_MASTER_BASEADDR, &masterConfig, sourceClock); // 初始化VEML6075,发送0x00命令,参数为0x40 txSize = 3; rxSize = 0; txData[0]=0x00; txData[1]=0x40;//0x10; txData[3]=0x00;//0x10; SetupXferRecAndExecute(I2C_ADDR_7BIT, txData,txSize, rxData, rxSize); txSize = 1; rxSize = 2; txData[0]=0x0C; SetupXferRecAndExecute(I2C_ADDR_7BIT, txData,txSize, rxData, rxSize); /* Enter the task loop */ DEBUGOUT("Initialization OKn"); float a = 2.22, b = 1.33, c = 2.95, d = 1.74; while(1) { uint16_t UVA_data, UVB_data, UVcomp1_data, UVcomp2_data, UV_id; float UVAcalc, UVBcalc; // 发送0x07命令,读取UVA_data寄存器的数值 txData[0]=0x07; SetupXferRecAndExecute(I2C_ADDR_7BIT, txData,txSize, rxData, rxSize); UVA_data = (rxData[1] << 8) + rxData[0]; delay(100); // 发送0x09命令,读取UVB_data寄存器的数值 txData[0]=0x09; SetupXferRecAndExecute(I2C_ADDR_7BIT, txData,txSize, rxData, rxSize); UVB_data = (rxData[1] << 8) + rxData[0]; delay(100); // 发送0x0A命令,读取UVcomp1_data寄存器的数值 txData[0]=0x0A; SetupXferRecAndExecute(I2C_ADDR_7BIT, txData,txSize, rxData, rxSize); UVcomp1_data = (rxData[1] << 8) + rxData[0]; delay(100); // 发送0x0B命令,读取UVcomp2_data寄存器的数值 txData[0]=0x0B; SetupXferRecAndExecute(I2C_ADDR_7BIT, txData,txSize, rxData, rxSize); UVcomp2_data = (rxData[1] << 8) + rxData[0]; delay(100); // 发送0x0C命令,读取UV_id寄存器的数值 txData[0]=0x0C; SetupXferRecAndExecute(I2C_ADDR_7BIT, txData,txSize, rxData, rxSize); UV_id = (rxData[1] << 8) + rxData[0]; delay(100); printf("UVA_data = %d, UVB_data = %d, UVcomp1_data = %d, UVcomp2_data = %d, UV_id = %xn", UVA_data, UVB_data, UVcomp1_data, UVcomp2_data, UV_id); UVAcalc = (float)UVA_data - a*(float)UVcomp1_data - b*(float)UVcomp2_data; UVBcalc = (float)UVB_data - c*(float)UVcomp1_data - d*(float)UVcomp2_data; printf("UVAcalc = %f, UVBcalc = %fnn", UVAcalc, UVBcalc); delay_Long(20000); } } 最终运行结果为: 图 34 i2c_polling_transfer例程修改后读取VEML6075紫外检测结果 3.2 BLE例程修改项目要求实现BLE连接功能,最终在手机上显示紫外检测结果,因此在BLE例程上进行修改。为了方便显示,选择blood_pressure_sensor例程。将原例程中的模拟的心率传感数据替换为读取的紫外显示数据,最终在App中可以直观的看到数据结果(虽然App显示为心率,但是实际明白是紫外指数就行。 首先硬件连线,将VEML6075的VCC、GND以及I2C接线SCL、SDA分别于FRDM-KW41Z连接即可。 图 35 FRDM-KW41Z和VEML6075的连线 基本同样的代码修改,在blood_pressure_sensor.c文件中添加如下代码: // Mars4zhu Add for VEML6075 #include "fsl_i2c.h" // #include "pinmux.h" #define EXAMPLE_I2C_MASTER_BASEADDR I2C1 #define I2C_MASTER_CLK_SRC I2C1_CLK_SRC #define I2C_MASTER_CLK_FREQ CLOCK_GetFreq(I2C1_CLK_SRC) #define I2C_BAUDRATE 100000U #define I2C_DATA_LENGTH 32U i2c_master_config_t masterConfig; uint32_t sourceClock; i2c_master_transfer_t masterXfer; #define VEML6075_I2C_ADDR_7BIT (0x10) #define I2C_ADDR_7BIT VEML6075_I2C_ADDR_7BIT static uint8_t txData[16]; static uint8_t rxData[16]; static int txSize, rxSize; void delay(unsigned int n) { while(n!=0){n--;} } void delay_Long(unsigned long n) { unsigned int i; for(i=0;i<n;i++) delay(100); } /* Function to setup and execute I2C transfer request */ static void SetupXferRecAndExecute(uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize, uint8_t *rxBuffPtr, uint16_t rxSize) { memset(&masterXfer, 0, sizeof(masterXfer)); masterXfer.slaveAddress = VEML6075_I2C_ADDR_7BIT; masterXfer.direction = kI2C_Write; masterXfer.subaddress = 0; masterXfer.subaddressSize = 0; masterXfer.data = txBuffPtr; masterXfer.dataSize = txSize; masterXfer.flags = kI2C_TransferNoStopFlag; I2C_MasterTransferBlocking(EXAMPLE_I2C_MASTER_BASEADDR, &masterXfer); memset(&masterXfer, 0, sizeof(masterXfer)); masterXfer.slaveAddress = VEML6075_I2C_ADDR_7BIT; masterXfer.direction = kI2C_Read; masterXfer.subaddress = 0; masterXfer.subaddressSize = 0; masterXfer.data = rxBuffPtr; masterXfer.dataSize = rxSize; masterXfer.flags = kI2C_TransferRepeatedStartFlag; I2C_MasterTransferBlocking(EXAMPLE_I2C_MASTER_BASEADDR, &masterXfer); } void VEML6075_Init() { // 修改开发板引脚设置,I2C1功能引出到PTC2/PTC3 BOARD_InitI2C(); // 初始化VEML6075,发送0x00命令,参数为0x40 I2C_MasterGetDefaultConfig(&masterConfig); masterConfig.baudRate_Bps = I2C_BAUDRATE; sourceClock = I2C_MASTER_CLK_FREQ; I2C_MasterInit(EXAMPLE_I2C_MASTER_BASEADDR, &masterConfig, sourceClock); txSize = 3; rxSize = 0; txData[0]=0x00; txData[1]=0x40; // 800ms txData[3]=0x00; ; SetupXferRecAndExecute(I2C_ADDR_7BIT, txData,txSize, rxData, rxSize); txSize = 1; rxSize = 2; txData[0]=0x0C; SetupXferRecAndExecute(I2C_ADDR_7BIT, txData,txSize, rxData, rxSize); } void VEML6075_GetUV_data(uint16_t *UVA_data, uint16_t *UVB_data) { txSize = 1; rxSize = 2; // 发送0x07命令,读取UVA_data寄存器的数值 txData[0]=0x07; SetupXferRecAndExecute(I2C_ADDR_7BIT, txData,txSize, rxData, rxSize); *UVA_data = (rxData[1] << 8) + rxData[0]; delay(100); // 发送0x09命令,读取UVB_data寄存器的数值 txData[0]=0x09; SetupXferRecAndExecute(I2C_ADDR_7BIT, txData,txSize, rxData, rxSize); *UVB_data = (rxData[1] << 8) + rxData[0]; delay(100); } 然后在BleApp_Init()函数中添加VEML6075_Init(); void BleApp_Init(void) { /* Initialize application support for drivers */ BOARD_InitAdc(); VEML6075_Init(); } 最后将TimerMeasurementCallback()函数修改为读取VEML6075的紫外检测指数。 static void TimerMeasurementCallback(void * pParam) { uint16_t UVA_data, UVB_data; VEML6075_GetUV_data(&UVA_data, &UVB_data); bpsMeasurement_t bp; bp.unit = gBps_UnitInkPa_c; bp.systolicValue = UVA_data; bp.diastolicValue = UVB_data; bp.meanArterialPressure = (bp.systolicValue + bp.diastolicValue * 2)/3; Bps_RecordBloodPressureMeasurement(service_blood_pressure, &bp); } 最后编译运行,在App中得到如下功能。必须认清App中的心率参数systolic和diastolic两个值现在分别是VEML6075传感器检测到的UVA和UVB紫外指数。 图 36 BLE例程blood_pressure_sensor修改后的截图界面 使用手机的相机LED曝光灯(手电筒功能)照射VEML6075,可以看到紫外线指数急剧增加。因此手机App成功通过BLE连接读取到了紫外检测结果。 图 37 blood_pressure_sensor例程修改后读取VEML6075并在手机App显示紫外指数截图 4 版本历史(Revision History)版本号
| 发布时间
| 内容
| A0
| 2017-06-30
| 初次编写
|
|