前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RT-Thread Nano如何适配I2C设备API,并在RT-Thread Nano使用软件包

RT-Thread Nano如何适配I2C设备API,并在RT-Thread Nano使用软件包

作者头像
Rice加饭
发布2022-05-10 18:18:05
7050
发布2022-05-10 18:18:05
举报
文章被收录于专栏:Rice嵌入式

本文介绍了如何在 RT-Thread Studio 上使用 RT-Thread Nano,并基于 BearPI-IOT STM32L431RCT6 的基础工程进行讲解如何使用 I2C 设备接口及相关软件包使用。

BearPI-IOT board

为什么需要设备接口

  1. RT-Thread 分为标准版本和 Nano 版本,其特点如下:
    • RT-Thread 标准版:拥有设备驱动框架,软件包等组件,软件包都是基于设备驱动接口来实现。
    • RT-Thread Nano:仅仅只是一个 RTOS 内核。没有任何组件。
  2. Nano 是无法直接使用 RT-Thread 丰富软件包功能。
  3. Nano 是一个面向低资源的 MCU 等芯片,不可能增加如同标准版的设备驱动框架。
  4. Nano 需要一套统一设备驱动 API,屏蔽不同芯片的 HAL 层的区别。方便移植工程到不同的平台。
  5. Nano 需要一套设备驱动 API,可以方便使用丰富软件包组件。

准备工作

  1. 使用 RT-Thread Studio 建立一个 STM32L431RCT6 的 RT-Thread Nano 基础工程。
  2. 基础工程创建可参考:在 RT-Thread Studio 上使用 RT-Thread Nano

I2C 设备接口

  1. 在 RT-Thread 标准版中,I2C设备驱动提供了一套设备管理接口来访问 I2C,用户程序可以直接使用该 API 操作 I2C 的功能,设备管理接口如下:

「函数」

「描述」

rt_device_find()

根据 I2C 总线设备名称查找设备获取设备句柄

rt_i2c_transfer()

传输数据

  1. 由于 RT-Thread Nano 不使用设备驱动框架,所以没有对应的 rt_device_find() 这个 API 获取设备对象。但 RT-Thread 标准版实际为用户层提供了另外一套 API 给用户层使用。设备管理接口如下:

「函数」

「描述」

rt_i2c_bus_device_find()

根据 I2C 总线设备名称查找设备获取设备句柄

rt_i2c_transfer()

传输数据

rt_i2c_master_send()

发送数据

rt_i2c_master_recv()

接收数据

  1. 对于 RT-Thread Nano,只需要适配如上这套 API,便可简单修改后使用 RT-Thread 丰富软件包功能。

适配 I2C 设备接口

  1. 复制 RT-Thread 完整版工程中的 i2c.h 文件(路径:rt-thread\components\drivers\include\drivers\i2c.h)到我们准备好的 STM32L431RCT6 的 RT-Thread Nano 基础工程中。
  2. 由于 RT-Thread Nano 没有设备驱动框架,所以我们要把 i2c.h 中有关完整版的内容去掉。整理完之后的 i2c.h 文件如下:
代码语言:javascript
复制
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author        Notes
 * 2021-04-20     RiceChen      first version
 */

#ifndef __I2C_H__
#define __I2C_H__

#include <rtthread.h>

#ifdef __cplusplus
extern "C" {
#endif

#define RT_I2C_WR                0x0000
#define RT_I2C_RD               (1u << 0)
#define RT_I2C_ADDR_10BIT       (1u << 2)  /* this is a ten bit chip address */
#define RT_I2C_NO_START         (1u << 4)
#define RT_I2C_IGNORE_NACK      (1u << 5)
#define RT_I2C_NO_READ_ACK      (1u << 6)  /* when I2C reading, we do not ACK */
#define RT_I2C_NO_STOP          (1u << 7)

struct rt_i2c_config
{
    char *name;
    rt_uint8_t scl;
    rt_uint8_t sda;
};

struct rt_i2c_msg
{
    rt_uint16_t addr;
    rt_uint16_t flags;
    rt_uint16_t len;
    rt_uint8_t  *buf;
};

/*for i2c bus driver*/
struct rt_i2c_bus_device
{
    struct rt_i2c_config *config;
    rt_uint16_t  flags;
    rt_uint16_t  addr;
    struct rt_mutex lock;
    rt_uint32_t  timeout;
    rt_uint32_t  retries;
    void *priv;
};

struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name);
rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
                          struct rt_i2c_msg         msgs[],
                          rt_uint32_t               num);
