RT-Thread系列06——I2C设备(24C02读写)

文章目录

====>>> 文章汇总(有代码汇总) <<<====

目标:通过I2C接口读写24C02。

  • RT-Thread studio,版本: 2.2.6,不一样其实区别也不大
  • RT-Thread:标准版,4.0.3版本
  • 芯片包版本:0.1.9

1. I2C测试

第一步:在 RT-Thread Settings 中 -> 组件 -> 设备驱动程序 -> 使用GPIO模拟I2C,勾选上。
在这里插入图片描述
第二步:在board.h中打开#define BSP_USING_I2C1宏定义,并修改对应的引脚。注意这里的引脚是用的软件模拟,跟硬件IIC没关系,所以引脚用哪个写哪个。这里如下:

#define BSP_USING_I2C1
#ifdef BSP_USING_I2C1
#define BSP_I2C1_SCL_PIN    GET_PIN(B, 6)
#define BSP_I2C1_SDA_PIN    GET_PIN(B, 7)
#endif

此时如果直接编译,然后在Shell窗口输入list_device命令,就已经能看到i2c1设备了。

第三步:编写24C02驱动代码及测试代码。

这部分c文件和h文件,实际上是从24C02的在线包里面节选出来的。

C文件

#include "drv_iic_24c02.h"

#define LOG_TAG               "AT24C02"
#define LOG_LVL               LOG_LVL_DBG
#include <rtdbg.h>

/* I2C总 线 设 备 句 柄 */
static struct rt_i2c_bus_device *i2c_bus = RT_NULL;

/**
 * @brief   读AT24C02中addr地址的数据
 *
 * @param   addr   读取的地址(0-255)
 *
 * @return  RT_EOK:正常;RT_ERROR:不正常。
 */
uint8_t at24c02_read_byte(uint8_t addr)
{
    struct rt_i2c_msg msg;
    uint8_t buffer[2];
    uint8_t data;

    msg.addr = AT24C02_I2C_ADDR;
    msg.flags = RT_I2C_WR;
    buffer[0] = addr;
    msg.buf = buffer;
    msg.len = 1;
    // 发送要读数据的地址
    rt_i2c_transfer(i2c_bus, &msg, 1);

    msg.flags = RT_I2C_RD;
    msg.buf = &data;
    // 读数据
    rt_i2c_transfer(i2c_bus, &msg, 1);

    return data;
}

/**
 * @brief   AT24C02写一个字节数据
 *
 * @param   addr   写入的地址(0-255)
 * @param   data   写入的数据
 *
 * @return  RT_EOK:正常;RT_ERROR:不正常。
 */
rt_err_t at24c02_write_byte(uint8_t addr, uint8_t data)
{
    struct rt_i2c_msg msg;

    uint8_t buffer[2];

    buffer[0] = addr;
    buffer[1] = data;

    msg.addr = AT24C02_I2C_ADDR;
    msg.flags = RT_I2C_WR;
    msg.buf = buffer;
    msg.len = 2;
    // 发送要写数据的地址、写的数据
    if(rt_i2c_transfer(i2c_bus, &msg, 1) != 1)
        return RT_ERROR;

    return RT_EOK;
}

/**
 * @brief   检查AT24C02设备是否正常
 *
 * @param   check   任意传入一个数(1字节),每次检查不要一样。
 *
 * @return  RT_EOK:正常;RT_ERROR:不正常。
 */
static rt_err_t at24c02_check(uint8_t check)
{
    uint8_t temp;

    // 读取最后一个字节的数据
    temp = at24c02_read_byte(AT24C02_SIZE - 1);
    if(temp != check)
    {
        // 把数据写入最后一个字节的位置
        at24c02_write_byte(AT24C02_SIZE - 1, check);
        rt_thread_mdelay(5);    // wait 5ms
        // 再次读取
        temp = at24c02_read_byte(AT24C02_SIZE - 1);
        if(temp != check)
            return RT_ERROR;
    }
    return RT_EOK;
}

/**
 * @brief   初始化AT24C02
 *
 * @param   void
 *
 * @return  none
 */
