145 lines
4.1 KiB
C
145 lines
4.1 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include "bh1750.h"
|
|
#include "driver/i2c_master.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/projdefs.h" // for pdMS_TO_TICKS
|
|
|
|
#define BH_1750_MEASUREMENT_ACCURACY 1.2 /*!< BH1750 传感器的典型测量精度因子 */
|
|
|
|
#define BH1750_POWER_DOWN 0x00 /*!< 设置为掉电模式的命令 */
|
|
#define BH1750_POWER_ON 0x01 /*!< 设置为上电模式的命令 */
|
|
#define I2C_CLK_SPEED 400000 /*!< I2C 通信时钟频率 (400kHz) */
|
|
|
|
/**
|
|
* @brief BH1750 设备私有结构体
|
|
*/
|
|
typedef struct {
|
|
i2c_master_dev_handle_t i2c_handle; /*!< I2C 主设备句柄 */
|
|
} bh1750_dev_t;
|
|
|
|
/**
|
|
* @brief 向 BH1750 写入一个字节的辅助函数
|
|
*/
|
|
static esp_err_t bh1750_write_byte(const bh1750_dev_t *const sens, const uint8_t byte)
|
|
{
|
|
return i2c_master_transmit(sens->i2c_handle, &byte, 1, pdMS_TO_TICKS(1000));
|
|
}
|
|
|
|
/**
|
|
* @brief 创建并注册 BH1750 设备
|
|
*
|
|
* @param i2c_bus I2C 总线句柄
|
|
* @param dev_addr 传感器 I2C 地址 (一般为 0x23 或 0x5C)
|
|
* @param handle_ret [out] 返回创建好的设备句柄
|
|
* @return esp_err_t 成功返回 ESP_OK
|
|
*/
|
|
esp_err_t bh1750_create(i2c_master_bus_handle_t i2c_bus, const uint8_t dev_addr, bh1750_handle_t *handle_ret)
|
|
{
|
|
esp_err_t ret = ESP_OK;
|
|
bh1750_dev_t *sensor = (bh1750_dev_t *) calloc(1, sizeof(bh1750_dev_t));
|
|
if (!sensor) {
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
|
|
// 配置并添加新的 I2C 设备到总线
|
|
const i2c_device_config_t i2c_dev_cfg = {
|
|
.device_address = dev_addr,
|
|
.scl_speed_hz = I2C_CLK_SPEED,
|
|
};
|
|
ret = i2c_master_bus_add_device(i2c_bus, &i2c_dev_cfg, &sensor->i2c_handle);
|
|
if (ret != ESP_OK) {
|
|
free(sensor);
|
|
return ret;
|
|
}
|
|
|
|
assert(sensor->i2c_handle);
|
|
*handle_ret = sensor;
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief 删除 BH1750 设备并释放资源
|
|
*/
|
|
esp_err_t bh1750_delete(bh1750_handle_t sensor)
|
|
{
|
|
bh1750_dev_t *sens = (bh1750_dev_t *) sensor;
|
|
if (sens->i2c_handle) {
|
|
i2c_master_bus_rm_device(sens->i2c_handle);
|
|
}
|
|
free(sens);
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief 进入掉电模式(低功耗)
|
|
*/
|
|
esp_err_t bh1750_power_down(bh1750_handle_t sensor)
|
|
{
|
|
bh1750_dev_t *sens = (bh1750_dev_t *) sensor;
|
|
return bh1750_write_byte(sens, BH1750_POWER_DOWN);
|
|
}
|
|
|
|
/**
|
|
* @brief 唤醒并进入上电模式
|
|
*/
|
|
esp_err_t bh1750_power_on(bh1750_handle_t sensor)
|
|
{
|
|
bh1750_dev_t *sens = (bh1750_dev_t *) sensor;
|
|
return bh1750_write_byte(sens, BH1750_POWER_ON);
|
|
}
|
|
|
|
/**
|
|
* @brief 设置测量时间倍率 (MTreg)
|
|
* 用于改变传感器的测量灵敏度
|
|
*/
|
|
esp_err_t bh1750_set_measure_time(bh1750_handle_t sensor, const uint8_t measure_time)
|
|
{
|
|
bh1750_dev_t *sens = (bh1750_dev_t *) sensor;
|
|
uint32_t i = 0;
|
|
uint8_t buf[2] = {0x40, 0x60}; // MTreg 常量部分
|
|
buf[0] |= measure_time >> 5;
|
|
buf[1] |= measure_time & 0x1F;
|
|
for (i = 0; i < 2; i++) {
|
|
esp_err_t ret = bh1750_write_byte(sens, buf[i]);
|
|
if (ESP_OK != ret) {
|
|
return ret;
|
|
}
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief 设置测量模式(连续测量或单词测量,以及分辨率选择)
|
|
*/
|
|
esp_err_t bh1750_set_measure_mode(bh1750_handle_t sensor, const bh1750_measure_mode_t cmd_measure)
|
|
{
|
|
bh1750_dev_t *sens = (bh1750_dev_t *) sensor;
|
|
return bh1750_write_byte(sens, (uint8_t)cmd_measure);
|
|
}
|
|
|
|
/**
|
|
* @brief 获取测量结果
|
|
*
|
|
* @param sensor 设备句柄
|
|
* @param data [out] 返回转换后的光照强度值 (单位: Lux)
|
|
* @return esp_err_t
|
|
*/
|
|
esp_err_t bh1750_get_data(bh1750_handle_t sensor, float *const data)
|
|
{
|
|
bh1750_dev_t *sens = (bh1750_dev_t *) sensor;
|
|
uint8_t read_buffer[2];
|
|
// 从 I2C 读取 2 字节原始数据
|
|
esp_err_t ret = i2c_master_receive(sens->i2c_handle, read_buffer, sizeof(read_buffer), pdMS_TO_TICKS(1000));
|
|
if (ESP_OK != ret) {
|
|
return ret;
|
|
}
|
|
// 将原始数据转换为 Lux (公式: (高8位 << 8 | 低8位) / 1.2)
|
|
*data = (( read_buffer[0] << 8 | read_buffer[1] ) / BH_1750_MEASUREMENT_ACCURACY);
|
|
return ESP_OK;
|
|
}
|