rt_err_t rt_i2c_control(struct rt_i2c_bus_device *bus,
                        rt_uint32_t               cmd,
                        rt_uint32_t               arg);
rt_size_t rt_i2c_master_send(struct rt_i2c_bus_device *bus,
                             rt_uint16_t               addr,
                             rt_uint16_t               flags,
                             const rt_uint8_t         *buf,
                             rt_uint32_t               count);
rt_size_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
                             rt_uint16_t               addr,
                             rt_uint16_t               flags,
                             rt_uint8_t               *buf,
                             rt_uint32_t               count);

rt_inline rt_err_t rt_i2c_bus_lock(struct rt_i2c_bus_device *bus, rt_tick_t timeout)
{
    return rt_mutex_take(&bus->lock, timeout);
}

rt_inline rt_err_t rt_i2c_bus_unlock(struct rt_i2c_bus_device *bus)
{
    return rt_mutex_release(&bus->lock);
}

int rt_i2c_core_init(void);

#ifdef __cplusplus
}
#endif

#endif

  1. 我们需要适配如上6个 I2C 设备 API ,参考实例:

「函数」

「描述」

rt_i2c_core_init()

I2C 总线初始化

rt_i2c_bus_device_find()

根据 I2C 总线设备名称查找设备获取设备句柄

rt_i2c_transfer()

数据传输

rt_i2c_control()

I2C 总线配置

rt_i2c_master_send()

发送数据

rt_i2c_master_recv()

接收数据

  • drv_i2c.c
代码语言:javascript
复制
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author            Notes
 * 2021-08-21     RiceChen     the first version
 */

#include <board.h>
#include "drv_i2c.h"

#ifdef RT_USING_I2C

enum
{
#ifdef RT_USING_I2C1
    I2C1_INDEX,
#endif
#ifdef RT_USING_I2C2
    I2C2_INDEX,
#endif
};

static struct rt_i2c_config i2c_config[] =
{
#ifdef RT_USING_I2C1
     RT_I2C1_CONFIG,
#endif
#ifdef RT_USING_I2C2
     RT_I2C1_CONFIG
#endif
};

static struct rt_i2c_bus_device i2c_bus[sizeof(i2c_config) / sizeof(i2c_config[0])] = {0};

static void rt_i2c_configure(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t scl_pin = bus->config->scl;
    rt_uint8_t sda_pin = bus->config->sda;

    rt_pin_mode(scl_pin, PIN_MODE_OUTPUT_OD);
    rt_pin_mode(sda_pin, PIN_MODE_OUTPUT_OD);

    rt_pin_write(scl_pin, PIN_HIGH);
    rt_pin_write(sda_pin, PIN_HIGH);
}

static void rt_i2c_set_sda(struct rt_i2c_bus_device *bus, rt_uint32_t state)
{
    rt_uint8_t sda_pin = bus->config->sda;

    if (state)
    {
        rt_pin_write(sda_pin, PIN_HIGH);
    }
    else
    {
        rt_pin_write(sda_pin, PIN_LOW);
    }
}

static void rt_i2c_set_scl(struct rt_i2c_bus_device *bus, rt_uint32_t state)
{
    rt_uint8_t scl_pin = bus->config->scl;

    if (state)
    {
        rt_pin_write(scl_pin, PIN_HIGH);
    }
    else
    {
        rt_pin_write(scl_pin, PIN_LOW);
    }
}

static rt_uint32_t rt_i2c_get_sda(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t sda_pin = bus->config->sda;

    return rt_pin_read(sda_pin);
}

static rt_uint32_t rt_i2c_get_scl(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t scl_pin = bus->config->scl;

    return rt_pin_read(scl_pin);
}

static void rt_i2c_udelay(rt_uint32_t us)
{
    rt_hw_us_delay(us);
}

