【外设移植】Ai-WB2+BH1750 光照强度传感器

[复制链接]
查看662 | 回复7 | 2024-9-3 02:53:49 | 显示全部楼层 |阅读模式

本帖最后由 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

image.png

在SDK下的application/iot-solution/demo_bh1750下已经提供了一个完整的实现。 我们来尝试将IIC配置中的PIN3(SDA)改成PIN17 (SDA)。同时将WB2-12fdevkit的12号PIN 和 17号PIN分别接到BH1750的SCL和SDA上进行烧录测试

image.png

微信图片_20240903021624.jpg

烧录验证

image.png

此时可以通过串口助手已经可以正确的查看到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。

回复

使用道具 举报

bzhou830 | 2024-9-3 08:31:58 | 显示全部楼层
王哥速度可太快了
选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

爱笑 | 2024-9-3 08:33:31 | 显示全部楼层
勤劳的小蜜蜂
用心做好保姆工作
回复 支持 反对

使用道具 举报

djy876 | 2024-9-3 09:58:30 | 显示全部楼层
为什么用blog_info而不用print?这里有知识点吗?
回复 支持 反对

使用道具 举报

大猫的鱼 | 2024-9-3 12:01:12 | 显示全部楼层
速度可以
回复

使用道具 举报

小小鸟 | 2024-9-3 16:32:08 | 显示全部楼层
打Call
回复

使用道具 举报

iiv | 2024-9-3 21:29:45 | 显示全部楼层
王哥真快
回复

使用道具 举报

妖猊 | 2024-9-4 09:08:00 | 显示全部楼层
王哥,我给你点赞
回复 支持 反对

使用道具 举报

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

本版积分规则