本帖最后由 WangChong 于 2024-9-3 02:53 编辑
本帖最后由 WangChong 于 2024-9-3 02:52 编辑
本帖最后由 WangChong 于 2024-9-3 02:19 编辑
本帖最后由 WangChong 于 2024-9-3 01:56 编辑
本帖最后由 WangChong 于 2024-9-3 01:56 编辑
本帖最后由 WangChong 于 2024-9-3 01:56 编辑
本帖最后由 WangChong 于 2024-9-3 01:55 编辑
外设介绍
BH1750 是一种基于光电二极管的数字光强传感器,能够测量环境中的光照强度,并将其转换为数字信号。它采用 I2C 接口进行通信,适合用于光强度检测的各种应用,如自动调节显示屏亮度、光线感应开关等。
外设规格参数
工作电压: 2.4V 至 3.6V
测量范围: 1 至 65535 lux
分辨率:
高分辨率模式(1 lx)
低分辨率模式(4 lx)
通信接口: I2C
I2C 地址: 0x23(默认),0x5C(可选) 根据Address 是否接拉低或者拉高进行选择
测量时间:
- 高分辨率模式: 120ms - 180ms
- 低分辨率模式: 16ms - 24 ms
- 待机模式: 0.1 µA(典型值)
功耗:
测量模式: 0.12 mA(典型值)
移植过程
BH1750数据手册
根据数据手册得知, BH1750是使用的I2C通信,同时我们使用的是WB2,因此我们需要根据原理图确认WB2的IIC接口PIN,由于我使用的是WB2-12f的开发板,所以可以在安信可社区Wb2专题下找到对应的原理图,同时根据博流官方GPIO的功能复用可以找到哪些PIN支持IIC
在SDK下的application/iot-solution/demo_bh1750下已经提供了一个完整的实现。 我们来尝试将IIC配置中的PIN3(SDA)改成PIN17 (SDA)。同时将WB2-12fdevkit的12号PIN 和 17号PIN分别接到BH1750的SCL和SDA上进行烧录测试
烧录验证
此时可以通过串口助手已经可以正确的查看到WB2-12F正确的读取了BH1750的光照强度。
代码解读
#include <stdio.h>
#include <FreeRTOS.h>
#include <task.h>
#include <hosal_i2c.h>
#include <bl_gpio.h>
#include <blog.h>
// BH1750 的默认 I2C 地址
#define BH1750_DEFAULT_ADDR BH1750_ADDR_L
#define BH1750_ADDR_H 0x5c // BH1750 高地址
#define BH1750_ADDR_L 0x23 // BH1750 低地址
// BH1750 的各种操作命令
#define BH1750_POWER_DOWN 0x00 // 断电命令
#define BH1750_POWER_ON 0x01 // 开机命令
#define BH1750_RESET 0x07 // 重置命令
#define BH1750_CONTINUOUS_H_MODE 0x10 // 高分辨率模式,持续测量
#define BH1750_CONTINUOUS_H_MODE2 0x11 // 高分辨率模式2,持续测量
#define BH1750_CONTINUOUS_L_MODE 0x13 // 低分辨率模式,持续测量
#define BH1750_ONETIME_H_MODE 0x20 // 高分辨率模式,一次性测量
#define BH1750_ONETIME_H_MODE2 0x21 // 高分辨率模式2,一次性测量
#define BH1750_ONETIME_L_MODE 0x23 // 低分辨率模式,一次性测量
int main(void)
{
// 定义并初始化 I2C 设备 i2c0
static hosal_i2c_dev_t i2c0 = {
.config = {
.address_width = HOSAL_I2C_ADDRESS_WIDTH_7BIT, // 7位地址模式
.freq = 100000, // I2C 通信频率为 100kHz
.mode = HOSAL_I2C_MODE_MASTER, // I2C 主机模式
.scl = 12, // 时钟引脚 GPIO 12
.sda = 17, // 数据引脚 GPIO 17
},
.port = 0, // I2C 端口号
};
// 初始化 I2C 接口
hosal_i2c_init(&i2c0);
for (;;) {
uint8_t buffer[2]; // 用于接收光照强度数据的缓冲区
uint8_t cmd = BH1750_ONETIME_H_MODE; // 设置 BH1750 的测量模式为高分辨率一次性测量
hosal_i2c_master_send(&i2c0, BH1750_DEFAULT_ADDR, &cmd, 1, HOSAL_WAIT_FOREVER); // 发送测量命令到 BH1750
// 接收来自 BH1750 的测量结果(2字节)
int ret = hosal_i2c_master_recv(&i2c0, BH1750_DEFAULT_ADDR, buffer, 2, 100);
if (ret) {
// 如果接收超时,重新发送上电命令并记录错误日志
cmd = BH1750_POWER_ON;
hosal_i2c_master_send(&i2c0, BH1750_DEFAULT_ADDR, &cmd, 1, 100);
blog_error("i2c timeout\r\n");
} else {
// 将接收到的两个字节数据合并为一个16位整数
uint16_t result = buffer[0];
result <<= 8; // 左移8位,放置高8位
result |= buffer[1]; // 组合低8位
// 将测量值转换为光照强度(lux)
float luxlevel = result;
result /= 1.2f;
// 输出光照强度日志
blog_info("lux level: %.02f\r\n", luxlevel);
}
// 任务延时 1000 毫秒,即每隔 1 秒执行一次测量
vTaskDelay(portTICK_RATE_MS * 1000);
}
return 0;
}
库函数
让我们简单的对上面的库函数进行一下整理
bh1750.c
#include "bh1750.h"
#include <blog.h>
#include <FreeRTOS.h>
#include <task.h>
static hosal_i2c_dev_t i2c0 = {
.config = {
.address_width = HOSAL_I2C_ADDRESS_WIDTH_7BIT,
.freq = 100000,
.mode = HOSAL_I2C_MODE_MASTER,
.scl = 12,
.sda = 17,
},
.port = 0,
};
void bh1750_init()
{
blog_info("Initializing I2C...\n");
hosal_i2c_init(&i2c0);
}
void read_bh1750(void *args)
{
for (;;)
{
uint8_t buffer[2];
uint8_t cmd = BH1750_ONETIME_H_MODE;
int ret;
blog_info("Sending command to BH1750...\n");
ret = hosal_i2c_master_send(&i2c0, BH1750_DEFAULT_ADDR, &cmd, 1, HOSAL_WAIT_FOREVER);
if (ret != 0)
{
blog_error("I2C send failed with error: %d\n", ret);
continue;
}
blog_info("Receiving data from BH1750...\n");
ret = hosal_i2c_master_recv(&i2c0, BH1750_DEFAULT_ADDR, buffer, 2, 100);
if (ret != 0)
{
cmd = BH1750_POWER_ON;
hosal_i2c_master_send(&i2c0, BH1750_DEFAULT_ADDR, &cmd, 1, 100);
blog_error("I2C receive failed with error: %d\n", ret);
}
else
{
uint16_t result = (buffer[0] << 8) | buffer[1];
float luxlevel = result / 1.2f;
blog_info("Lux level: %.02f\n", luxlevel);
}
vTaskDelay(pdMS_TO_TICKS(1000)); // 使用宏将毫秒转换为FreeRTOS时间单位
}
}
bh1750.h
#ifndef BH1750_H
#define BH1750_H
#include <hosal_i2c.h>
// BH1750 的默认 I2C 地址
#define BH1750_DEFAULT_ADDR BH1750_ADDR_L
#define BH1750_ADDR_H 0x5c // BH1750 高地址
#define BH1750_ADDR_L 0x23 // BH1750 低地址
// BH1750 的各种操作命令
#define BH1750_POWER_DOWN 0x00 // 断电命令
#define BH1750_POWER_ON 0x01 // 开机命令
#define BH1750_RESET 0x07 // 重置命令
#define BH1750_CONTINUOUS_H_MODE 0x10 // 高分辨率模式,持续测量
#define BH1750_CONTINUOUS_H_MODE2 0x11 // 高分辨率模式2,持续测量
#define BH1750_CONTINUOUS_L_MODE 0x13 // 低分辨率模式,持续测量
#define BH1750_ONETIME_H_MODE 0x20 // 高分辨率模式,一次性测量
#define BH1750_ONETIME_H_MODE2 0x21 // 高分辨率模式2,一次性测量
#define BH1750_ONETIME_L_MODE 0x23 // 低分辨率模式,一次性测量
// 函数声明
void bh1750_init();
void read_bh1750(void *args);
#endif // BH1750_H
main.c
#include <stdio.h>
#include <FreeRTOS.h>
#include <task.h>
#include <hosal_i2c.h>
#include <bl_gpio.h>
#include <blog.h>
#include "bh1750.h"
int main(void)
{
bh1750_init();
xTaskCreate(read_bh1750, "BH1750 Task", 4096, NULL, 10, NULL);
return 0;
}
注意事项
切记,不要在主函数中开启任务的调度器,主函数在其他地方使用extern引用了,相当于一个中转的中间方法,可以用于初始化task。