#define SET_SDA(bus, val)   rt_i2c_set_sda(bus, val)
#define SET_SCL(bus, val)   rt_i2c_set_scl(bus, val)
#define GET_SDA(bus)        rt_i2c_get_sda(bus)
#define GET_SCL(bus)        rt_i2c_get_scl(bus)

#define SDA_L(bus)          SET_SDA(bus, 0)
#define SDA_H(bus)          SET_SDA(bus, 1)
#define SCL_L(bus)          SET_SCL(bus, 0)

static rt_err_t SCL_H(struct rt_i2c_bus_device *bus)
{
    rt_tick_t start;

    SET_SCL(bus, 1);

    if(rt_i2c_get_scl(bus))
    {
        goto done;
    }

    start = rt_tick_get();
    while (!GET_SCL(bus))
    {
        if ((rt_tick_get() - start) > 100)
            return -RT_ETIMEOUT;
        rt_thread_delay(100);
    }
done:
    rt_i2c_udelay(1);

    return RT_EOK;
}

static void rt_i2c_start(struct rt_i2c_bus_device *bus)
{
    SDA_L(bus);
    rt_i2c_udelay(1);
    SCL_L(bus);
}

static void rt_i2c_restart(struct rt_i2c_bus_device *bus)
{
    SDA_H(bus);
    SCL_H(bus);
    rt_i2c_udelay(1);

    SDA_L(bus);
    rt_i2c_udelay(1);
    SCL_L(bus);
}

static void rt_i2c_stop(struct rt_i2c_bus_device *bus)
{
    SDA_L(bus);
    rt_i2c_udelay(1);
    SCL_H(bus);
    rt_i2c_udelay(1);
    SDA_H(bus);
    rt_i2c_udelay(1);
}

rt_inline rt_bool_t rt_i2c_waitack(struct rt_i2c_bus_device *bus)
{
    rt_bool_t ack;

    SDA_H(bus);
    rt_i2c_udelay(1);

    if (SCL_H(bus) < 0)
    {
        return -RT_ETIMEOUT;
    }
    ack = !GET_SDA(bus);
    SCL_L(bus);

    return ack;
}

static rt_int32_t rt_i2c_writeb(struct rt_i2c_bus_device *bus, rt_uint8_t data)
{
    rt_int32_t i;
    rt_uint8_t bit;

    for (i = 7; i >= 0; i--)
    {
        SCL_L(bus);
        bit = (data >> i) & 1;
        SET_SDA(bus, bit);
        rt_i2c_udelay(1);
        if (SCL_H(bus) < 0)
        {
            return -RT_ETIMEOUT;
        }
    }
    SCL_L(bus);
    rt_i2c_udelay(1);

    return rt_i2c_waitack(bus);
}

static rt_int32_t rt_i2c_readb(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t i;
    rt_uint8_t data = 0;

    SDA_H(bus);
    rt_i2c_udelay(1);
    for (i = 0; i < 8; i++)
    {
        data <<= 1;
        if (SCL_H(bus) < 0)
        {
            return -RT_ETIMEOUT;
        }
        if (GET_SDA(bus))
            data |= 1;
        SCL_L(bus);
        rt_i2c_udelay(1);
    }

    return data;
}

static rt_size_t rt_i2c_send_bytes(struct rt_i2c_bus_device *bus,
                                   struct rt_i2c_msg *msg)
{
    rt_int32_t ret;
    rt_size_t bytes = 0;
    const rt_uint8_t *ptr = msg->buf;
    rt_int32_t count = msg->len;
    rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;

    while (count > 0)
    {
        ret = rt_i2c_writeb(bus, *ptr);

        if ((ret > 0) || (ignore_nack && (ret == 0)))
        {
            count --;
            ptr ++;
            bytes ++;
        }
        else if (ret == 0)
        {
            return 0;
        }
        else
        {
            return ret;
        }
    }

    return bytes;
}

static rt_err_t rt_i2c_send_ack_or_nack(struct rt_i2c_bus_device *bus, int ack)
{
    if (ack)
        SET_SDA(bus, 0);
    rt_i2c_udelay(1);
    if (SCL_H(bus) < 0)
    {
        return -RT_ETIMEOUT;
    }
    SCL_L(bus);

    return RT_EOK;
}

