EEPROM
Nayon sok esetben problémát okoz az Arduinok esetén, hogy az adatok alapból nem perzisztálhatók. A perzisztáció azt jelenti, hogy az adatok nem törlődnek újraindítás, komplexebb esetben redundáns átkapcsolás után sem. Az Arduino operatív memóriája teljes mértékben törlődik ilyenkor. A legegyszerűbb megoldás az, hogy az Arduino EEPROM memória-területére tároljuk az ilyen adatokat, vagy egy külső memóriát alkalmazunk adattárolásra, ami lehet akár egy SD kártya is, de egyszerűbb egy külső EEPROM-ot beépíteni. Nyilván a megoldások között segít eligazítani, hogy mennyire akarjuk terhelni az Arduino saját EEPROM-ját, illetve milyen mennyiségű adatot akarunk perzisztálni.
Arduino EEPROM
A különböző Arduino board-ok eltérő méretű EEPROM-mal rendelkeznek:
- ATmega328P: 1024 bájt
- ATmega168: 512 bájt
- ATmega8: 512 bájt
- ATmega1280: 4096 bájt
- ATmega2560: 4096 bájt
Az EEPROM eléréséhez érdemes az EEPROM könyvtár funkcióit felhasználni: https://www.arduino.cc/en/Reference/EEPROM
A belső EEPROM írásánál ügyelni kell arra, hogy az maximum nagyjából 100.000 írásciklusra alkalmaz. Ez talán soknak tűnik, de ha minden ciklusban adatokat próbálunk oda menteni, gyorsan elérhetjük élettartamának a végét. Nyilván érdemes az írásokat nem túl gyakran bekövetkező eseményekhez, vagy idő-triggerhez kötni.
Példaprogram az Arduino EEPROM-hoz
/* * EEPROM Write * * Stores values read from analog input 0 into the EEPROM. * These values will stay in the EEPROM when the board is * turned off and may be retrieved later by another sketch. */ #include <EEPROM.h> /** the current address in the EEPROM (i.e. which byte we're going to write to next) **/ int addr = 0; void setup() { /** Empty setup. **/ } void loop() { /*** Need to divide by 4 because analog inputs range from 0 to 1023 and each byte of the EEPROM can only hold a value from 0 to 255. ***/ int val = analogRead(0) / 4; /*** Write the value to the appropriate byte of the EEPROM. these values will remain there when the board is turned off. ***/ EEPROM.write(addr, val); /*** Advance to the next address, when at the end restart at the beginning. Larger AVR processors have larger EEPROM sizes, E.g: - Arduno Duemilanove: 512b EEPROM storage. - Arduino Uno: 1kb EEPROM storage. - Arduino Mega: 4kb EEPROM storage. Rather than hard-coding the length, you should use the pre-provided length function. This will make your code portable to all AVR processors. ***/ addr = addr + 1; if (addr == EEPROM.length()) { addr = 0; } /*** As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an EEPROM address is also doable by a bitwise and of the length - 1. ++addr &= EEPROM.length() - 1; ***/ delay(100); }
AT24C256 I²C EEPROM IC és modul
Ebben az esetben az EEPROM funkció I²C-n keresztül érhető el. Mivel jó eséllyel úgyis alkalmazunk pár másik Arduino I²C kommunikációs egységet is, így már a memóriakezelés nem fog további értékes pin-eket foglalni. Ennek az IC-nek két változata van, az AT24C128 128 kBit - 16 kByte, míg a AT24C256 256 kBit - 32 kByte címezhető, törölhető, de perzisztens adatterületet tartalmaz. Az írás / olvasás bájtonként vagy laponként (64 bájt) történhet.
AT24C256 technikai adatok
- Tápfeszültség:
- (alacsony feszültésgű mód): 1,8..3,6 V
- (normál feszültésgű mód): 2,7..5,5 V
- Kommunikáció: I²C
- Átlapolás mód: 64 byte
- I²C frekvencia kompatibilitás: 1 MHz (5V), 400 kHz (2,7..2,5V), 100 kHz (1,8V)
- Írásciklusok maximális száma: 1 millió
- Működési hőmérséklet: -55..125 °C
- A lábak feszültségtűrése a GND-hez képest: -1..7 V
- Maximális tápfeszültség: 6,25 V
- Kimeneti áram: 5,0 mA
AT24C256 IC lábkiosztás
A0, A1: I²C cím
SDA: I²C adatport
SCL: I²C órajel port
WP: írásvédelem az IC-re
NC: nincs bekötve
Az IC külön is beszerezhető, de egyszerűbb a modult beszerzi, akkor már nem kell bütykölni az I²C felhúzóellenállásaival, címzés jumperekkel, és a „drótozással”.
AT24C256 címkiosztás
AT24C256 telegram-felépítés
Vezetékezés (modul)
Szoftver
A modulhoz alkalmazásprogram a Githubról is letölthető: https://github.com/cyberp/AT24Cx
/* * Use the I2C bus with EEPROM 24LC64 * Sketch: eeprom.ino * * Author: hkhijhe * Date: 01/10/2010 * * */ #include <Wire.h> void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) { int rdata = data; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.write(rdata); Wire.endTransmission(); } // WARNING: address is a page address, 6-bit end will wrap around // also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) { Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddresspage >> 8)); // MSB Wire.write((int)(eeaddresspage & 0xFF)); // LSB byte c; for ( c = 0; c < length; c++) Wire.write(data[c]); Wire.endTransmission(); } byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) { byte rdata = 0xFF; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(deviceaddress,1); if (Wire.available()) rdata = Wire.read(); return rdata; } // maybe let's not read more than 30 or 32 bytes at a time! void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) { Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(deviceaddress,length); int c = 0; for ( c = 0; c < length; c++ ) if (Wire.available()) buffer[c] = Wire.read(); } void setup() { char somedata[] = "this is data from the eeprom"; // data to write Wire.begin(); // initialise the connection Serial.begin(9600); i2c_eeprom_write_page(0x50, 0, (byte *)somedata, sizeof(somedata)); // write to EEPROM delay(100); //add a small delay Serial.println("Memory written"); } void loop() { int addr=0; //first address byte b = i2c_eeprom_read_byte(0x50, 0); // access the first address from the memory while (b!=0) { Serial.print((char)b); //print content to serial port addr++; //increase address b = i2c_eeprom_read_byte(0x50, addr); //access an address from the memory } Serial.println(" "); delay(2000); }