Fork me on GitHub

Microcontrolandos

O Blog está passando por uma fase de mudanças. Todos os posts estão sendo atualizados, códigos, links e imagens estão sendo arrumados. Conteúdos novos ainda estão por vir.

PIC: EEPROM I2C

Share:

PIC: EEPROM I2C



Neste post, irei falar sobre como trabalhar com memórias externas.

24C32

Esta memória possui as seguintes características:
  • Comunicação via protocolo I2C;
  • Possui uma memória de 32K(4096 x 8);
  • Vida útil de mais de 1000000 de ciclos de escrita;
  • Data Protect;
  • Pode-se conectar até 8 memórias no mesmo barramento.
Para fazer a escrita ou leitura é necessário seguir esta sequência:


CONTROL BYTE é formado pelo SLAVE ADDRESS(1010), pelo DEVICE SELECT(A2, A1, A0) e um comando (Escrita = 0, Leitura = 1).

Veja que o DEVICE SELECT é definido ligando os pinos A2, A1 e A0 da memória.

O pino WP quando no nível alto, projete a memória contra a gravação.

DOWNLOAD:
Projeto: I2C_Eeprom.zip

BIBLIOTECA:
#define Lo(param) ((char *)&param)[0]
#define Hi(param) ((char *)&param)[1]

void Eeprom_24C32A_WriteByte(char DEVICE, unsigned address, char wData)
{
   I2C1_Start();// Envia um sinal de Start
   I2C1_Wr(0xA0 | (DEVICE << 1));//Envia o endereço, device e comando de escrita
   I2C1_Wr(Hi(address)); //envia o byte mais significativo do endereço
   I2C1_Wr(Lo(address)); //envia o byte menos significativo do endereço
   I2C1_Wr(wData); //envia o dado a ser gravado
   I2C1_Stop(); //sinal de stop
   Delay_ms(5); //tempo de uma gravação
}

char Eeprom_24C32A_ReadByte(char DEVICE, unsigned address)
{
char rData;
   I2C1_Start();
   I2C1_Wr(0xA0 | (DEVICE << 1));
   I2C1_Wr(Hi(address));
   I2C1_Wr(Lo(Address));
   I2C1_Repeated_Start();
   I2C1_Wr(0xA1 | (DEVICE << 1));//Envia o endereço, device e comando de leitura
   rData = I2C1_Rd(0);
   I2C1_Stop();
   return rData;
}

void Eeprom_24C32A_WriteString(char DEVICE, unsigned address, char *wData)
{
  while(*wData != 0)
  {
    Eeprom_24C32A_WriteByte(DEVICE, address++, *(wData++));
  }
}

void Eeprom_24C32A_ReadString(char DEVICE, unsigned address, char *rData, char Size)
{
char i;
 while(i < Size)
 {
    rData[i++] = Eeprom_24C32A_ReadByte(DEVICE, address++);
 }
}

char Eeprom_24C32A_Connected(char DEVICE)
{
char ack;
     I2C1_Start();
     ack = I2C1_Wr(0xA0 | (DEVICE << 1));//retorna 0 se nao houver erro
     I2C1_Stop();
     return !ack;
}

EXEMPLO
char nome[16];

void main()
{
    I2C1_Init(100000);//inicia modulo i2c
    UART1_Init(9600);
    delay_ms(10);
    Eeprom_24C32A_WriteByte(0, 0, 0x05);//escreve o valor 0x05 no endereço 0 do dispositivo 0
    Eeprom_24C32A_WriteByte(1, 0, 0x01);//escreve o valor 0x01 no endereço 0 do dispositivo 1
    Eeprom_24C32A_WriteString(0, 1, "TiagoHenrique");//escreve uma string a partir do endereço 1
    Eeprom_24C32A_ReadString(0, 1, nome, 13);//faz a leitura de 13 caracter a partir do endereço 1
    Uart1_write_text(nome);
}


24C04




Esta memória possui as seguintes características:
  • Comunicação via protocolo I2C;
  • Possui uma memória de 4K(512 x 8);
  • Vida útil de mais de 1000000 de ciclos de escrita;
  • Data Protect;
  • Pode-se conectar até 4 memórias no mesmo barramento.
a sequencia de escrita e leitura é a mesma para o 24C32, mas o CONTROL BYTE diferencia pelo bit 1, que é o bit de seleção do banco de memória.

