RT_Thread ——外设I2C的使用

主要内容参考官方文档https://www.rt-thread.org/document/site/programming-manual/device/i2c/i2c/

官方文档中采用的是通过IO口模拟来实现I2C(即软件I2C),软件I2C相对于硬件I2C有着更好的移植性。

  1. 通过env配置打开I2C

      有时候打开env配置时,会发现并没有I2C这个选型,如下图所示:

   这个时候需要去配置 Kconfig 文件。Kconfig语法参考文档

   https://www.rt-thread.org/document/site/programming-manual/kconfig/kconfig/

  通过在Kconfig文件中添加以下内容即可

  

    menuconfig BSP_USING_I2C
        bool "Enable I2C BUS"
        default n
        select RT_USING_I2C
        select RT_USING_I2C_BITOPS
        select RT_USING_PIN
        if BSP_USING_I2C
            menuconfig BSP_USING_I2C3
                bool "Enable I2C3 BUS (software simulation)"
                default y
                if BSP_USING_I2C3
                    comment "Notice: PC0 --> 32; PC1 --> 33" 
                    config BSP_I2C3_SCL_PIN
                        int "i2c3 scl pin number"
                        range 1 176
                        default 32
                    config BSP_I2C3_SDA_PIN
                        int "I2C3 sda pin number"
                        range 1 176
                        default 33
                endif

            menuconfig BSP_USING_I2C4
                bool "Enable I2C4 BUS (AHT10)"
                default n
                if BSP_USING_I2C4
                    comment "Notice: PC1 --> 33; PD6 --> 54" 
                    config BSP_I2C4_SCL_PIN
                        int "i2c4 scl pin number"
                        range 1 176
                        default 54
                    config BSP_I2C4_SDA_PIN
                        int "I2C4 sda pin number"
                        range 1 176
                        default 33
                endif
        endif

   其中需要注意的是:PC1对应33编号,是I2C4_SDA 。PD6对应的是54编号,是I2C4_SCL。(这里是因为我使用的潘多拉板子,上面这两个引脚连接到了AHT10这个模块,如你想使用其他引脚,直接改引脚就好)。 这里的编号和引脚的对应关系参考源文件中的 drv_gpio.c

  在env工具中,我们就可以看到自己添加的设备了。

我们也可以在其中去修改自己配置的引脚,改为自己想要的引脚对应的编号即可,如下图所示:

保存配置,重新生成工程即可使用了。

下面这段代码来自官方例程,用于测试

/*
 * 程序清单:这是一个 I2C 设备使用例程
 * 例程导出了 i2c_aht10_sample 命令到控制终端
 * 命令调用格式:i2c_aht10_sample i2c1
 * 命令解释:命令第二个参数是要使用的I2C总线设备名称,为空则使用默认的I2C总线设备
 * 程序功能:通过 I2C 设备读取温湿度传感器 aht10 的温湿度数据并打印
*/

#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;

    buf[0] = reg; //cmd
    buf[1] = data[0];
    buf[2] = data[1];

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

    /* 调用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, 0);      /* 发送命令 */
    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 = (struct rt_i2c_bus_device *)rt_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);

特别注意一点:

直接运行肯定会报错,会找不到I2C设备,在测试程序中

#define AHT10_I2C_BUS_NAME          "i2c1"  /* 传感器连接的I2C总线设备名称 */

名称是 i2c1 ,而 Kconfig配置文件中写的是 I2C4

将测试代码中的名称宏定义改为i2c4即可

#define AHT10_I2C_BUS_NAME          "i2c4"  /* 传感器连接的I2C总线设备名称 */

  最后附上测试结果,通过模拟I2C成功读取到AHT10传感器获取到的温度和湿度数据。

  

 

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RT-Thread,可以使用DMA来提高I2C传输的效率。具体实现步骤如下: 1. 配置I2C设备 通过RT-Thread的设备驱动框架,可以配置I2C设备。在I2C设备初始化的过程,需要指定I2C总线号、设备地址等参数。 例如,配置I2C1总线,设备地址为0x50,可以使用以下代码: ```c /* 获取I2C设备 */ struct rt_i2c_bus_device *i2c_bus = (struct rt_i2c_bus_device *)rt_device_find("i2c1"); /* 配置I2C参数 */ struct rt_i2c_msg msgs[2]; rt_uint8_t data[2]; /* 设置读写数据 */ data[0] = 0x00; data[1] = 0x01; /* 设置写数据消息 */ msgs[0].addr = 0x50; msgs[0].flags = RT_I2C_WR; msgs[0].len = 2; msgs[0].buf = data; /* 设置读数据消息 */ msgs[1].addr = 0x50; msgs[1].flags = RT_I2C_RD; msgs[1].len = 2; msgs[1].buf = data; /* 发送I2C消息 */ rt_i2c_transfer(i2c_bus, msgs, 2); ``` 2. 配置DMA设备 通过RT-Thread的设备驱动框架,可以配置DMA设备。在DMA设备初始化的过程,需要指定DMA通道号、传输方向等参数。 例如,配置DMA1通道3,传输方向为从外设到内存,可以使用以下代码: ```c /* 获取DMA设备 */ struct rt_dma_device *dma_device = (struct rt_dma_device *)rt_device_find("dma1"); /* 配置DMA参数 */ struct rt_dma_config dma_config; dma_config.direction = RT_DMA_DEV_TO_MEM; dma_config.tran_width = RT_DMA_WIDTH_8BITS; dma_config.priority = RT_DMA_PRIORITY_HIGH; dma_config.mburst = RT_DMA_BURST_SINGLE; dma_config.pburst = RT_DMA_BURST_SINGLE; dma_config.src_addr = (rt_uint32_t)(&I2C1->DR); dma_config.dst_addr = (rt_uint32_t)(&data[0]); dma_config.buffer_size = 2; dma_config.callback = NULL; /* 配置DMA通道 */ rt_dma_configure(dma_device, 3, &dma_config); ``` 3. 启用DMA传输 在I2C设备和DMA设备都初始化之后,可以启用DMA传输。可以使用RT-Thread的设备接口函数rt_device_control来启用DMA传输。 例如,启用I2C1总线和DMA1通道3的传输,可以使用以下代码: ```c /* 启用DMA传输 */ rt_i2c_dma_transfer(i2c_bus, msgs, 2, dma_device, 3); ``` 启用DMA传输之后,当I2C总线有数据需要传输时,DMA通道就会自动进行数据传输,从而提高I2C传输的效率。 需要注意的是,启用DMA传输之前,需要先将I2C总线的断禁用,否则可能会引起冲突。在DMA传输完成后,需要重新启用I2C总线的断。可以使用以下代码来实现: ```c /* 禁用I2C断 */ rt_interrupt_disable(I2C1_EV_IRQn); rt_interrupt_disable(I2C1_ER_IRQn); /* 启用DMA传输 */ rt_i2c_dma_transfer(i2c_bus, msgs, 2, dma_device, 3); /* 等待DMA传输完成 */ while (rt_dma_get_status(dma_device, 3) != RT_EOK); /* 启用I2C断 */ rt_interrupt_enable(I2C1_EV_IRQn); rt_interrupt_enable(I2C1_ER_IRQn); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值