前言
本章介绍如何在涂鸦T2-U开发板上添加光感bh1750驱动并实现定时读取数据。
一、基础介绍
BH1750( GY-302 )光照传感器
这篇文章有bh1750的基础介绍。
我这里总结一下。
bh1750采用i2c通信,有5个引脚,vcc,gnd,sda,scl,add。
其中add接gnd时i2c地址为0x23,接vcc为0x5c。
模式:
三种分辨率模式,H(1lx),H2(0.5lx),L(41lx),其中1lx表示返回的数值1表示1lx,用于计算实际lx。
两种测试:连续,一次。
总共组合就是6中,常用的是一次H分辨率模式。
指令:
以一次H分辨率模式为例。
- 软重置:__bh1750_write_cmd(dev, BH1750_CMD_SOFT_RESET);
- 设置模式:__bh1750_write_cmd(dev, BH1750_CMD_ONE_H_RES_MODE);
- 等待采样:__bh1750_delay_ms(180);
- 读取采样值:__bh1750_read_data(dev, 2, buf);
如上述四步就可以读取到光感数据,剩下的就是实现接口和数据处理。
#define BH1750_CMD_POWER_DOWN 0x00
#define BH1750_CMD_POWER_ON 0x01
#define BH1750_CMD_SOFT_RESET 0x07
#define BH1750_CMD_CON_H_RES_MODE 0x10
#define BH1750_CMD_CON_H_RES_MODE2 0x11
#define BH1750_CMD_CON_L_RES_MODE 0x13
#define BH1750_CMD_ONE_H_RES_MODE 0x20
#define BH1750_CMD_ONE_H_RES_MODE2 0x21
#define BH1750_CMD_ONE_L_RES_MODE 0x23
二、电路图
2.1 电路图1
一开始我打算使用默认的pin1和pin0作为sda和scl,但是不知道是不是和打开了串口调试开关有关,i2c通信失败,后续采用了20,22。
注意,p1和p0,对应的pin是28,29。
序号 |
符号 |
说明 |
---|
22 |
RX2 |
T2-U 的 UART_RX2,对应 IC 的 P1(对应 IC 的 Pin 28)。 |
23 |
TX2 |
T2-U 的 UART_TX2,打印日志口,对应 IC 的 P0(对应 IC 的 Pin 29)。 |
2.2 电路图2——实际采用
序号 |
符号 |
说明 |
---|
24 |
P20 |
T2-U 的 普通 GPIO(对应 IC 的 Pin 20)。 |
25 |
P22 |
T2-U 的 普通 GPIO(对应 IC 的 Pin 18)。 |
三、代码
代码基于tuyaos_sensor_hub_demo_quickstart实现的。
需要复制该项目,并仿照温感sht30的驱动,添加bh1750驱动。
电子发烧友的帖子大小有限,可以去csdn看源码。
【涂鸦T2-U】2、添加光感bh1750-CSDN博客
tdd_sensor_bh1750.c
#include "tdl_sensor_driver.h"
#include "tdd_sensor_light.h"
#include "tkl_gpio.h"
#include "tal_system.h"
#include "tal_log.h"
#define CRC_OK (0)
#define CRC_ERR (-1)
#define BH1750_CLOSE 0
#define BH1750_OPEN (!BH1750_CLOSE)
#define BH1750_RSRC_INDEX_STAT 0
#define BH1750_RSRC_INDEX_ADDR 1
#define BH1750_RSRC_INDEX_PREC 2
#define BH1750_RSRC_INDEX_FREQ 3
#define BH1750_RSRC_INDEX_RESL 4
typedef USHORT_T BH1750_CMD_E;
#define BH1750_CMD_POWER_DOWN 0x00
#define BH1750_CMD_POWER_ON 0x01
#define BH1750_CMD_SOFT_RESET 0x07
#define BH1750_CMD_CON_H_RES_MODE 0x10
#define BH1750_CMD_CON_H_RES_MODE2 0x11
#define BH1750_CMD_CON_L_RES_MODE 0x13
#define BH1750_CMD_ONE_H_RES_MODE 0x20
#define BH1750_CMD_ONE_H_RES_MODE2 0x21
#define BH1750_CMD_ONE_L_RES_MODE 0x23
#define BH1750_CMD_READ_SERIALNBR 0x3780
#define BH1750_CMD_HEATER_ENABLE 0x306D
#define BH1750_CMD_HEATER_DISABLE 0x3066
#define BH1750_CMD_READ_STATUS 0xF32D
#define BH1750_CMD_CLEAR_STATUS 0x3041
#define BH1750_CMD_ART 0x2B32
#define BH1750_CMD_BREAK 0x3093
#define BH1750_CMD_FETCH_DATA 0xE000
#define BH1750_CMD_MEAS_PERI_05_H 0x2032
#define BH1750_CMD_MEAS_PERI_05_M 0x2024
#define BH1750_CMD_MEAS_PERI_05_L 0x202F
#define BH1750_CMD_MEAS_PERI_1_H 0x2130
#define BH1750_CMD_MEAS_PERI_1_M 0x2126
#define BH1750_CMD_MEAS_PERI_1_L 0x212D
#define BH1750_CMD_MEAS_PERI_2_H 0x2236
#define BH1750_CMD_MEAS_PERI_2_M 0x2220
#define BH1750_CMD_MEAS_PERI_2_L 0x222B
#define BH1750_CMD_MEAS_PERI_4_H 0x2334
#define BH1750_CMD_MEAS_PERI_4_M 0x2322
#define BH1750_CMD_MEAS_PERI_4_L 0x2329
#define BH1750_CMD_MEAS_PERI_10_H 0x2737
#define BH1750_CMD_MEAS_PERI_10_M 0x2721
#define BH1750_CMD_MEAS_PERI_10_L 0x272A
#define BH1750_CMD_MEAS_POLLING_H 0x2400
#define BH1750_CMD_MEAS_POLLING_M 0x240B
#define BH1750_CMD_MEAS_POLLING_L 0x2416
#define BH1750_CMD_MEAS_CLOCKSTR_H 0x2C06
#define BH1750_CMD_MEAS_CLOCKSTR_M 0x2C0D
#define BH1750_CMD_MEAS_CLOCKSTR_L 0x2C10
#define BH1750_CMD_W_AL_LIM_HS 0x611D
#define BH1750_CMD_W_AL_LIM_HC 0x6116
#define BH1750_CMD_W_AL_LIM_LC 0x610B
#define BH1750_CMD_W_AL_LIM_LS 0x6100
#define BH1750_CMD_R_AL_LIM_LS 0xE102
#define BH1750_CMD_R_AL_LIM_LC 0xE109
#define BH1750_CMD_R_AL_LIM_HS 0xE11F
#define BH1750_CMD_R_AL_LIM_HC 0xE114
#if (SR_CONFIG_NO_FPU == 1)
STATIC SR_ELE_CFG_T sg_ele_val_tp[SR_LT_ELE_NUM] = {
{
.id = SR_LT_ELE_ID_LIGHT,
.val_tp = SR_VAL_TP_INT,
}
};
#else
STATIC SR_ELE_CFG_T sg_ele_val_tp[SR_LT_ELE_NUM] = {
{
.id = SR_LT_ELE_ID_LIGHT,
.val_tp = SR_VAL_TP_FLOAT,
}
};
#endif
STATIC VOID_T __bh1750_delay_ms(IN CONST ULONG_T tm)
{
tal_system_sleep(tm);
}
STATIC UCHAR_T __bh1750_get_crc8(IN CONST UCHAR_T *data, IN USHORT_T len)
{
UCHAR_T i;
UCHAR_T crc = 0xFF;
while (len--) {
crc ^= *data;
for (i = 8; i > 0; --i) {
if (crc & 0x80) {
crc = (crc << 1) ^ 0x31;
} else {
crc = (crc << 1);
}
}
data++;
}
return crc;
}
STATIC INT_T __bh1750_check_crc8(IN CONST UCHAR_T *data, IN CONST USHORT_T len, IN CONST UCHAR_T crc_val)
{
if (__bh1750_get_crc8(data, len) != crc_val) {
return CRC_ERR;
}
return CRC_OK;
}
STATIC OPERATE_RET __bh1750_read_data(IN CONST SR_RSRC_T *dev, IN CONST USHORT_T len, OUT UCHAR_T *data)
{
SR_I2C_MSG_T rd_msg = {
.flags = SR_I2C_FLAG_RD,
.addr = dev->info[BH1750_RSRC_INDEX_ADDR],
.len = len,
.buff = data
};
return tdd_sensor_i2c_xfer(dev->port, &rd_msg);
}
STATIC OPERATE_RET __bh1750_write_cmd2(IN CONST SR_RSRC_T *dev, IN CONST BH1750_CMD_E cmd)
{
UCHAR_T cmd_bytes[2];
cmd_bytes[0] = (UCHAR_T)(cmd >> 8);
cmd_bytes[1] = (UCHAR_T)(cmd & 0x00FF);
SR_I2C_MSG_T wr_msg = {
.flags = SR_I2C_FLAG_WR,
.addr = dev->info[BH1750_RSRC_INDEX_ADDR],
.len = 2,
.buff = cmd_bytes
};
return tdd_sensor_i2c_xfer(dev->port, &wr_msg);
}
STATIC OPERATE_RET __bh1750_write_cmd(IN CONST SR_RSRC_T *dev, IN CONST BH1750_CMD_E cmd)
{
UCHAR_T cmd_bytes;
cmd_bytes = (UCHAR_T)(cmd & 0xFF);
SR_I2C_MSG_T wr_msg = {
.flags = SR_I2C_FLAG_WR,
.addr = dev->info[BH1750_RSRC_INDEX_ADDR],
.len = 1,
.buff = &cmd_bytes
};
return tdd_sensor_i2c_xfer(dev->port, &wr_msg);
}
STATIC VOID_T __bh1750_write_2bytes_data(IN CONST SR_RSRC_T *dev, IN CONST BH1750_CMD_E cmd, IN CONST USHORT_T data)
{
UCHAR_T buf[5];
buf[0] = (UCHAR_T)(cmd >> 8);
buf[1] = (UCHAR_T)(cmd & 0x00FF);
buf[2] = (UCHAR_T)(data >> 8);
buf[3] = (UCHAR_T)(data & 0x00FF);
buf[4] = __bh1750_get_crc8(buf+2, 2);
SR_I2C_MSG_T wr_msg = {
.flags = SR_I2C_FLAG_WR,
.addr = dev->info[BH1750_RSRC_INDEX_ADDR],
.len = 5,
.buff = buf
};
tdd_sensor_i2c_xfer(dev->port, &wr_msg);
}
STATIC VOID_T __bh1750_start_periodic_measurement(IN CONST SR_RSRC_T *dev)
{
switch (dev->info[BH1750_RSRC_INDEX_PREC]) {
default:
case SR_LT_PREC_HIGH:
switch (dev->info[BH1750_RSRC_INDEX_FREQ]) {
case SR_LT_FREQ_ONE:
__bh1750_write_cmd(dev, BH1750_CMD_ONE_H_RES_MODE);
break;
case SR_LT_FREQ_CON:
__bh1750_write_cmd(dev, BH1750_CMD_CON_H_RES_MODE);
break;
}
break;
case SR_LT_PREC_MEDIUM:
switch (dev->info[BH1750_RSRC_INDEX_FREQ]) {
case SR_LT_FREQ_ONE:
__bh1750_write_cmd(dev, BH1750_CMD_ONE_H_RES_MODE);
break;
case SR_LT_FREQ_CON:
__bh1750_write_cmd(dev, BH1750_CMD_CON_H_RES_MODE);
break;
}
break;
case SR_LT_PREC_LOW:
switch (dev->info[BH1750_RSRC_INDEX_FREQ]) {
case SR_LT_FREQ_ONE:
__bh1750_write_cmd(dev, BH1750_CMD_ONE_L_RES_MODE);
break;
case SR_LT_FREQ_CON:
__bh1750_write_cmd(dev, BH1750_CMD_CON_L_RES_MODE);
break;
}
break;
}
}
STATIC VOID_T __bh1750_stop_periodic_measurement(IN CONST SR_RSRC_T *dev)
{
__bh1750_write_cmd(dev, BH1750_CMD_ONE_L_RES_MODE);
}
STATIC OPERATE_RET __bh1750_set_precision(INOUT SR_RSRC_T *dev, IN CONST SR_LT_PREC_E *prec)
{
if ((prec == NULL) || (*prec >= SR_LT_PREC_INVALID)) {
return OPRT_INVALID_PARM;
}
dev->info[BH1750_RSRC_INDEX_PREC] = *prec;
__bh1750_start_periodic_measurement(dev);
return OPRT_OK;
}
STATIC OPERATE_RET __bh1750_set_frequency(INOUT SR_RSRC_T *dev, IN CONST SR_LT_PREC_E *freq)
{
if ((freq == NULL) || (*freq >= SR_LT_FREQ_INVALID)) {
return OPRT_INVALID_PARM;
}
dev->info[BH1750_RSRC_INDEX_PREC] = *freq;
__bh1750_start_periodic_measurement(dev);
return OPRT_OK;
}
STATIC VOID_T __bh1750_calc_light(IN CONST USHORT_T light, OUT SR_VAL_U *light_val,IN USHORT_T resl)
{
#if (SR_CONFIG_NO_FPU == 1)
light_val->sr_int = light * resl / 2;
TAL_PR_ERR("light_val->sr_int=%d",light_val->sr_int);
#else
light_val->sr_float = light * resl / 2.0F;
TAL_PR_ERR("light_val->sr_float=%0.1f",light_val->sr_float);
#endif
}
STATIC OPERATE_RET __bh1750_read_light(IN CONST SR_RSRC_T *dev, OUT USHORT_T *light)
{
UCHAR_T buf[2] = {0};
OPERATE_RET ret = OPRT_OK;
TAL_PR_ERR("[BH1750] __bh1750_read_light");
__bh1750_write_cmd(dev, BH1750_CMD_SOFT_RESET);
__bh1750_write_cmd(dev, BH1750_CMD_ONE_H_RES_MODE);
__bh1750_delay_ms(180);
ret = __bh1750_read_data(dev, 2, buf);
if(ret != OPRT_OK)
return ret;
*light = ((USHORT_T)buf[0] << 8) | buf[1];
TAL_PR_ERR("[BH1750] buf = %0x %0x light= %d",buf[0],buf[1],*light);
return OPRT_OK;
}
STATIC OPERATE_RET __bh1750_soft_reset(IN CONST SR_RSRC_T *dev)
{
__bh1750_write_cmd(dev, BH1750_CMD_SOFT_RESET);
__bh1750_delay_ms(50);
return OPRT_OK;
}
STATIC OPERATE_RET __tdd_sensor_bh1750_open(INOUT SR_RSRC_T *dev)
{
__bh1750_write_cmd(dev, BH1750_CMD_POWER_ON);
dev->info[BH1750_RSRC_INDEX_STAT] = BH1750_OPEN;
return OPRT_OK;
}
STATIC OPERATE_RET __tdd_sensor_bh1750_close(INOUT SR_RSRC_T *dev)
{
__bh1750_write_cmd(dev, BH1750_CMD_POWER_DOWN);
dev->info[BH1750_RSRC_INDEX_STAT] = BH1750_CLOSE;
return OPRT_OK;
}
STATIC OPERATE_RET __tdd_sensor_bh1750_control(INOUT SR_RSRC_T* dev, IN UCHAR_T cmd, INOUT VOID_T *param)
{
OPERATE_RET op_ret = OPRT_OK;
if ((BH1750_OPEN == dev->info[BH1750_RSRC_INDEX_STAT]) &&\\
(cmd == SR_LT_CMD_SET_PREC ||\\
cmd == SR_LT_CMD_SET_FREQ ||\\
cmd == SR_LT_CMD_SOFT_RESET )) {
TAL_PR_ERR("[BH1750] Command <%d> is only supported when acquisition is closed.");
return OPRT_COM_ERROR;
}
switch (cmd) {
case SR_LT_CMD_SOFT_RESET:
op_ret = __bh1750_soft_reset(dev);
break;
case SR_LT_CMD_SET_PREC:
op_ret = __bh1750_set_precision(dev, (SR_LT_PREC_E *)param);
break;
case SR_LT_CMD_SET_FREQ:
op_ret = __bh1750_set_frequency(dev, (SR_LT_FREQ_E *)param);
break;
default:
op_ret = OPRT_INVALID_PARM;
TAL_PR_ERR("[BH1750] Command <%d> is invalid.", cmd);
break;
}
return op_ret;
}
STATIC OPERATE_RET __tdd_sensor_bh1750_read(IN SR_RSRC_T* dev, OUT SR_ELE_DATA_T *ele_data, IN UCHAR_T ele_num)
{
USHORT_T light = 0;
TAL_PR_ERR("[BH1750] __tdd_sensor_bh1750_read");
OPERATE_RET op_ret = __bh1750_read_light(dev, &light);
if (op_ret != OPRT_OK) {
return op_ret;
}
for (UCHAR_T i = 0; i < ele_num; i++) {
switch (ele_data[i].id) {
case SR_LT_ELE_ID_LIGHT:
TAL_PR_ERR("[BH1750] get value. resl=%d",dev->info[BH1750_RSRC_INDEX_RESL]);
__bh1750_calc_light(light, &ele_data[i].val, (USHORT_T)dev->info[BH1750_RSRC_INDEX_RESL]);
break;
default:
TAL_PR_ERR("[BH1750] Element ID: %d is invalid.", ele_data[i].id);
break;
}
}
return OPRT_OK;
}
OPERATE_RET tdd_sensor_bh1750_register(IN CHAR_T *name, IN SR_LT_I2C_CFG_T i2c_cfg, IN SR_LT_MEAS_CFG_T meas_cfg)
{
if (i2c_cfg.gpio.scl == i2c_cfg.gpio.sda) {
return OPRT_INVALID_PARM;
}
tdd_sensor_i2c_init(i2c_cfg.port, i2c_cfg.gpio);
SR_RSRC_T resource = {0};
resource.port = i2c_cfg.port;
resource.handle = NULL;
resource.info[BH1750_RSRC_INDEX_STAT] = BH1750_CLOSE;
resource.info[BH1750_RSRC_INDEX_ADDR] = i2c_cfg.addr;
resource.info[BH1750_RSRC_INDEX_PREC] = meas_cfg.prec;
resource.info[BH1750_RSRC_INDEX_FREQ] = meas_cfg.freq;
switch (meas_cfg.prec) {
case SR_LT_PREC_HIGH:
resource.info[BH1750_RSRC_INDEX_RESL] = 2;
break;
case SR_LT_PREC_MEDIUM:
resource.info[BH1750_RSRC_INDEX_RESL] = 1;
break;
case SR_LT_PREC_LOW:
resource.info[BH1750_RSRC_INDEX_RESL] = 82;
break;
default:
resource.info[BH1750_RSRC_INDEX_RESL] = 1;
break;
}
STATIC SR_INTFS_T s_intfs;
s_intfs.open = __tdd_sensor_bh1750_open;
s_intfs.close = __tdd_sensor_bh1750_close;
s_intfs.control = __tdd_sensor_bh1750_control;
s_intfs.read_ele = __tdd_sensor_bh1750_read;
OPERATE_RET op_ret = tdl_sensor_register(name, &s_intfs, SR_LT_ELE_NUM, sg_ele_val_tp, &resource);
if (OPRT_OK != op_ret) {
return op_ret;
}
return OPRT_OK;
}
四、编译
在ubuntu下使用vscode进行编译很方便。
图片过大,电子发烧友无法上传图片,可以去csdn上看。
【涂鸦T2-U】2、添加光感bh1750-CSDN博客
五、刷机
图片过大,电子发烧友无法上传图片,可以去csdn上看。
【涂鸦T2-U】2、添加光感bh1750-CSDN博客
六、测试结果
如图,其中buf显示的是bh1750返回的值,两个字节。
比如01,38合起来就是0x138=312。
[01-01 00:43:20 TUYA E][tdd_sensor_bh1750.c:861] [BH1750] __tdd_sensor_bh1750_read
[01-01 00:43:20 TUYA E][tdd_sensor_bh1750.c:425] [BH1750] __bh1750_read_light
[01-01 00:43:20 TUYA E][tdd_sensor_bh1750.c:450] [BH1750] buf = 1 38 light= 312
[01-01 00:43:20 TUYA E][tdd_sensor_bh1750.c:871] [BH1750] get value. resl=2
[01-01 00:43:20 TUYA E][tdd_sensor_bh1750.c:392] light_val->sr_float=312.0
[01-01 00:43:20 TUYA I][app_light.c:147] Light: 312 sg_lt_dp_data.light.dp_value: 312
[01-01 00:43:22 TUYA E][tdd_sensor_bh1750.c:861] [BH1750] __tdd_sensor_bh1750_read
[01-01 00:43:22 TUYA E][tdd_sensor_bh1750.c:425] [BH1750] __bh1750_read_light
[01-01 00:43:22 TUYA E][tdd_sensor_bh1750.c:450] [BH1750] buf = 4 3d light= 1085
[01-01 00:43:22 TUYA E][tdd_sensor_bh1750.c:871] [BH1750] get value. resl=2
[01-01 00:43:22 TUYA E][tdd_sensor_bh1750.c:392] light_val->sr_float=1085.0
[01-01 00:43:22 TUYA I][app_light.c:147] Light: 1085 sg_lt_dp_data.light.dp_value: 312
[01-01 00:43:22 TUYA I][app_light.c:154] Light change. Enable report
[01-01 00:43:24 TUYA E][tdd_sensor_bh1750.c:861] [BH1750] __tdd_sensor_bh1750_read
[01-01 00:43:24 TUYA E][tdd_sensor_bh1750.c:425] [BH1750] __bh1750_read_light
[01-01 00:43:24 TUYA E][tdd_sensor_bh1750.c:450] [BH1750] buf = 4 3d light= 1085
[01-01 00:43:24 TUYA E][tdd_sensor_bh1750.c:871] [BH1750] get value. resl=2
[01-01 00:43:24 TUYA E][tdd_sensor_bh1750.c:392] light_val->sr_float=1085.0
[01-01 00:43:24 TUYA I][app_light.c:147] Light: 1085 sg_lt_dp_data.light.dp_value: 1085
小结
本章只是基础的添加驱动,后续还是需要实现联网并上传到云端。
补充一下,除了前期遇到环境搭建的网络问题,涂鸦的开发还是很舒服的,一键编译和一键下载。