您现在的位置是:首页 > 科技前沿

在Arduino中使用内部或外部 EEPROM来保存设置及其它数据

智慧创新站 2025-04-12【科技前沿】8人已围观

简介本文英文原创:DronebotWorkshop翻译整理:DIY百事目录1简介2了解EEPROM2.1非易失性存储器类型2.2EEPROM限制3带有Arduino的EEPROM–两种类型3.1内部EEPROM3.2外部EEPROM4使用内部EEPROM4.1ArduinoEEPROM库4.1.1EEP...

本文英文原创:DronebotWorkshop
翻译整理:DIY百事

目录

1简介
2了解EEPROM
2.1非易失性存储器类型
2.2EEPROM限制

3带有Arduino的EEPROM–两种类型
3.1内部EEPROM
3.2外部EEPROM

4使用内部EEPROM
4.1ArduinoEEPROM库
4.1.1EEPROM更新
4.1.2EEPROM读取
4.1.3EEPROM清除

5使用外部EEPROM
5.1AT24LC256EEPROM
5.1.1AT24LC256模块
5.2外部EEPROM连接
5.3外部EEPROMArduino代码
5.3.1运行外部EEPROM代码

6结论

介绍

计算机和微控制器需要内存来永久或临时存储数据,虽然这种内存可以有多种形式,但它可以分为两种基本类型——易失性和非易失性。

易失性存储器通常采用RAM或随机存取存储器的形式。这是您设备的“工作”内存,它保存程序运行期间使用的临时数据。一旦断电,内存就会被清除。

正如您现在可能已经猜到的那样,非易失性存储器即使在断电后也会保留其数据。有多种不同类型的非易失性存储器,今天我们将研究其中一种——电可擦可编程只读存储器(EEPROM)。

具体来说,我们将研究如何在Arduino中使用EEPROM。

了解EEPROM

还有许多其他形式的非易失性存储器,包括闪存、SD卡、USB驱动器、硬盘驱动器和SSD。那么EEPROM有什么特点呢?

与上述存储器类型相比,EEPROM的存储量非常小,事实上,EEPROM容量通常以比特而不是字节来衡量。由于它们只存储少量数据,因此不会消耗大量电流,因此非常适合电池和低功耗应用。

EEPROM是在1970年代初开发的,第一个EEPROM在1975年获得了NEC的专利。

非易失性内存类型

EEPROM是使用浮栅晶体管阵列构成的,每个位有两个晶体管。它是ROM或只读存储器系列设备的一部分。

EEPROM与闪存FlashMemory类似,不同之处在于闪存更大,使用更大的数据块。这是以牺牲寿命或重写或“写入周期”为代价的,闪存只能重写大约10,000次。

Arduino微控制器使用闪存来存储上传到其中的程序。Arduino也有内部EEPROM,我们很快就会看到。

ROM系列的其他成员包括:

ROM——只读存储器。这些芯片在制造过程中进行了编程,无法更改。

PROM——可编程只读存储器。这些芯片可以使用特殊设备进行编程,但是不能擦除和重新编程。

EPROM——可擦除可编程只读存储器。与PROM一样,EPROM需要特殊的编程设备。这种类型的存储芯片可以使用紫外线擦除,然后重新使用。

由于它不需要外部编程或“烧录”设备,因此EEPROM是这些设备中最容易使用的。

EEPROM限制

在您的设计中使用EEPROM时还需要考虑一些限制。

与闪存一样,EEPROM的写入周期数有限。您可以随意读取它们,但您只能写入或重写数据给定的次数。

普通EEPROM的写入周期限制约为10万到200万次写入周期。

几十万甚至几百万的写入周期听起来可能很多,但考虑一下现代微控制器或微处理器写入数据的速度有多快,您很快就会意识到它可能会成为一个严重的限制。如果您每秒重写一次EEPROM,并且它的写入次数为10万次,那么您将在一天多一点的时间内耗尽其寿命!

使用EEPROM进行设计时,您会希望尽可能少地写入设备。另一种技术,我们稍后会讨论,是在写入之前先读取该位——如果它已经是正确的值,那么就没必要重写它。

另一个EEPROM限制是数据保存时间。EEPROM技术在不断改进,今天的EEPROM可以在室温下将数据保存大约10年。重写该数据则重新计算,从而延长数据保存时间。

最后,一个明显的限制是EEPROM的存储容量,与其他存储设备相比,它非常小。但是,由于EEPROM最常见的用途是保留配置和校准数据,因此问题不大。

Arduino两种类型的EEPROM

在我们的Arduino设计中添加EEPROM可以让我们的项目在断电后保留数据。这对于需要校准或存储用户设置的应用程序非常有用。

