RT-Thread和STM32|RT-Thread IIC总线官方实例实现

官方的文档写的是读取传感器的温湿度并打印出来,作为萌新学rtt,这个过程稍微有点看不懂,所以我简化了实现过程。
用GPIO口模拟IIC,实现往向设备写入数据,并向从设备读取数据,这个简单的套路理解了,后面完成复杂的功能也会有思路。
工作原理
工作原理参考链接: IIC基本原理
想要先完成数据的读写以实现明显代码效果,可以只用看时序图那一部分。这个文章说了一个重要的点,我把重点的放进来:
这是写操作:

  • 起始信号->从设备地址->写操作->应答信号->从设备数据的地址->应答信号->存数据的buffer->停止信号。
    写入的时候需要明确这个数据需要放在哪。
    RT-Thread和STM32|RT-Thread IIC总线官方实例实现
    文章图片
这是读操作:进行读操作之前需要进行一次伪写操作
  • 起始信号->从设备地址->写操作->应答信号->从设备数据的地址->应答信号->停止信号。
  • 起始信号->从设备数据的地址->应答信号->取数据的buffer->应答信号->停止信号。
RT-Thread和STM32|RT-Thread IIC总线官方实例实现
文章图片

这样就完成了数据的写入和读取。
代码解析
接下来进入代码片:
static void i2c_eep_sample(int argc, char *argv[]) { //定义写入数据的buffer,第一个是数据地址位,第二、三个数据是今天的日期, //uint8为unsigned char型,定义成 6, 18应该不影响 //从设备的地址设为全局变量,这里没有写 rt_uint8_t buf_wr[3] = {0x51, 6,18}; i2c_bus = rt_i2c_bus_device_find(EEP_I2C_BUS_NAME); //查找设备 if(i2c_bus == RT_NULL) { rt_kprintf("can't find %s", EEP_I2C_BUS_NAME); } // WP位拉低,进行写操作 //这是用的EEPROM的控制引脚,使用写数据需要将RE位拉低 //没有就不需要加进去 rt_pin_mode(WP, PIN_MODE_OUTPUT); rt_pin_write(WP, PIN_LOW); epp_wr(i2c_bus, buf_wr, 3); //写数据,数据地址位和两个数据位 rt_thread_mdelay(400); //读数据前需要把读取数据的地址写入, //这里的{0x51,0}下面用两次,一次写入地址,一次读取之前设定好的两个数据 rt_uint8_t buf_rd[2] = {0x51, 0}; //写数据,这里只需要写入一个参数就行 epp_wr(i2c_bus, buf_rd, 1); //读数据,将读到的两位放入buf_rd中 epp_rd(i2c_bus, buf_rd, 2); if (ret == RT_EOK) {rt_kprintf("today is %d.%d\n", buf_rd[0], buf_rd[1]); }}

写入数据实现块:
/* 写传EEPROM寄存器 */ static rt_err_t epp_wr(struct rt_i2c_bus_device *bus, rt_uint8_t *data, rt_uint8_t add) { //创建消息数据结构 struct rt_i2c_msg msgs; msgs.addr = EEP_ADDR; //从设备地址 msgs.flags = RT_I2C_WR; //写 msgs.buf = data; //写入数据,包括从设备数据地址以及两个时间数据 msgs.len = add; //写入数据个数,包括从设备地址/* 调用I2C设备接口传输数据 */ if (rt_i2c_transfer(bus, &msgs, 1) == 1) { rt_kprintf("write ok!\n"); return RT_EOK; } else { return -RT_ERROR; } }

读取数据实现块:
/* 读传EEPROM寄存器数据 */ static rt_err_t epp_rd(struct rt_i2c_bus_device *bus, rt_uint8_t *data, rt_uint8_t add) { //消息数据结构 struct rt_i2c_msg msgs; msgs.addr = EEP_ADDR; //从设备地址 msgs.flags = RT_I2C_RD; //读 msgs.buf = data; //存储数据的buffer msgs.len = add; //读取个数/* 调用I2C设备接口传输数据 */ if (rt_i2c_transfer(bus, &msgs, 1) == 1) {//msgs.buf[1] += 1; rt_kprintf("read ok!\n"); return RT_EOK; } else { return -RT_ERROR; } }

完整代码
#include #include #include "drv_common.h"#define EEP_I2C_BUS_NAME"i2c1"/* 连接I2C总线设备名称 */ #define EEP_ADDR0x50/* 从机地址 */ #define WPGET_PIN(B, 5)static struct rt_i2c_bus_device *i2c_bus = RT_NULL; /* I2C总线设备句柄 *//* 写传EEPROM寄存器 */ static rt_err_t epp_wr(struct rt_i2c_bus_device *bus, rt_uint8_t *data, rt_uint8_t add) {struct rt_i2c_msg msgs; msgs.addr = EEP_ADDR; msgs.flags = RT_I2C_WR; msgs.buf = data; msgs.len = add; /* 调用I2C设备接口传输数据 */ if (rt_i2c_transfer(bus, &msgs, 1) == 1) { rt_kprintf("write ok!\n"); return RT_EOK; } else { return -RT_ERROR; } }/* 读传EEPROM寄存器数据 */ static rt_err_t epp_rd(struct rt_i2c_bus_device *bus, rt_uint8_t *data, rt_uint8_t add) { struct rt_i2c_msg msgs; msgs.addr = EEP_ADDR; msgs.flags = RT_I2C_RD; msgs.buf = data; msgs.len = add; /* 调用I2C设备接口传输数据 */ if (rt_i2c_transfer(bus, &msgs, 1) == 1) {//msgs.buf[1] += 1; rt_kprintf("read ok!\n"); return RT_EOK; } else { return -RT_ERROR; } }static void i2c_eep_sample(int argc, char *argv[]) { rt_err_t ret = RT_NULL; rt_uint8_t buf_wr[3] = {0x51, 6,18}; i2c_bus = rt_i2c_bus_device_find(EEP_I2C_BUS_NAME); //查找设备 if(i2c_bus == RT_NULL) { rt_kprintf("can't find %s", EEP_I2C_BUS_NAME); } /* WP位拉低,进行写操作 */ rt_pin_mode(WP, PIN_MODE_OUTPUT); rt_pin_write(WP, PIN_LOW); epp_wr(i2c_bus, buf_wr, 3); //写地址 rt_thread_mdelay(400); rt_uint8_t buf_rd[2] = {0x51, 0}; epp_wr(i2c_bus, buf_rd, 1); //读数据 epp_rd(i2c_bus, buf_rd, 2); if (ret == RT_EOK) {rt_kprintf("today is %d.%d\n", buf_rd[0], buf_rd[1]); }} /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(i2c_eep_sample, i2c aht10 sample);

实现效果
【RT-Thread和STM32|RT-Thread IIC总线官方实例实现】RT-Thread和STM32|RT-Thread IIC总线官方实例实现
文章图片

总结:这是简单的实现,考虑到的底层很少,相当于黑盒学习,这种办法不益于学习,但是最主要的目的是通过代码效果来告诉你,你的方向是没错的,完成效果后,还需对底层实现进一步的了解!

    推荐阅读