static rt_size_t rt_i2c_recv_bytes(struct rt_i2c_bus_device *bus,
                                   struct rt_i2c_msg *msg)
{
    rt_int32_t val;
    rt_int32_t bytes = 0;   /* actual bytes */
    rt_uint8_t *ptr = msg->buf;
    rt_int32_t count = msg->len;
    const rt_uint32_t flags = msg->flags;

    while (count > 0)
    {
        val = rt_i2c_readb(bus);
        if (val >= 0)
        {
            *ptr = val;
            bytes ++;
        }
        else
        {
            break;
        }

        ptr ++;
        count --;
        if (!(flags & RT_I2C_NO_READ_ACK))
        {
            val = rt_i2c_send_ack_or_nack(bus, count);
            if (val < 0)
                return val;
        }
    }

    return bytes;
}

static rt_int32_t rt_i2c_send_address(struct rt_i2c_bus_device *bus,
                                      rt_uint8_t addr, rt_int32_t retries)
{
    rt_int32_t i;
    rt_err_t ret = 0;

    for (i = 0; i <= retries; i++)
    {
        ret = rt_i2c_writeb(bus, addr);
        if (ret == 1 || i == retries)
            break;
        rt_i2c_stop(bus);
        rt_i2c_udelay(1);
        rt_i2c_start(bus);
    }

    return ret;
}

static rt_err_t rt_i2c_bit_send_address(struct rt_i2c_bus_device *bus,
                                        struct rt_i2c_msg *msg)
{
    rt_uint16_t flags = msg->flags;
    rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;

    rt_uint8_t addr1, addr2;
    rt_int32_t retries;
    rt_err_t ret;

    retries = ignore_nack ? 0 : bus->retries;

    if (flags & RT_I2C_ADDR_10BIT)
    {
        addr1 = 0xf0 | ((msg->addr >> 7) & 0x06);
        addr2 = msg->addr & 0xff;

        ret = rt_i2c_send_address(bus, addr1, retries);
        if ((ret != 1) && !ignore_nack)
        {
            return -RT_EIO;
        }

        ret = rt_i2c_writeb(bus, addr2);
        if ((ret != 1) && !ignore_nack)
        {
            return -RT_EIO;
        }
        if (flags & RT_I2C_RD)
        {
            rt_i2c_restart(bus);
            addr1 |= 0x01;
            ret = rt_i2c_send_address(bus, addr1, retries);
            if ((ret != 1) && !ignore_nack)
            {
                return -RT_EIO;
            }
        }
    }
    else
    {
        addr1 = msg->addr << 1;
        if (flags & RT_I2C_RD)
            addr1 |= 1;
        ret = rt_i2c_send_address(bus, addr1, retries);
        if ((ret != 1) && !ignore_nack)
            return -RT_EIO;
    }

    return RT_EOK;
}

rt_err_t rt_i2c_control(struct rt_i2c_bus_device *bus,
                        rt_uint32_t               cmd,
                        rt_uint32_t               arg)
{
    return RT_EOK;
}

rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
                          struct rt_i2c_msg         msgs[],
                          rt_uint32_t               num)
{
    struct rt_i2c_msg *msg;
    rt_int32_t i, ret;
    rt_uint16_t ignore_nack;

    rt_i2c_start(bus);
    for (i = 0; i < num; i++)
    {
        msg = &msgs[i];
        ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
        if (!(msg->flags & RT_I2C_NO_START))
        {
            if (i)
            {
                rt_i2c_restart(bus);
            }
            ret = rt_i2c_bit_send_address(bus, msg);
            if ((ret != RT_EOK) && !ignore_nack)
            {
                goto out;
            }
        }
        if (msg->flags & RT_I2C_RD)
        {
            ret = rt_i2c_recv_bytes(bus, msg);
            if (ret >= 1)
                ;
            if (ret < msg->len)
            {
                if (ret >= 0)
                    ret = -RT_EIO;
                goto out;
            }
        }
        else
        {
            ret = rt_i2c_send_bytes(bus, msg);
            if (ret >= 1)
                ;
            if (ret < msg->len)
            {
                if (ret >= 0)
                    ret = -RT_ERROR;
                goto out;
            }
        }
    }
    ret = i;

out:
    rt_i2c_stop(bus);

    return ret;
}