内部EEPROM

我们可以很容易地将EEPROM功能添加到我们的Arduino项目中。事实上,Arduino已经有一些我们可以在程序中使用的内部EEPROM。内存量取决于我们使用的Arduino模型。

下面说明了一些流行的Arduino模型中内部EEPROM的数量:

微控制器EEPROM容量
Atmega2560(ArduinoMega2560)4096字节
ATmega328(ArduinoUno、Mini,Nano)1024字节
ATmega168(Nano)512字节

在许多设计中,这种低容量的非易失性存储器就足够了。

外部EEPROM

如果您的设计需要更多EEPROM容量,那么您可以添加一个外部EEPROM。

由于EEPROM在位级别上运行,它们通常设计为使用串行数据,换句话说,一次传输一位的数据。这导致了许多基于I2C的EEPROM设备的开发。

使用带有Arduino的I2CEEPROM设备非常简单,因为Arduino已经连接了I2C和库以使用它们。许多I2CEEPROM可以配置为唯一地址,允许您在同一电路中使用多个设备。

外部I2CEEPROM的优点是它们具有比Arduino内部EEPROM限制的10万次写入更大的寿命。

使用内部EEPROM

我们将使用Arduino中的内部EEPROM开始我们的EEPROM实验。对于我们的实验,我使用的是ArduinoUno,但如果您愿意,可以替换为不同的Arduino。

为了演示内部EEPROM,我们将在Arduino中添加一个电位器,将其连接到模拟输入端口之一。下面是接线图:

连接后,将Arduino连接到运行ArduinoIDE的计算机。

ArduinoEEPROM库

使用ArduinoIDE中已经包含的ArduinoEEPROM库将大大简化我们的实验。

该库带有许多简短的示例代码。我们可以使用它们来试验Arduino的内部EEPROM。请注意,该库仅适用于内部EEPROM,要使用外部设备将需要不同的库。

为了在ArduinoIDE中使用示例程序,请执行以下步骤:

启动ArduinoIDE。

选择示例。将出现一个子菜单。

选择EEPROM。将出现一个额外的子菜单。

您可以从子菜单中选择一个示例。

该库包含八个示例,其中的代码将帮助您编写自己的代码以使用Arduino内置EEPROM。这里有一些你可以尝试:

EEPROM更新

虽然有一个EEPROM写入代码,但在将数据写入EEPROM时,使用更新方法是更好的选择。这是因为这种方法先读取EEPROM的值,如果不一样才更新,实际上它只是Read和Write方法的结合。

通过这样做可以减少对EEPROM的写入次数。

/***,itisno***///startreadingfromthefirstbyte(address0)oftheEEPROMintaddress=0;bytevalue;voidsetup(){//initializeserialandwaitforporttoopen:(9600);while(!Serial){;//等待串口连接}}voidloop(){//readabytefromthecurrentaddressoftheEEPROMvalue=(address);(address);("\t");(value,DEC);();/***Advancetothenextaddress,,:-ArdunoDuemilanove:512bEEPROMstorage.-ArduinoUno:1kbEEPROMstorage.-ArduinoMega:4,***/address=address+1;if(address==()){address=0;}/***AstheEEPROMsizesarepowersoftwo,wrapping(preventingoverflow)ofanEEPROMaddressisalsodoablebyabitwiseandofthelength-1.++address=()-1;***/delay(500);}

代码只是读取EEPROM并将数据打印到串行监视器。因此,如果您要在上一个代码之后运行它,您应该会看到电位器运动产生的值。

该代码使用制表符(“\t”)很好地格式化显示,显示每个EEPROM位置的地址和数值。

EEPROM清除

EEPROM清除代码将EEPROM中的所有值重置为零

