准备工作
使用 RT-Thread Studio 建立一个 STM32L431RCT6 的 RT-Thread Nano 基础工程。
基础工程创建可参考:在 RT-Thread Studio 上使用 RT-Thread Nano
I2C 设备接口
在 RT-Thread 标准版中,I2C设备驱动提供了一套设备管理接口来访问 I2C,用户程序可以直接使用该 API 操作 I2C 的功能,设备管理接口如下:
「函数」 | 「描述」 |
---|
rt_device_find() | 根据 I2C 总线设备名称查找设备获取设备句柄 |
rt_i2c_transfer() | 传输数据 |
由于 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() | 接收数据 |
对于 RT-Thread Nano,只需要适配如上这套 API,便可简单修改后使用 RT-Thread 丰富软件包功能。
适配 I2C 设备接口
复制 RT-Thread 完整版工程中的 i2c.h 文件(路径:rt-thread\components\drivers\include\drivers\i2c.h)到我们准备好的 STM32L431RCT6 的 RT-Thread Nano 基础工程中。
由于 RT-Thread Nano 没有设备驱动框架,所以我们要把 i2c.h 中有关完整版的内容去掉。整理完之后的 i2c.h 文件如下:
/*
?*?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
我们需要适配如上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() | 接收数据 |
/*
?*?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?*/
/*
?*?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 设备使用示例
#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 设备相关软件包使用
我们使用as7341软件包来验证 I2C 设备 API。
首先克隆 as7341 软件包到 STM32L431RCT6 的 RT-Thread Nano 工程。as7341 软件包链接:https://github.com/RiceChen/as7341.git
由于没有了 RT-Thread 标准版本的设备驱动框架,所以对软件包进行简单的修改:
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();???
????}
}
使用 as7341 软件包实例,编译烧录便可以在终端输入测试命令:
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 标准版的学习,更加简单方便。
关注微信公众号『Rice嵌入式开发技术分享』,后台回复“微信”添加作者微信,备注”入群“,便可邀请进入技术交流群。