rt_size_t rt_i2c_master_send(struct rt_i2c_bus_device *bus,
                             rt_uint16_t               addr,
                             rt_uint16_t               flags,
                             const rt_uint8_t         *buf,
                             rt_uint32_t               count)
{
    rt_err_t ret;
    struct rt_i2c_msg msg;

    msg.addr  = addr;
    msg.flags = flags;
    msg.len   = count;
    msg.buf   = (rt_uint8_t *)buf;

    ret = rt_i2c_transfer(bus, &msg, 1);

    return (ret > 0) ? count : ret;
}

rt_size_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
                             rt_uint16_t               addr,
                             rt_uint16_t               flags,
                             rt_uint8_t               *buf,
                             rt_uint32_t               count)
{
    rt_err_t ret;
    struct rt_i2c_msg msg;
    RT_ASSERT(bus != RT_NULL);

    msg.addr   = addr;
    msg.flags  = flags | RT_I2C_RD;
    msg.len    = count;
    msg.buf    = buf;

    ret = rt_i2c_transfer(bus, &msg, 1);

    return (ret > 0) ? count : ret;
}

struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name)
{
    rt_size_t bus_num = sizeof(i2c_bus) / sizeof(i2c_bus[0]);

    for(int i = 0; i < bus_num; i++)
    {
        if(rt_strncmp(i2c_bus[i].config->name, bus_name, RT_NAME_MAX) == 0)
        {
            return &i2c_bus[i];
        }
    }
    return RT_NULL;
}

int rt_i2c_core_init(void)
{
    rt_size_t bus_num = sizeof(i2c_bus) / sizeof(i2c_bus[0]);

    for(int i = 0; i < bus_num; i++)
    {
        i2c_bus[i].config = &i2c_config[i];
        rt_i2c_configure(&i2c_bus[i]);
    }

    return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_i2c_core_init);

#endif /* RT_USING_I2C */

  • drv_i2c.h
代码语言:javascript
复制
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author            Notes
 * 2021-04-20     RiceChen      first version
 */

#ifndef __DRV_I2C_H__
#define __DRV_I2C_H__

#include <drv_common.h>
#include <board.h>
#include "pin.h"
#include "i2c.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef RT_USING_I2C1
#define RT_I2C1_SCL_PIN            GET_PIN(B, 6)
#define RT_I2C1_SDA_PIN            GET_PIN(B, 7)

#define RT_I2C1_CONFIG                                         \
    {                                                          \
        .name = "i2c1",                                        \
        .scl = RT_I2C1_SCL_PIN,                                \
        .sda = RT_I2C1_SDA_PIN,                                \
    }
#endif

#ifdef RT_USING_I2C2
#define RT_I2C2_SCL_PIN            GET_PIN(B, 8)
#define RT_I2C2_SDA_PIN            GET_PIN(B, 9)

#define RT_I2C2_CONFIG                                         \
    {                                                          \
        .name = "i2c2",                                        \
        .scl = RT_I2C2_SCL_PIN,                                \
        .sda = RT_I2C2_SDA_PIN,                                \
    }
#endif

#ifdef __cplusplus
}
#endif

#endif /* __DRV_GPIO_H__ */

编写 I2C 设备使用示例

代码语言:javascript
复制
#include <rtthread.h>
#include <rtdevice.h>

#define AHT10_I2C_BUS_NAME          "i2c1"  /* 传感器连接的I2C总线设备名称 */
#define AHT10_ADDR                  0x38    /* 从机地址 */
#define AHT10_CALIBRATION_CMD       0xE1    /* 校准命令 */
#define AHT10_NORMAL_CMD            0xA8    /* 一般命令 */
#define AHT10_GET_DATA              0xAC    /* 获取数据命令 */

static struct rt_i2c_bus_device *i2c_bus = RT_NULL;     /* I2C总线设备句柄 */
static rt_bool_t initialized = RT_FALSE;                /* 传感器初始化状态 */

