在嵌入式开发中,I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,广泛应用于与外设(如 EEPROM、传感器、显示屏等)进行数据交换。AT24C02 是一种常见的 I2C EEPROM 存储器,它提供 2Kbit 的存储空间,适合存储少量数据,如配置参数或校准数据等。通过编写 I2C 驱动程序和应用程序(APP),我们可以方便地与 AT24C02 EEPROM 进行读写操作。
本指南将介绍如何开发一个 I2C 驱动,编写应用程序来访问 AT24C02 EEPROM,并在 Ubuntu 环境下配置交叉编译工具链来开发和部署该程序。
目录
AT24C02访问方法
在Ubuntu设置交叉编译工具链
使用I2C app代码
AT24C02访问方法
在编写APP之前,我们首先要知道,用哪个IIC控制器,这个IIC设备的设备地址是多少(芯片手册)如下所示就是芯片手册中的截取片段了。因为我们的A2-A0都是拉低的,位于PCB图片中可以看到,因此呢,我们的地址就是0x50了。
同时就是我们也查到了这个设备地址的内容了。
在Ubuntu设置交叉编译工具链
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
export PATH=$PATH:/home/book/imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin
export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
使用I2C app代码
相关代码如下:
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
#include "i2cbusses.h"
#include <time.h>
/* ./at24c02 <i2c_bus_number> w "xxxxx"
* ./at24c02 <i2c_bus_number> r
*/
int main(int argc, char **argv)
{
unsigned char dev_addr = 0x50;
unsigned char mem_addr = 0;
unsigned char buf[32];
int file;
char filename[20];
unsigned char *str;
int ret;
struct timespec req;
if (argc != 3 && argc != 4)
{
printf("Usage:\n");
printf("write eeprom: %s <i2c_bus_number> w string\n", argv[0]);
printf("read eeprom: %s <i2c_bus_number> r\n", argv[0]);
return -1;
}
file = open_i2c_dev(argv[1][0]-'0', filename, sizeof(filename), 0);
if (file < 0)
{
printf("can't open %s\n", filename);
return -1;
}
if (set_slave_addr(file, dev_addr, 1))
{
printf("can't set_slave_addr\n");
return -1;
}
if (argv[2][0] == 'w')
{
// write str: argv[3]
str = argv[3];
req.tv_sec = 0;
req.tv_nsec = 20000000; /* 20ms */
while (*str)
{
// mem_addr, *str
// mem_addr++, str++
ret = i2c_smbus_write_byte_data(file, mem_addr, *str);
if (ret)
{
printf("i2c_smbus_write_byte_data err\n");
return -1;
}
// wait tWR(10ms)
nanosleep(&req, NULL);
mem_addr++;
str++;
}
ret = i2c_smbus_write_byte_data(file, mem_addr, 0); // string end char
if (ret)
{
printf("i2c_smbus_write_byte_data err\n");
return -1;
}
}
else
{
// read
ret = i2c_smbus_read_i2c_block_data(file, mem_addr, sizeof(buf), buf);
if (ret < 0)
{
printf("i2c_smbus_read_i2c_block_data err\n");
return -1;
}
buf[31] = '\0';
printf("get data: %s\n", buf);
}
return 0;
}
<i2c_bus_number>
: 目标设备所在的 I2C 总线号。- 操作类型:
w
表示写数据,r
表示读数据。 - 如果是写操作,传入一个要写入 EEPROM 的字符串。
open_i2c_dev 是一个自定义函数,用于打开 I2C 设备文件(例如 /dev/i2c-1
)。它根据参数指定的 I2C 总线号来选择设备文件。
set_slave_addr 是另一个自定义函数,用于设置 I2C 从设备的地址。在这里,dev_addr = 0x50
是 AT24C02 EEPROM 的默认设备地址。
如果第二个参数是 w
,程序会将字符串写入 EEPROM。
nanosleep(&req, NULL) 在每次写入后暂停 20 毫秒,确保数据能够稳定写入 EEPROM。
最终写入一个 0
字符表示字符串结束。
如果第二个参数是 r
,程序会从 EEPROM 中读取数据。
读取的数据存储在 buf
数组中,最后会打印出来。
例子如下所示:
./at24c02 1 w "xxxxx"
这会将字符串 "xxxxx"
写入 EEPROM。
如果你要读取 EEPROM 中存储的数据,可以使用以下命令:
./at24c02 1 r
这会从 EEPROM 中读取数据并打印出来。
如下为Makefile的相关命令:
all:
$(CROSS_COMPILE)gcc -I ./include -o at24c02_test at24c02_test.c i2cbusses.c smbus.c