主要內容參考官方文檔https://www.rt-thread.org/document/site/programming-manual/device/i2c/i2c/
官方文檔中採用的是通過IO口模擬來實現I2C(即軟件I2C),軟件I2C相對於硬件I2C有着更好的移植性。
- 通過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傳感器獲取到的溫度和溼度數據。