/* 写传感器寄存器 */
static rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t *data)
{
    rt_uint8_t buf[3];
    struct rt_i2c_msg msgs;
    rt_uint32_t buf_size = 1;

    buf[0] = reg; //cmd
    if (data != RT_NULL)
    {
        buf[1] = data[0];
        buf[2] = data[1];
        buf_size = 3;
    }

    msgs.addr = AHT10_ADDR;
    msgs.flags = RT_I2C_WR;
    msgs.buf = buf;
    msgs.len = buf_size;

    /* 调用I2C设备接口传输数据 */
    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}

/* 读传感器寄存器数据 */
static rt_err_t read_regs(struct rt_i2c_bus_device *bus, rt_uint8_t len, rt_uint8_t *buf)
{
    struct rt_i2c_msg msgs;

    msgs.addr = AHT10_ADDR;
    msgs.flags = RT_I2C_RD;
    msgs.buf = buf;
    msgs.len = len;

    /* 调用I2C设备接口传输数据 */
    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}

static void read_temp_humi(float *cur_temp, float *cur_humi)
{
    rt_uint8_t temp[6];

    write_reg(i2c_bus, AHT10_GET_DATA, RT_NULL);      /* 发送命令 */
    rt_thread_mdelay(400);
    read_regs(i2c_bus, 6, temp);                /* 获取传感器数据 */

    /* 湿度数据转换 */
    *cur_humi = (temp[1] << 12 | temp[2] << 4 | (temp[3] & 0xf0) >> 4) * 100.0 / (1 << 20);
    /* 温度数据转换 */
    *cur_temp = ((temp[3] & 0xf) << 16 | temp[4] << 8 | temp[5]) * 200.0 / (1 << 20) - 50;
}

static void aht10_init(const char *name)
{
    rt_uint8_t temp[2] = {0, 0};

    /* 查找I2C总线设备,获取I2C总线设备句柄 */
    i2c_bus = rt_i2c_bus_device_find(name);

    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", name);
    }
    else
    {
        write_reg(i2c_bus, AHT10_NORMAL_CMD, temp);
        rt_thread_mdelay(400);

        temp[0] = 0x08;
        temp[1] = 0x00;
        write_reg(i2c_bus, AHT10_CALIBRATION_CMD, temp);
        rt_thread_mdelay(400);
        initialized = RT_TRUE;
    }
}

