Arduino 入门学习笔记12 读写外置EEPROM
- 一、准备工作
- 1. 外置 EEPROM 简介
- 2. Arduino操作外置 EEPROM 流程
- 二、读写操作流程
- 1. 写操作流程
- 2. 读操作
- 三、示例代码
一、准备工作
1. 外置 EEPROM 简介
外置I2C接口的EEPROM是一种常用的非易失性存储器,通过I2C总线与微控制器或其他设备进行通信。它通常用于存储持久性数据,如配置设置、日志、校准数据等。以下是一些常用的外置I2C接口的EEPROM型号以及它们的特点:
-
24C系列:Microchip的24C系列EEPROM是一些常见的I2C接口EEPROM型号。它们分为24C01到24C512等不同容量的型号,容量从128字节到64K字节不等。这些EEPROM设备在I2C总线上占用7位或8位的设备地址,并且通常具有多个页,可实现更高的写入速度。
-
AT24系列:AT24系列是Atmel(现在的Microchip)生产的I2C EEPROM。它们也提供不同容量的选项,从AT24C01到AT24C512。这些设备通常具有低功耗特性,适用于电池供电的设备。
-
CAT24系列:Catalyst(现在的ON Semiconductor)的CAT24系列EEPROM是一种具有扩展温度范围和多个页的EEPROM。它们适用于工业和汽车应用。
-
M24系列:STMicroelectronics的M24系列EEPROM提供了多种不同容量的型号,具有低功耗和低工作电流特性。
-
TC24系列:Microchip的TC24系列EEPROM针对温度敏感的应用提供了增强的温度范围。
-
FM24系列:Fremont Micro Devices的FM24系列EEPROM采用了更大的页大小,以实现更高的写入速度。
-
LC24系列:Excelon™ Ultra-Low-Power EEPROM是Microchip的一个系列,适用于需要极低功耗的应用。
下图是AT24系列引脚示例:
2. Arduino操作外置 EEPROM 流程
在Arduino中,读写外部EEPROM(电可擦除可编程只读存储器)的流程与内置EEPROM类似,但需要通过I2C通信来与外部EEPROM设备进行交互。基本流程是:
-
连接硬件:首先,将外部EEPROM设备与Arduino连接,通常使用I2C通信协议。确保连接SCL(时钟线)和SDA(数据线)引脚,并将设备的电源(VCC和GND)连接到适当的电源引脚。
-
安装I2C库:在Arduino IDE中,需要安装Wire库,它用于I2C通信。在"工具"菜单下的"管理库"中搜索"Wire"并安装它。
-
编写读写代码:根据外部EEPROM的规格和通信协议,编写Arduino代码来读写EEPROM。
一般EEPROM 的 I2C 地址从 0x00开始。
二、读写操作流程
1. 写操作流程
当使用writeEEPROM
函数时,一个外部EEPROM设备通过I2C总线与我们建立了通信,以实现数据写入到特定地址的存储单元。以下是writeEEPROM
函数的步骤解释:
-
开启通信:首先,我们使用
Wire.beginTransmission(EEPROM_ADDR)
来开始I2C通信,发送一个起始信号,这标志着写入操作的开始。在这里,EEPROM_ADDR
是外部EEPROM设备的I2C地址。 -
发送高位地址:接着,我们使用
Wire.write((int)highByte(address))
发送了地址的高字节部分。这个高位地址指示了我们希望将数据写入的确切存储单元。 -
发送低位地址:继续,我们使用
Wire.write((int)lowByte(address))
发送了地址的低字节部分。这个低位地址更精确地指定了写入的位置。 -
发送数据:此时,我们使用
Wire.write(data)
将待写入的数据发送出去。 -
结束通信:随后,我们调用了
Wire.endTransmission()
来结束I2C通信。这意味着我们已经将数据和地址都传送给了外部EEPROM设备。实际上,这是向设备发送了一个写入请求。 -
等待写入完成:为确保写入操作成功完成,我们添加了
delay(5)
。这个短暂的等待时间允许EEPROM完成数据写入的操作,确保数据被正确存储。
需要注意的是,EEPROM写入通常需要一些时间,所以在调用writeEEPROM
函数后,等待一段时间非常重要。EEPROM的写入周期可以从设备的规格表中获知。
2. 读操作
当我们使用readEEPROM
函数时,我们与外部EEPROM设备通过I2C总线建立了通信,以从特定地址的存储单元读取数据。以下是readEEPROM
函数的步骤解释:
-
开始通信:首先,我们使用
Wire.beginTransmission(EEPROM_ADDR)
开启I2C通信,发送了一个起始信号,这表明读取操作的开始。在这里,EEPROM_ADDR
是外部EEPROM设备的I2C地址。 -
发送地址:然后,我们使用
Wire.write((int)highByte(address))
发送地址的高字节部分。这个高位地址指示了我们希望读取数据的确切存储单元。 -
发送低位地址:接下来,我们使用
Wire.write((int)lowByte(address))
发送地址的低字节部分。这个低位地址更精确地指明了读取的位置。 -
结束通信:随后,我们调用了
Wire.endTransmission()
来结束I2C通信。这意味着我们已经向外部EEPROM设备发送了读取请求。 -
请求数据:然后,我们使用
Wire.requestFrom(eepromAddress, 1)
请求从EEPROM读取1字节数据。 -
等待数据:我们使用
while (Wire.available() == 0)
来等待数据的到达。这确保了在数据准备好之前,我们不会继续执行。 -
获取数据:一旦数据可用,我们使用
Wire.read()
来读取并返回这个数据。
总结:通过readEEPROM
函数,我们使用I2C通信协议成功地从外部EEPROM设备读取数据。我们发送地址和读取请求,然后等待数据的到达。这样,我们能够从EEPROM的指定地址成功地获取数据。
需要注意的是,EEPROM读取也需要一些时间,所以在调用readEEPROM
函数后,等待一段时间也是必要的。EEPROM的读取速度可以从设备的规格表中找到。
三、示例代码
#include <Wire.h>
const byte EEPROM_ADDR = 0x57; // I2C address
#define start 0x25
#define BUF_SIZE 50
char myMessage[BUF_SIZE] = { "Hello, I'll save Data to EEPROM demo." };
char MEM[BUF_SIZE];
void setup() {
Serial.begin(9600);
Wire.begin();
Serial.println();
Serial.println("Writing to Ext.EEPROM...");
for (unsigned int i = 0; i < sizeof(myMessage); i++) {
writeEEPROM(i + start, myMessage[i]);
delay(5);
}
Serial.println("Write Complete.");
Serial.println();
Serial.println("Reading Ext.EEPROM...");
for (unsigned int j = 0; j < sizeof(MEM); j++) {
byte data = readEEPROM(j + start);
Serial.print("Address 0x");
Serial.print(j + start, HEX);
Serial.print(": 0x");
Serial.print(data, HEX);
Serial.print(" '");
if (data >= 32 && data <= 126) {
Serial.print((char)data);
} else {
Serial.print(".");
}
Serial.println("'");
}
Serial.println("Read Complete.");
}
void loop() {
}
void writeEEPROM(unsigned int address, byte data) {
Wire.beginTransmission(EEPROM_ADDR);
Wire.write((int)highByte(address));
Wire.write((int)lowByte(address));
Wire.write(data);
Wire.endTransmission();
delay(5); // wait to complete the write cycle
}
byte readEEPROM(unsigned int address) {
byte data;
Wire.beginTransmission(EEPROM_ADDR);
Wire.write((int)highByte(address));
Wire.write((int)lowByte(address));
Wire.endTransmission();
Wire.requestFrom(EEPROM_ADDR, (byte)1);
while (Wire.available() == 0)
; // wait for data
data = Wire.read();
return data;
}
运行效果: