3075|5

659

帖子

1

TA的资源

纯净的硅(中级)

楼主
 

【KW41Z】使用手机BLE连接VEML6075的可穿戴平台紫外检测功能开发 [复制链接]

 
本帖最后由 mars4zhu 于 2017-7-1 10:10 编辑

使用手机BLE连接VEML6075的可穿戴平台紫外检测功能开发
文档编号
TN_TEMPLATE0101_A0
关键字
BLE,VEML6075,可穿戴,紫外检测
摘要
本技术笔记对使用手机BLE连接VEML6075的可穿戴平台紫外检测功能开发进行说明

Mars4zhu
目 录
插图索引
表格索引
错误!未找到目录项。
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("\r\nI2C example -- MasterPolling_VEML6075\r\n");
/*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 OK\n");
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 = %x\n",
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 = %f\n\n", 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
初次编写

最新回复

我的意思是代码里同时有这两个设备的代码,简单说就是既显示六轴传感器的数据,又显示VEML6075的数据。 这时候需要怎么处理一下?我是同时显示六轴的数据和一个I2C时钟,结果I2C时钟的I2C调用不正常,陷到死循环里了(看样子是回调函数有什么地方不正常)。你的两个I2C设备的回调函数是同一个吗?  详情 回复 发表于 2017-7-3 17:04
点赞 关注
 
 

回复
举报

1239

帖子

68

TA的资源

纯净的硅(中级)

沙发
 
 
 
 

回复

1305

帖子

0

TA的资源

纯净的硅(高级)

板凳
 
楼主你的VEML6075和板上的六轴传感器共用I2C1吗?还是说你取消了六轴传感器的代码?或者说你没有尝试2个设备公用同一个I2C接口?

点评

共用i2c总线啊。只要从设备地址不同就行了。我的接线方式就是杜邦线连接到i2c的两根线上面。  详情 回复 发表于 2017-7-3 13:52
 
 
 

回复

659

帖子

1

TA的资源

纯净的硅(中级)

4
 
yang_alex 发表于 2017-7-1 21:35
楼主你的VEML6075和板上的六轴传感器共用I2C1吗?还是说你取消了六轴传感器的代码?或者说你没有尝试2个设 ...

共用i2c总线啊。只要从设备地址不同就行了。我的接线方式就是杜邦线连接到i2c的两根线上面。

点评

我的意思是代码里同时有这两个设备的代码,简单说就是既显示六轴传感器的数据,又显示VEML6075的数据。 这时候需要怎么处理一下?我是同时显示六轴的数据和一个I2C时钟,结果I2C时钟的I2C调用不正常,陷到死循环  详情 回复 发表于 2017-7-3 17:04
 
 
 

回复

1305

帖子

0

TA的资源

纯净的硅(高级)

5
 
mars4zhu 发表于 2017-7-3 13:52
共用i2c总线啊。只要从设备地址不同就行了。我的接线方式就是杜邦线连接到i2c的两根线上面。

我的意思是代码里同时有这两个设备的代码,简单说就是既显示六轴传感器的数据,又显示VEML6075的数据。

这时候需要怎么处理一下?我是同时显示六轴的数据和一个I2C时钟,结果I2C时钟的I2C调用不正常,陷到死循环里了(看样子是回调函数有什么地方不正常)。你的两个I2C设备的回调函数是同一个吗?
 
 
 

回复

659

帖子

1

TA的资源

纯净的硅(中级)

6
 
只用了一个u2c
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表