文章目录
目标:通过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
命令,即可看到程序首先将芯片数据全部擦除,然后读取,读取之后写入,并再次读取查看是否是写入的数据。