Publicidade:

terça-feira, 12 de abril de 2016

Arduino - Memória EEPROM - AT24C256

Essa semana postei um artigo no site sistemas embarcados. O Assunto foi memória EEPROM, interna e externa. No caso da memória externa foi abordado o CI AT24C256. Segue o link para o artigo completo: http://www.sistemasembarcados.org/2016/04/arduino-memoria-eeprom.html

Veja também o vídeo sobre o AT24C256.



Veja também o vídeo que mostra a classe feita para facilitar a gravação e leitura da memória:



Código-fonte:

/*
Baseado nos exemplos abaixo:
http://hobbytronics.co.uk/eeprom-page-write
http://playground.arduino.cc/Code/EEPROMWriteAnything

Fabiano A. Arndt
www.youtube.com/fabianoallex
www.facebook.com/dicasarduino
*/

#include <Wire.h>

/*************************************************************************************************************
*******************************CLASSE EE24CXXX - CI I2C EEPROM AT24C128/256***********************************
**************************************************************************************************************/
class EE24CXXX {
  private:
    byte _device_address;
  public:
    EE24CXXX(byte device_address){ _device_address = device_address; }
    void write(unsigned int eeaddress, unsigned char * data, unsigned int data_len);
    void read (unsigned int eeaddress, unsigned char * data, unsigned int data_len);
    
    template <class T> int write(unsigned int eeaddress, const T& value);
    template <class T> int read(unsigned int eeaddress, T& value);
};

void EE24CXXX::write(unsigned int eeaddress, unsigned char * data, unsigned int data_len) {
  unsigned int  address;
  unsigned int  page_space;
  unsigned int  page=0;
  unsigned int  num_writes;
  unsigned char first_write_size;
  unsigned char last_write_size;  
  unsigned char write_size;  
  
  page_space = int(((eeaddress/64) + 1)*64)-eeaddress;      // Calculate space available in first page

  if (page_space>16) {                                      // Calculate first write size
     first_write_size = page_space-((page_space/16)*16);
     if (first_write_size==0) { first_write_size=16; }
  } else {
    first_write_size = page_space; 
  }
  if (data_len>first_write_size)  { last_write_size = (data_len-first_write_size)%16;   }      // calculate size of last write  
  num_writes = (data_len>first_write_size) ? ((data_len-first_write_size)/16)+2 : 1;           // Calculate how many writes we need
     
  unsigned char i=0, counter=0;
  address = eeaddress;
  for (page=0; page<num_writes; page++)  {
    if (page == 0) { 
      write_size = first_write_size; 
    } else if(page == (num_writes-1)) { 
      write_size = last_write_size;
    } else { 
      write_size = 16;
    }
 
    Wire.beginTransmission(_device_address);
    Wire.write((int)((address) >> 8));   // MSB
    Wire.write((int)((address) & 0xFF)); // LSB
    counter = 0;
    do { 
      Wire.write((byte) data[i++]);
      counter++;
    } while(counter<write_size);
    Wire.endTransmission();
    address += write_size;   // Increment address for next write
     
    delay(5);  // needs 5ms for page write
  }
}

void EE24CXXX::read(unsigned int eeaddress, unsigned char * data, unsigned int data_len){
  unsigned char i = 0;
  unsigned int size = data_len;
  unsigned int j=0;
  while (size > 0){
    Wire.beginTransmission(_device_address);
    eeaddress += j*28;
    
    Wire.write((int)(eeaddress >> 8));   // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    
    if (size >= 28) { 
      Wire.requestFrom(_device_address, (unsigned int) 28);
      size -= 28;
    } else {
      Wire.requestFrom(_device_address, (unsigned int) size);
      size = 0;
    }
    while(Wire.available()) { data[i++] = Wire.read(); }
    j++;
  }
}

template <class T> int EE24CXXX::write(unsigned int eeaddress, const T& value) {
  const byte* p = (const byte*)(const void*)&value;
  unsigned char data[sizeof(value)+1];
  for (int i=0; i<sizeof(value); i++) { data[i] = *p++; }
  data[sizeof(value)] = '\n';
  write(eeaddress, data, sizeof(value));
  return sizeof(value);
}

template <class T> int EE24CXXX::read(unsigned int eeaddress, T& value) {
  byte * p = (byte*)(void*)&value;
  unsigned char c[sizeof(value)];
  read(eeaddress, c, sizeof(value));
  for (int i=0; i<sizeof(value); i++) { *p++ = c[i]; }
  return sizeof(value);
}
/*************************************************************************************************************
*******************************FIM - CLASSE EE24CXXX - CI I2C EEPROM AT24C128/256*****************************
**************************************************************************************************************/

EE24CXXX m(0x50);

struct teste{
  int a;
  int b;
  int c;
};

void setup() {
  Serial.begin(9600);
  Wire.begin();  
  
  char i[] = {"1234567890"};
  char j[10];

  m.write(18522, i);              //grava na memória a quantidade de bytes ocupada pelo tipo de dados passado
  
  int count = m.read(18522, j);   //carrega da memória a quantidade de bytes 
  
  Serial.print("Quant: ");
  Serial.println(count);
  Serial.print("Valor: ");
  Serial.println(j);
}

void loop() { }


3 comentários:

  1. Nossa muito bom o artigo. Meus parabéns, estava atrás de algo assim, já que sou novo no mundo dos microcontroladores e estava bolando um projeto de para minha empresa chamado sequenciador de mangas. O projeto consiste em verificar a saturação dentro da câmara e em modo automático regular o tempo do disparo e o tempo de cada disparo.
    Para isso tenho que incluir um menu de parametrização.
    Pois bem, acho que meu projeto vai ultrapassar os 32Kbytes do arduíno uno que eu quero utilizar no projeto.
    Desde já muito grato.
    E novamente parabéns

    ResponderExcluir
  2. Meus parabéns, material muito bom. Pelo que entendi o seu código trata os dados de forma dinâmica pelo tipo do dado, mas sempre no endereço 18522, mas como seria se os endereços fossem dinâmicos também? Um sequência de gravação, exemplo: um sistema de medidor de temperatura que grava a temperatura por minuto ao longo do dia para recuperar depois, vc pode me ajudar a entender como tratar os endereçamentos por favor

    ResponderExcluir
    Respostas
    1. 18522 é apenas um exemplo de uso da classe. Mas claro que não é pra ser usados apenas nesse endereço. Mas para o seu caso, acho que o mais indicado é gravar em um cartão de memória, já que eeproms têm um número limitado de escritas (100.000 aprox. se não me engano), então quando se trata de gravar de minuto em minuto elas não são as melhores opções.

      Excluir