硬件介绍
- RT-Thread版本:V4.1.0
- 软件包名称:at24cxx
- MCU型号:AT32F407VET7
- EEPROM型号:AT24C16
使用说明
1、使用menuconfig将软件包添加进入工程,路径如下所示。 2、把IIC总线打开,这里使用软件IIC,如果已经打开了就不用再次打开,IIC所用的引脚暂时先不管。 3、然后编译工程。 4、编译完成以后,打开工程,可以发现IIC驱动已经被添加进来了,at24cxx软件包也添加进来了。 5、然后我们进入at24cxx.h文件,修改我们EEPROM型号。我这里是AT24C6。 6、然后我们进入rtconfig.h文件里面,修改我们的IIC引脚。默认是22和23,这里我直接使用GET_PIN来获取引脚,但是这种方式的缺点就是每次menuconfig以后都要去修改一次,不过我也不是经常去menuconfig,测试时就暂时先这么改吧。 7、然后我们将工程编译一下,没有错误,下载到板子上。在shell中输入at24cxx,然后回车,就会弹出几个命令。分别是probe,read,write。 8、要想使用read/write命令,要先使用probe命令对AT24CXX进行初始化。于是输入下面的命令进行初始化。 9、然后就可以使用at24cxx read 和at24cxx write命令进行读写了。当然这个命令做得太简单了,只是读写都是从0地址开始,读写指定的位置的。而我想读写任意位置的数据,因此需要对命令进行改造一下。经过修改后的函数如下,这样我就可以读写任意位置的数据了。我们来演示一下。
static uint8_t opt_buffer[2048];
void at24cxx(int argc, char *argv[])
{
static at24cxx_device_t dev = RT_NULL;
uint16_t opt_addr, opt_len;
if (argc > 1)
{
if (!strcmp(argv[1], "probe"))
{
if (argc > 2)
{
if (!dev || strcmp(dev->i2c->parent.parent.name, argv[2]))
{
if (dev)
{
at24cxx_deinit(dev);
}
dev = at24cxx_init(argv[2], atoi(argv[3]));
}
}
else
{
rt_kprintf("at24cxx probe <dev_name> <AddrInput> - probe sensor by given name\n");
}
}
else if (!strcmp(argv[1], "read"))
{
if (dev)
{
if( argc != 4 )
{
rt_kprintf("example: at24cxx read addr len.\n");
return ;
}
opt_addr = atoi(argv[2]);
opt_len = atoi(argv[3]);
if( opt_len > sizeof(opt_buffer) )
{
rt_kprintf("read len must less than %d.\n", sizeof(opt_buffer));
return ;
}
if( at24cxx_read(dev, opt_addr, opt_buffer, opt_len) == RT_EOK )
{
rt_kprintf("read at24cxx ok\n");
for(uint16_t i=0; i<opt_len; i++)
{
rt_kprintf("%02x ", opt_buffer[i]);
}
rt_kprintf("\n");
for(uint16_t i=0; i<opt_len; i++)
{
rt_kprintf("%02c ", opt_buffer[i]);
}
rt_kprintf("\n");
}
else
{
rt_kprintf("read at24cxx fail.\n");
}
}
else
{
rt_kprintf("Please using 'at24cxx probe <dev_name>' first\n");
}
}
else if (!strcmp(argv[1], "write"))
{
if (dev)
{
if( argc != 4 )
{
rt_kprintf("example: at24cxx write address string.\n");
return ;
}
opt_addr = atoi(argv[2]);
if( at24cxx_write(dev, opt_addr, (uint8_t *)argv[3], rt_strlen(argv[3])) == RT_EOK )
{
rt_kprintf("write ok\n");
}
else
{
rt_kprintf("write fail\n");
}
}
else
{
rt_kprintf("Please using 'at24cxx probe <dev_name>' first\n");
}
}
else if (!strcmp(argv[1], "check"))
{
if (at24cxx_check(dev) == 1)
{
rt_kprintf("check faild \n");
}
}
else
{
rt_kprintf("Unknown command. Please enter 'at24cxx0' for help\n");
}
}
else
{
rt_kprintf("Usage:\n");
rt_kprintf("at24cxx probe <dev_name> - probe eeprom by given name\n");
rt_kprintf("at24cxx check - check eeprom at24cxx \n");
rt_kprintf("at24cxx read - read eeprom at24cxx data\n");
rt_kprintf("at24cxx write - write eeprom at24cxx data\n");
}
}
MSH_CMD_EXPORT(at24cxx, at24cxx eeprom function);
10、我们从0地址开始读,读10个字节。命令格式如下:at24cxx read addr len。表示从addr地址开始读,读取len个字节,如果读取成功,就会将数据通过十六进制和字符的形式打印出来,是不是方便多啦。 11、写指令也是一样的,命令格式如下:at24cxx write addr string 表示从addr开始写,写入字符串string。 12、下面我就通过一个GIF来演示整个过程吧。因为我的项目中有使用easylog(一个打印日志的软件包,会影响我们观看shell的打印),因此我首先将esaylog先关闭,这步操作大家无需进行。 13、另外我还发现了一个问题,就是我的EEPROM是AT24C16,它是2048个字节大小的,但是我似乎无法正常读取256字节以后的地址。经过查看芯片手册发现,AT24C16一共有3位页地址,和8位的字地址,如下表所示。
页地址 | 数据 |
---|
第0页 | 256字节 | 第1页 | 256字节 | , | … | 第15页 | 256字节 |
页地址,用来就控制这是第几页。字地址,用来表示页里面的第几个字节。 而页地址和字地址,是在什么时候发送的呢?我们去看EEPROM的芯片手册的,按字节写操作,会传入8位的字地址。这个就表示要写某页的第几个字节。 而页地址呢?怎么好像没有传入?别急,我们看下图,原来AT24C16没有器件地址,它的器件地址的3个位,用来作为页地址使用了。 也就是说,当我们要访问第256个地址的时候(从0开始计算),我们需要将页地址(器件地址)设置为1,字地址设置为0即可。 14、回过来看代码,我发现读写一个字节的函数的器件地址都是可设置的,AT24CXX_ADDR | dev->AddrInput就是EEPROM器件的地址。这个dev->AddrInput是我们使用probe命令的时候手动传入的,对于我们AT24C16而言使用上不太方便,因为我每次访问不同的地址就需要重新传一遍dev->AddrInput不太好,因此我对这两个读写函数改造一下,让dev->AddrInput可以根据我们传入的读写地址自动计算出来。于是修改后的读写一个字节的代码如下。
uint8_t at24cxx_read_one_byte(at24cxx_device_t dev, uint16_t readAddr)
{
rt_uint8_t buf[2];
rt_uint8_t temp;
#if (EE_TYPE > AT24C16)
buf[0] = (uint8_t)(readAddr>>8);
buf[1] = (uint8_t)readAddr;
if (rt_i2c_master_send(dev->i2c, AT24CXX_ADDR, 0, buf, 2) == 0)
#else
dev->AddrInput = readAddr >> 8;
buf[0] = readAddr;
if (rt_i2c_master_send(dev->i2c, AT24CXX_ADDR | dev->AddrInput, 0, buf, 1) == 0)
#endif
{
return RT_ERROR;
}
read_regs(dev, 1, &temp);
return temp;
}
rt_err_t at24cxx_write_one_byte(at24cxx_device_t dev, uint16_t writeAddr, uint8_t dataToWrite)
{
rt_uint8_t buf[3];
#if (EE_TYPE > AT24C16)
buf[0] = (uint8_t)(writeAddr>>8);
buf[1] = (uint8_t)writeAddr;
buf[2] = dataToWrite;
if (rt_i2c_master_send(dev->i2c, AT24CXX_ADDR, 0, buf, 3) == 3)
#else
dev->AddrInput = writeAddr >> 8;
buf[0] = writeAddr;
buf[1] = dataToWrite;
if (rt_i2c_master_send(dev->i2c, AT24CXX_ADDR | dev->AddrInput, 0, buf, 2) == 2)
#endif
return RT_EOK;
else
return -RT_ERROR;
}
15、编译,下载,再去验证一下,看看能否成功读写0-2047地址的数据。如下图所示,正常啦。
|