BIBLIOTECA
void Eeprom_24C04_WriteByte( char DEVICE, unsigned Address, char _data )
{
   I2C1_Start();// Envia um sinal de Start
   //Envia o device, Select Bank, e comando de escrita
   I2C1_Wr(0xA0 | (DEVICE << 2) | ( ((char*)&Address)[1].B0 << 1) );
   I2C1_Wr( ((char*)&Address)[0] ); //envia o endereço
   I2C1_Wr( _data ); //envia o dado a ser gravado
   I2C1_Stop(); //sinal de stop
   Delay_ms(5); //tempo de uma gravação
}

char Eeprom_24C04_ReadByte( char DEVICE, unsigned Address )
{
char device_addr = 0xA0 | (DEVICE << 2) | ( ((char*)&Address)[1].B0 << 1);
char _data;
   I2C1_Start();// Envia um sinal de Start
   //Envia o device, Select Bank, e comando de escrita
   I2C1_Wr( device_addr );
   I2C1_Wr( ((char*)&Address)[0] ); //envia o endereço
   I2C1_Repeated_Start();
   I2C1_Wr( device_addr | 1 );
   _data = I2C1_Rd(0);
   I2C1_Stop(); //sinal de stop
   return _data;
}

31 comentários:

  1. ola
    gostei do blog ta show.

    agora me diz como faço para gravar um valor de 32bit ex um valor de 0 ate 999999 utilizando a memoria 24c04 ,você poderia postar um exemplo pra mim ter uma noção ? Pois ainda sou iniciante em C

    obrigado

    ResponderExcluir
    Respostas
    1. Olá, obrigado.

      um valor de 32bits possui 4 bytes, entao voce tem que enviar um byte de cada vez.

      ((char*)&Valor)[0] - é o byte menos significativo ( 0xDD )
      ((char*)&Valor)[3] - é o byte mais significativo ( 0xAA )

      Exemplo:
      unsigned long Valor = 0xAABBCCDD;

      for( i = 0 ; i < 4 ; i++ )
      {
      Eeprom_24C04_WriteByte( _device, _address++, ((char*)&Valor)[i] );
      }

      Excluir
    2. Ola não entendi ,eu tenho um codigo simples por ex um receptor de fm que funciona em 88,000 ate 108000 mhz,queria gravar frequencias preferidas na memoria eeprom do pic ,seria possível me dizer como devo proceder uma rotina para fazer isso ?

      ex
      88000 =00000000 00000001 01010111 11000000
      108000=00000000 00000001 10100101 11100000

      Excluir
    3. unsigned long frequencia = 88000;

      //Grava no endereço 0, o byte menos significativo
      Eeprom_24C04_WriteByte( DEVICE, 0, ((char*)&Frequencia)[0] ); //00000000
      //Grava no endereço 1, o segundo byte
      Eeprom_24C04_WriteByte( DEVICE, 1, ((char*)&Frequencia)[1] ); //00000001
      //Grava no endereço 2, o terceiro byte
      Eeprom_24C04_WriteByte( DEVICE, 2, ((char*)&Frequencia)[2] ); //01010111
      //Grava no endereço 3, o byte mais significativo
      Eeprom_24C04_WriteByte( DEVICE, 3, ((char*)&Frequencia)[3] ); //11000000

      Para fazer a leitura
      ((char*)&Frequencia)[0] = Eeprom_24C04_ReadByte( DEVICE, 0 );
      ((char*)&Frequencia)[1] = Eeprom_24C04_ReadByte( DEVICE, 1 );
      ((char*)&Frequencia)[2] = Eeprom_24C04_ReadByte( DEVICE, 2 );
      ((char*)&Frequencia)[3] = Eeprom_24C04_ReadByte( DEVICE, 3 );

      Excluir
    4. Ok ,deu pra entender ,se caso eu resolver gravar na memoria eeprom do pic ,e o mesmo procedimento ?

      Excluir
    5. posso enviar para o seu email o Código fonte para que voce possa analisar ?

      Excluir
    6. Para realizar a gravação na eeprom pode utilizar o mesmo procedimento. E pode enviar pro meu email sim.

      Excluir
  2. Ola amigo fiz assim mais não funciona

    void grava (void)
    //Gravar
    {
    EEPROM_Write(0,(unsigned char)((freq & [0]);//>>24));
    EEPROM_Write(1,(unsigned char)((freq & [1]);//>>16));
    EEPROM_Write(2,(unsigned char)((freq& [2]);//>>8));
    EEPROM_Write(3,(unsigned char)((freq & [3]);
    //////////////////////////////////////////////////////

    }

    void leitura (void)
    //Ler
    {
    freq = (unsigned long)(EEPROM_Read(0)<<24);
    freq = (unsigned long)(EEPROM_Read(1)<<16);
    freq = (unsigned long)(EEPROM_Read(2)<<8);
    freq = (unsigned long)(EEPROM_Read(3));
    }*/

    ResponderExcluir
    Respostas
    1. tem que ser assim:

      void grava (void)
      //Gravar
      {
      EEPROM_Write(0, ((char*)&freq)[0] ); //byte menos significativo
      EEPROM_Write(1, ((char*)&freq)[1] );
      EEPROM_Write(2, ((char*)&freq)[2] );
      EEPROM_Write(3, ((char*)&freq)[3] ); //byte mais significativo
      //////////////////////////////////////////////////////

      }

      void leitura (void)
      //Ler
      {
      ((char*)&freq)[0] = EEPROM_Read(0); //byte menos significativo
      ((char*)&freq)[1] = EEPROM_Read(1);
      ((char*)&freq)[2] = EEPROM_Read(2);
      ((char*)&freq)[3] = EEPROM_Read(3); //byte mais significativo
      }

      Excluir
    2. Explicação:
      ( (char*) &freq )[0]
      (char*) - Cria um ponteiro e aponta para o endereço de "freq" &freq . Um valor será gravado no endereço de "freq" + 0 [0]

      Excluir
  3. Ola poderia me ajudar com devo proceder para incrementar um botao para alterar a banda do radio ?

    pressiona o botao entra no loop do programa pressiona novamente sai do loop ,a função seria alterar a banda do radio fm/am seria bom também memorizar o estado da chave na eeprom .

    obrigado

    ResponderExcluir
  4. Boa tarde. Quanto a ligação entre um PIC18F2550 e um 24C32, é obrigatório ligar nos pinos SDA e SCL do PIC ou se ligar em outros pinos do PIC vai funcionar também?


    Att,

    ResponderExcluir
    Respostas
    1. Isso vai depender de como voce ira programar. Se voce utilizar o módulo I2C interno do pic para realizar a comunicação I2C, DEVERÁ utilizar os pinos SDA e SCL, pois são os pinos do módulo.
      Você também pode emular o I2C( principalmente em pics que não suportam o I2C ) na qual você pode utilizar quaisquer pino. Para emular você utiliza a biblioteca "Soft_I2C" do MikroC PRO PIC.

      Excluir
  5. OLa

    Voce teria uma biblioteca pronta para incluir memoria 24c04 ,vi a sua mais aqui não funcionou me parece que e para ser utilizada com mais de 1 eprom não e isso ? seria Possível fazer para usar somente 1 eeprom ?

    obrigado

    ResponderExcluir
    Respostas
    1. Esta biblioteca pode comandar ate 4 memorias eeproms. Verifica se definiu o endereço do dispositivo no barramento corretamente.

      Excluir
    2. acho que sim amigo ,veja abaixo a blioteca e minha rotina .


      void Eeprom_24C04_WriteByte( char DEVICE, unsigned Address, char _data )
      {
      Soft_I2C_Start();// Envia um sinal de Start
      //Envia o device, Select Bank, e comando de escrita
      Soft_I2C_Write(0xA0 | (DEVICE << 2) | ( ((char*)&Address)[1].B0 << 1) );
      Soft_I2C_Write( ((char*)&Address)[0] ); //envia o endereço
      Soft_I2C_Write( _data ); //envia o dado a ser gravado
      Soft_I2C__Stop(); //sinal de stop
      Delay_ms(5); //tempo de uma gravação
      }
      char Eeprom_24C04_ReadByte( char DEVICE, unsigned Address )
      {
      char device_addr = 0xA0 | (DEVICE << 2) | ( ((char*)&Address)[1].B0 << 1);
      char _data;
      Soft_I2C_Start();// Envia um sinal de Start
      //Envia o device, Select Bank, e comando de escrita
      Soft_I2C_Write( device_addr );
      Soft_I2C_Write( ((char*)&Address)[0] ); //envia o endereço
      Soft_I2C_Start();
      Soft_I2C_Write( device_addr | 1 );
      _data = I2C1_Rd(0);
      Soft_I2C_Stop(); //sinal de stop
      return _data;
      }

      /////////minha rotina para ler e gravar////////////

      void salvarm (void)
      //Gravar
      {
      nr=chl*4; //variar o valor da eeprom para gravação. Inicia com o zero
      Eeprom_24C04_WriteByte(nr, ((char*)&freq)[0] ); //byte menos significativo
      Eeprom_24C04_WriteByte(nr+1, ((char*)&freq)[1] );
      Eeprom_24C04_WriteByte(nr+2, ((char*)&freq)[2] );
      Eeprom_24C04_WriteByte(nr+3, ((char*)&freq)[3] ); //byte mais significativo
      //delay_ms(20);
      //////////////////////////////////////////////////////
      //grava_lcd();
      if (nr <= 4){
      nr = 4;
      }
      if (nr > 80){
      nr = 80;
      }

      if (chl <= 1){
      chl = 1;
      }
      if (chl > 20){
      chl = 20;
      }
      grava_lcd();
      }

      void leituram (void)
      //Ler
      {
      nr=chl*4; //variar o valor da eeprom para gravação. Inicia com o zero
      ((char*)&freq)[0] = Eeprom_24C04_ReadByte(nr); //byte menos significativo
      ((char*)&freq)[1] = Eeprom_24C04_ReadByte(nr+1);
      ((char*)&freq)[2] = Eeprom_24C04_ReadByte(nr+2);
      ((char*)&freq)[3] = Eeprom_24C04_ReadByte(nr+3); //byte mais significativo
      //delay_ms(90);

      if (nr <= 4){
      nr = 4;
      }
      if (nr > 80){
      nr = 80;

      }
      if (chl <= 1){
      chl = 1;
      }
      //}
      if (chl >=20){
      chl = 20;
      }
      ler_lcd();
      }


      Excluir
  6. Como eu faria para escrever 3 nomes na 24C04, e que tivessem dois botões, clicando no primeiro botão eu ficaria mostrando os nomes da memória em um lcd 16x2, e apertando o segundo eu apagaria e gravaria esses nomes?

    ResponderExcluir
  7. Olá, o blog é muito bom!
    Mas tenho uma dúvida, gostaria de escrever no meu PIC (não importando qual memória) Dados provenientes das entradas analógicas dele. Como posso proceder?

    ResponderExcluir
  8. Olá, muito boa sua biblioteca, parabéns, funciona certinho.
    Só uma dúvida que tenho aqui, como eu faria para guardar uma imagem gerada pelo utilitário do KS0108 dentro da eeprom? e como ler ela depois?

    ResponderExcluir
    Respostas
    1. Primeiro voce deve gravar a imagem dentro da eeprom utilizando um gravador de EEPROM.
      Depois para ler,você usa as funções da biblioteca acima.

      Excluir
    2. Obrigado pela velocidade da resposta, mas como eu não tenho um gravador de eeprom, pensei em fazer o seguinte:

      Método preguiçoso: Compilo o código com duas imagens e mando escrever elas na eeprom pelo próprio PIC, em tempo de execução. Troco os vetores das imagens, trocos os endereços, compilo, e escrevo elas na eeprom... E assim por diante, até ter todas na eeprom, aí faço o programa que só lê e joga no meu LCD... Será que dá certo?

      Excluir
    3. Dá certo sim :) É melhor do que comprar um gravador né!

      Excluir
    4. Sim rsrs... Obrigadão... Abraços.

      Excluir
    5. ola, vc conseguiu fazer leitura das imagem do glcd , mas como consigo ler varias imagem dentro da memoria AT24c512

      Excluir
  9. Amigo para 24c1024 ou 24c512 seria a mesma coisa ou mudaria algo no hardware e software ,se não vc poderia me dar um exemplo.Desde já agradeço.

    ResponderExcluir
  10. Olá gostaria de saber como faço pra criar um código para sensor de irrigação usando microcontrolador pic12f675 usando compilador mikroC.

    ResponderExcluir
  11. como eu faço para incluir outra memoria que não sejam as citadas acima? exemplo, se eu quisesse usar uma 24lc512? somente ela sem outra memoria junto

    ResponderExcluir
  12. Uma ideia era o projeto de um sensor de irrigação inteligente. Uma boa tarde

    ResponderExcluir