/**EEPROMClear**SetsallofthebytesoftheEEPROMto0.*Pleaseseeeeprom_iterationforamoreindepth*lookathowtotraversetheEEPROM.**Thisexamplecodeisinthepublicdomain.*/include""//IncludetheServoLibrarydefineEEPROM_I2C_ADDRESS0x50//AnalogpinforpotentiometerintanalogPin=0;//Integertoholdpotentiometervalueintval=0;//BytetoholddatareadfromEEPROMintreadVal=0;//Integertoholdnumberofaddressestofillintmaxaddress=1500;//CreateaServoobjectServomyservo;//FunctiontowritetoEEPROOMvoidwriteEEPROM(intaddress,byteval,inti2c_address){//(i2c_address);//((int)(address8));//((int)(address0xFF));//LSB//(val);//();//Add5msdelayforEEPROMdelay(5);}//FunctiontoreadfromEEPROMbytereadEEPROM(intaddress,inti2c_address){//DefinebyteforreceiveddatabytercvData=0xFF;//(i2c_address);//((int)(address8));//((int)(address0xFF));//LSB//();//(i2c_address,1);//ReadthedataandassigntovariablercvData=();//ReturnthedataasfunctionoutputreturnrcvData;}voidsetup(){//();//(9600);//(9);//("StartRecording");//Rununtilmaximumaddressisreachedfor(intaddress=0;address=maxaddress;address++){//Readpotandmaptorangeof0-180forservoval=map(analogRead(analogPin),0,1023,0,180);//Writetotheservo//(val);delay(15);//RecordthepositionintheexternalEEPROMwriteEEPROM(address,val,EEPROM_I2C_ADDRESS);//("ADDR=");(address);("\t");(val);}//("RecordingFinished!");//Delay5Secondsdelay(5000);//("BeginPlayback");//Rununtilmaximumaddressisreachedfor(intaddress=0;address=maxaddress;address++){//ReadvaluefromEEPROMreadVal=readEEPROM(address,EEPROM_I2C_ADDRESS);//Writetotheservo//Delaytoallowservotosettleinposition//(readVal);delay(15);//("ADDR=");(address);("\t");(readVal);}//("PlaybackFinished!");}voidloop(){//Nothinginloop}

与内部EEPROM不同,我们将使用I2C的ArduinoWire库以及Servo库。这两个库都已包含在您的ArduinoIDE中。

包含所需的库后,我们设置了一些常量和变量。

EEPROM_I2C_ADDRESS–表示EEPROMI2C地址的常量,在我们的例子中是十六进制50。

模拟引脚——连接到电位器抽头的引脚,在本例中为A0。

val–一个整数,用于表示记录期间发送到伺服电机的值。

readVal–一个整数,用于表示播放期间发送到伺服电机的值。

maxaddress–我们要使用的最高地址位置。如果您希望可以增加此值,我使用1500来最小化运行演示所需的时间。

然后我们创建一个名为myservo的伺服对象来表示电机。

接下来,我们定义两个函数,writeEEPROM和readEEPROM,它们分别执行我们的EEPROM写入和读取。

writeEEPROM函数将存储器地址、您希望写入该地址的数据和EEPROMI2C地址作为输入。然后它连接到EEPROM并将存储器地址作为两个独立字节传递。这是因为I2C总线一次只允许您传输一个地址字节。

接下来,我们将希望记录的值放到I2C总线上。之后,我们结束传输。

我还在写入后添加了5ms的延迟,因为EEPROM需要在写入之间这样做。

readEEPROM函数将存储器地址和I2C地址作为输入。然后它连接到I2C总线,传递地址信息并结束传输。这会导致EEPROM将指定地址的数据放入其输出缓冲区,以供主机读取。我们读取该值,然后将其输出以结束函数。

setup是我们将所有内容放在一起的地方。

我们首先连接到I2C总线作为主机,设置串行监视器并连接到引脚9上的伺服电机。

打印到串行监视器后,我们进入for-next循环,遍历所有地址。在每个地址上,我们从连接电位器的模拟端口捕获值,并将其转换为伺服电机的0-180值。

我们写入伺服器并允许它延迟15ms以使其就位。然后我们将值写入EEPROM并将其打印到串行监视器。

循环浏览地址后,我们再次打印到串行监视器并等待五秒钟。

然后我们再次遍历地址。这次我们读取每个值并将其写入串行监视器和伺服电机。我们再次为伺服提供延迟。

最后,我们打印到串行监视器并结束设置。

由于所有“动作”都发生在setup,因此loop中没有任何事情可做。

运行外部EEPROM代码

将代码加载到您的Arduino并开始转动电位器。您应该相应地观察伺服转动,以及串行监视器上显示的数据。

大约一分钟后,录制将结束。延迟5秒后,电机将开始自行移动,与您记录的模式相同。

您可以对此代码进行许多修改,甚至可以在基础上使用它作为记录器和播放单元,并添加几个按钮和一些状态LED。

或者,作为一个简单的实验,尝试在第一次运行后删除执行记录的代码部分。然后再次运行代码,仅使用播放功能。您应该观察电机以相同的模式转动。然后,您可以关闭所有电源并再次启动Arduino,非易失性EEPROM存储器将使伺服器像以前一样完成它的步伐。

结论

在您的Arduino项目中拥有一些非易失性存储器确实可以增加一个新的维度。如果您只需要存储一些参数,您可以使用Arduinos内部EEPROM。而对于大内存需求,可以使用外部EEPROM。只要记住EEPROM的局限性,不要太频繁地写入它.

很赞哦!(167)