双击左侧 RT-Thread Setting
文件,即可打开RT-Thread图形化配置工具,软件模拟I2C这一项是灰色的,表示没有打开,单击一下即可打开软件 I2C 的驱动框架,图标变为彩色表示打开:
右击该选项可以打开更多配置,比如查看该驱动设备的依赖、查看该驱动设备的详细配置,查看该驱动设备的API文档,查看在线文档等操作:
按Ctrl+S
保存,配置生效,软件会自动添加I2C设备驱动框架到工程中:
打开了软件 I2C 的驱动框架之后,还要添加软件I2C的驱动底层实现,具体芯片的软件 I2C 驱动源码不同,本例中下载添加 STM32 系列的软件 I2C 驱动:Gitee 下载地址。
git clone https://gitee.com/tyustli/tyustli.git
下载之后源码只有两个文件:
将这两个文件添加到项目中的drivers
文件夹中:
回到RT-Thread Studio IDE,在项目名称上右击,选择刷新,即可在目录中看到添加的文件:
软件 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
然后在文件最后添加如下注册软件 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总线设备注册成功:
#include
#include
#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』。