RT-Thread Studio 使用笔记(六)| 获取光传感器数据(I2C设备驱动+BH1750手写驱动代码分享)

1. 介绍

2. 添加I2C设备

2.1. 打开I2C设备驱动框架

双击左侧 RT-Thread Setting 文件,即可打开RT-Thread图形化配置工具,软件模拟I2C这一项是灰色的,表示没有打开,单击一下即可打开软件 I2C 的驱动框架,图标变为彩色表示打开:

右击该选项可以打开更多配置,比如查看该驱动设备的依赖、查看该驱动设备的详细配置,查看该驱动设备的API文档,查看在线文档等操作:

Ctrl+S保存,配置生效,软件会自动添加I2C设备驱动框架到工程中:

2.2. 添加软件 I2C 源码

打开了软件 I2C 的驱动框架之后,还要添加软件I2C的驱动底层实现,具体芯片的软件 I2C 驱动源码不同,本例中下载添加 STM32 系列的软件 I2C 驱动:Gitee 下载地址

git clone https://gitee.com/tyustli/tyustli.git

下载之后源码只有两个文件:

将这两个文件添加到项目中的drivers文件夹中:

回到RT-Thread Studio IDE,在项目名称上右击,选择刷新,即可在目录中看到添加的文件:

2.3. 注册 I2C 设备

软件 I2C 添加到工程中之后就可以调用软件 I2C 注册函数 rt_hw_i2c_init 来注册软件 I2C 设备了,该函数的原型如下:

int rt_hw_i2c_init(char *name, rt_uint8_t scl, rt_uint8_t sda)
  • name:设备名称
  • scl:软件模拟I2C的SCL引脚
  • sda:软件模拟I2C的SDA引脚

在小熊派IoT开发板上,温湿度传感器SHT30连接在PB6(SCL)和PB7(SDA) ,所以在main.c文件中先添加头文件:

#include <drv_soft_i2c.h>

然后在文件最后添加如下注册软件 I2C到系统中的代码:

int register_i2c(void)
{
    rt_hw_i2c_init("i2c1", GET_PIN(B,6), GET_PIN(B,7));

    return RT_EOK;
}
//注册到系统中,自动初始化设备
INIT_BOARD_EXPORT(register_i2c);

添加完成之后点击编译,下载到开发板中运行,即可在串口终端中看到日志信息(绿色),提示I2C总线设备已注册成功:

因为main线程中循环打印对使用控制台有影响,所以将打印函数注释:

重新编译下载,在串口终端中输入命令list_device查看系统中注册的设备吗,再次确认I2C总线设备注册成功:

3. BH1750驱动代码

#include <rtthread.h>
#include <rtdevice.h>

#define BH1750_I2C_BUS_NAME         "i2c1"   /* 传感器连接的I2C总线设备名称 */
#define BH1750_ADDR                  0x23    /* 从机地址 */

typedef enum
{
        POWER_OFF_CMD      =        0x00,        //断电:无激活状态
        POWER_ON_CMD       =        0x01,        //通电:等待测量指令
        RESET_REGISTER      =        0x07,        //重置数字寄存器(在断电状态下不起作用)
        CONT_H_MODE           =        0x10,        //连续H分辨率模式:在11x分辨率下开始测量,测量时间120ms
        CONT_H_MODE2         =        0x11,        //连续H分辨率模式2:在0.51x分辨率下开始测量,测量时间120ms
        CONT_L_MODE            =        0x13,        //连续L分辨率模式:在411分辨率下开始测量,测量时间16ms
        ONCE_H_MODE           =        0x20,        //一次高分辨率模式:在11x分辨率下开始测量,测量时间120ms,测量后自动设置为断电模式
        ONCE_H_MODE2         =        0x21,        //一次高分辨率模式2:在0.51x分辨率下开始测量,测量时间120ms,测量后自动设置为断电模式
        ONCE_L_MODE            =        0x23        //一次低分辨率模式:在411x分辨率下开始测量,测量时间16ms,测量后自动设置为断电模式
} BH1750_MODE;

static struct rt_i2c_bus_device *i2c_bus = RT_NULL;     /* I2C总线设备句柄 */

/**
 * @brief        向BH1750发送一条指令
 * @param        cmd —— BH1750工作模式指令(在BH1750_MODE中枚举定义)
 * @retval        成功返回RT_EOK
*/
rt_err_t BH1750_Send_Cmd(BH1750_MODE cmd)
{
    struct rt_i2c_msg msgs;

    msgs.addr = BH1750_ADDR;
    msgs.flags = RT_I2C_WR;
    msgs.len = 1;
    msgs.buf = (rt_uint8_t*)&cmd;

    /* 调用I2C设备接口传输数据 */
    if (rt_i2c_transfer(i2c_bus, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}
/**
 * @brief        从BH1750接收一次光强数据
 * @param        dat —— 存储光照强度的地址(两个字节数组)
 * @retval        成功 —— 返回RT_EOK
*/
rt_err_t BH1750_Read_Dat(rt_uint8_t* dat)
{
    struct rt_i2c_msg msgs;

    msgs.addr = BH1750_ADDR;
    msgs.flags = RT_I2C_RD;
    msgs.len = 2;
    msgs.buf = dat;

    /* 调用I2C设备接口传输数据 */
    if (rt_i2c_transfer(i2c_bus, &msgs, 2) == 2)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}
/**
 * @brief        将BH1750的两个字节数据转换为光照强度值(0-65535)
 * @param        dat  —— 存储光照强度的地址(两个字节数组)
 * @retval        成功 —— 返回光照强度值
*/
rt_uint16_t BH1750_Dat_To_Lux(rt_uint8_t* dat)
{
        rt_uint16_t lux = 0;
        lux = dat[0];
        lux <<= 8;
        lux += dat[1];
        lux = (int)(lux / 1.2);

        return lux;
}

void i2c_bh1750_example_entry(void *parameter)
{
    rt_uint8_t dat[2] = {0};                //dat[0]是高字节,dat[1]是低字节

    /* 查找I2C总线设备,获取I2C总线设备句柄 */
    i2c_bus = (struct rt_i2c_bus_device*)rt_device_find(BH1750_I2C_BUS_NAME);

    if(i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", BH1750_I2C_BUS_NAME);
    }
    while(1)
    {
        /* 发送命令设置模式 */
        BH1750_Send_Cmd(ONCE_H_MODE);

        /* 等待数据转换完成 */
        rt_thread_mdelay(150);

        /* 读取数据 */
        BH1750_Read_Dat(dat);

        /* 转换数据并打印 */
        rt_kprintf("current: %5d lux\n", BH1750_Dat_To_Lux(dat));

        rt_thread_mdelay(1000);
    }
}
int i2c_bh1750_example(void)
{
    rt_thread_t tid;    //线程句柄

    tid = rt_thread_create("bh1750_thread",
                            i2c_bh1750_example_entry,
                            RT_NULL,
                            512,
                            9,
                            10);
   if(tid != RT_NULL)
   {
        //线程创建成功,启动线程
        rt_thread_startup(tid);
   }

   return 0;

}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(i2c_bh1750_example, i2c bh1750 example);

执行该线程:

接收更多精彩文章及资源推送,欢迎订阅我的微信公众号:『mculover666』。

发布了241 篇原创文章 · 获赞 624 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/Mculover666/article/details/104675712