static void i2c_aht10_sample(int argc, char *argv[])
{
    float humidity, temperature;
    char name[RT_NAME_MAX];

    humidity = 0.0;
    temperature = 0.0;

    if (argc == 2)
    {
        rt_strncpy(name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(name, AHT10_I2C_BUS_NAME, RT_NAME_MAX);
    }

    if (!initialized)
    {
        /* 传感器初始化 */
        aht10_init(name);
    }
    if (initialized)
    {
        /* 读取温湿度数据 */
        read_temp_humi(&temperature, &humidity);

        rt_kprintf("read aht10 sensor humidity   : %d.%d %%\n", (int)humidity, (int)(humidity * 10) % 10);
        if( temperature >= 0 )
        {
            rt_kprintf("read aht10 sensor temperature: %d.%d°C\n", (int)temperature, (int)(temperature * 10) % 10);
        }
        else
        {
            rt_kprintf("read aht10 sensor temperature: %d.%d°C\n", (int)temperature, (int)(-temperature * 10) % 10);
        }
    }
    else
    {
        rt_kprintf("initialize sensor failed!\n");
    }
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(i2c_aht10_sample, i2c aht10 sample);

实例代码运行现象:

``` C
msh >i2c_aht10_sample i2c1
read aht10 sensor humidity   : 90.0 %
read aht10 sensor temperature: 25.33°C
msh >

I2C 设备相关软件包使用

  1. 我们使用as7341软件包来验证 I2C 设备 API。
  2. 首先克隆 as7341 软件包到 STM32L431RCT6 的 RT-Thread Nano 工程。as7341 软件包链接:https://github.com/RiceChen/as7341.git
  3. 由于没有了 RT-Thread 标准版本的设备驱动框架,所以对软件包进行简单的修改:
    • 在 as7341.h 中包含 drv_i2c.h 头文件。
    • 修改 as7341.c 中的测试用例。代码如下:
代码语言:javascript
复制
static void as7341(int argc, char *argv[])
{
    static as7341_device_t dev = RT_NULL;
    
    if (argc > 1)
    {
        if (!strcmp(argv[1], "probe"))
        {
            if (argc >= 3)
            {
                /* initialize the sensor when first probe */
                if (!dev || strcmp(dev->i2c->config->name, argv[2])) // 修改点1
                {
                    /* deinit the old device */
                    if(dev)
                    {
      rt_kprintf("Deinit as7341\n");
                        as7341_deinit(dev);
                    }

                    dev = as7341_init(argv[2], eSpm);
                    if(!dev)
                    {
                        rt_kprintf("as7341 probe failed, check input args\n");
                    }else
     {
      rt_kprintf("as7341 probed, addr:0x%x\n", AS7341_ADDR) ;
     }
                }
            }
            else
            {
                as7341_usage();
            }
        }
        else if (!strcmp(argv[1], "read"))
        {
            if (dev)
            {
                if(!strcmp(argv[2], "spectral"))
                {
                    MODE_ONE_DATA_t data1;
                    MODE_TOW_DATA_t data2;

                    as7341_start_measure(dev, eF1F4ClearNIR);
                    data1 = as7341_read_spectral_data_one(dev);
                    rt_kprintf("F1(405-425nm): %d\n", data1.ADF1);
                    rt_kprintf("F2(435-455nm): %d\n", data1.ADF2);
                    rt_kprintf("F3(470-490nm): %d\n", data1.ADF3);
                    rt_kprintf("F4(505-525nm): %d\n", data1.ADF4);

                    as7341_start_measure(dev, eF5F8ClearNIR);
                    data2 = as7341_read_spectral_data_tow(dev);
                    rt_kprintf("F5(545-565nm): %d\n", data2.ADF5);
                    rt_kprintf("F6(580-600nm): %d\n", data2.ADF6);
                    rt_kprintf("F7(620-640nm): %d\n", data2.ADF7);
                    rt_kprintf("F8(670-690nm): %d\n", data2.ADF8);

                    rt_kprintf("Clear: %d\n", data2.ADCLEAR);
                    rt_kprintf("NIR: %d\n", data2.ADNIR);
                }
                else if(!strcmp(argv[2], "flicker"))
                {
                    rt_uint8_t freq = 0;
                    freq = as7341_read_flicker_data(dev);
                    if(freq == 1)
                    {
                        rt_kprintf("Unknown frequency\n");
                    }
                    else if(freq == 0)
                    {
                        rt_kprintf("No flicker\n");
                    }
                    else
                    {
                        rt_kprintf("freq: %dHz\n", freq);
                    }
                }
                else
                {
                    as7341_usage();
                }
                
            }
            else
            {
                rt_kprintf("Please using 'as7341 probe <i2c dev name>' first\n");
            }
        }
        else
        {
            as7341_usage();
        }
    }
    else
    {
        as7341_usage();   
    }
}
  1. 使用 as7341 软件包实例,编译烧录便可以在终端输入测试命令:
代码语言:javascript
复制
msh >as7341 probe i2c1
as7341 id: 0x24
as7341 probed, addr:0x39
msh >
msh >as7341 read spectral
F1(405-425nm): 1
F2(435-455nm): 3
F3(470-490nm): 4
F4(505-525nm): 5
F5(545-565nm): 7
F6(580-600nm): 6
F7(620-640nm): 7
F8(670-690nm): 4
Clear: 22
NIR: 2
msh >

总结

  • 通过适配I2C设备接口,我们可以无缝对接到软件包的使用。
  • 对于低资源的芯片使用 Nano 并且能够使用 RT-THREAD 丰富的软件,无疑是一个非常完美的做法。也没有庞大的驱动框架。
  • 通过这样的方式,学习完 RT-THREAD Nano 在转移到 RT-THREAD 标准版的学习,更加简单方便。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Rice 嵌入式开发技术分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么需要设备接口
  • 准备工作
  • I2C 设备接口
  • 适配 I2C 设备接口
  • 编写 I2C 设备使用示例
  • I2C 设备相关软件包使用
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档