rt_err_t at24c02_init()
{
    // 查找I2C总线设备,获取I2C总线设备句柄
    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(AT24C02_I2C_BUS_NAME);
    if (i2c_bus == RT_NULL)
    {
        LOG_D("can't find device! \n");
        return RT_ERROR;
    }

    // 检查AT24C02
    if(at24c02_check(AT24C02_CHECK_VALUE) != RT_EOK)
    {
        LOG_D("at24c02 check fail! \n");
        return RT_ERROR;
    }
    LOG_D("at24c02 check ok! \n");
    return RT_EOK;
}

头文件

#ifndef APPLICATIONS_ICODE_IIC_24C02_SUPPORT_DRV_IIC_24C02_H_
#define APPLICATIONS_ICODE_IIC_24C02_SUPPORT_DRV_IIC_24C02_H_

#include <rtthread.h>
#include "drv_soft_i2c.h"

#define AT24C02_I2C_BUS_NAME    "i2c1"      // 挂载IIC1上,PB6、PB7
#define AT24C02_I2C_ADDR        0x50        // AT24C02从机地址(原有的是0xA0)
#define AT24C02_SIZE            256         // AT24C02大小,共256字节
#define AT24C02_CHECK_VALUE     0x5a

/*
 * 24C02是2K,A0/A1/A2均为0,根据数据手册地址应该为,1 0 1 0 0 0 0 R/W;
 * 即
 * 写:R/W=0,1 0 1 0 0 0 0 0,即0xA0;
 * 读:R/W=1,1 0 1 0 0 0 0 1,即0xA1;
 * 但是:对于7位地址模式,rt_i2c_transfer函数调用了bus->ops->master_xfer(bus, msgs, num);
 * 这个函数为:i2c_bit_xfer,这个函数又调用了i2c_bit_send_address。
 * 这个函数对于七位地址的处理为 addr1 = msg->addr << 1;
 * 即 左移了一位。我们原有的 0xA0 左移之后就不对了。
 * 因此,这里将我们的0xA0提前右移一位 变成0x50,然后再发送就可以了。
 *
 * */

rt_err_t at24c02_init();    // 初始化AT24C02
uint8_t at24c02_read_byte(uint8_t addr);
rt_err_t at24c02_write_byte(uint8_t addr, uint8_t data);


#endif /* APPLICATIONS_ICODE_IIC_24C02_SUPPORT_DRV_IIC_24C02_H_ */

测试代码

#include "drv_iic_24c02.h"
#include <rtthread.h>


static int iic_at24c02_test(void)
{
    rt_uint8_t *read_write_read_buf = RT_NULL;

    // 申请一段内存(256个字节)
    read_write_read_buf = (rt_uint8_t *)rt_malloc(AT24C02_SIZE);

    // 初始化 at24c02
    at24c02_init();

    // 擦除(即全部填充为0)
    for(rt_uint16_t addr = 0; addr < AT24C02_SIZE; addr++)
    {
        if(RT_EOK == at24c02_write_byte(addr, 0))
            rt_kprintf("address %x erase OK.\n", addr);
        else
            rt_kprintf("address %x erase Failed.\n", addr);
    }

    // 连续读255字节的数据
    for(rt_uint16_t addr = 0; addr < AT24C02_SIZE; addr++)
    {
        read_write_read_buf[addr] = at24c02_read_byte(addr);
        rt_kprintf("the data at address %x is %d.\n", addr, read_write_read_buf[addr]);
    }

    // 连续写
    for(rt_uint16_t addr = 0; addr < AT24C02_SIZE; addr++)
    {
        if(RT_EOK == at24c02_write_byte(addr, addr))
            rt_kprintf("address %x write OK.\n", addr);
        else
            rt_kprintf("address %x write Failed.\n", addr);
    }

    // 再次连续读255字节的数据
    for(rt_uint16_t addr = 0; addr < AT24C02_SIZE; addr++)
    {
        read_write_read_buf[addr] = at24c02_read_byte(addr);
        rt_kprintf("the data at address %x is %d.\n", addr, read_write_read_buf[addr]);
    }

    // 释放申请的内存
    rt_free(read_write_read_buf);

    return RT_EOK;
}
MSH_CMD_EXPORT(iic_at24c02_test, iic at24c02 read write test);

程序运行后,在Shell窗口输入iic_at24c02_test命令,即可看到程序首先将芯片数据全部擦除,然后读取,读取之后写入,并再次读取查看是否是写入的数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值