quarta-feira, 15 de junho de 2011

Usando comunicação I2C no AVR (memoria 24CXX) :

O circuito no simulador proteus:


configurando os fuses:

 
O código fonte :

   1:  //************************************************************************

   2:  //                             usando o protocolo I2C (

   3:  //  Version    : 1.0

   4:  //  microcontrolador : AVR ATMega8
   5:  //  Autor        : Aguivone (fiz só uma adaptação )
   6:  //  descrição  : embora ele seja chamado de two wire interface(TWI) só difere do I2C
   7:  //  pelo numero de endereços (dispositivos) na linha de comunicação.
   8:  //  data : 08/06/11.
   9:  //
  10:  //************************************************************************
  11:  #include <inttypes.h>
  12:  #include <avr/io.h>
  13:  #include <util/twi.h>        /* header que contem algumas macros utilizadas */
  14:   
  15:  #define F_CPU 4000000L    /*frequencia em hz , valor do cristal*/
  16:   
  17:  /*
  18:   * I2C endereços nas 24Cxx EEPROM:
  19:   * 
  20:   * 1 0 1 0 E2 E1 E0 R/~W    24C01/24C02
  21:   * 1 0 1 0 E2 E1 A8 R/~W    24C04
  22:   * 1 0 1 0 E2 A9 A8 R/~W    24C08
  23:   * 1 0 1 0 A10 A9 A8 R/~W    24C16
  24:    assim para escrever por exemplo na memoria 24C16 deve se colocar 1010 + o endereço do banco de memoria que vai acessar +sinaliza se é escrita ou leitura
  25:  
  26:   */
  27:   
  28:  #define ENDE_ESCRITA    0xA0    /* E2 E1 E0 = 0 0 0 banco zero */
  29:  #define PAGE_SIZE 8 // no maximo 8 bytes por linha podem ser escrito(1pagina = 8bytes)
  30:   
  31:  uint8_t twst;
  32:   
  33:  void I2C_inicializar(void)//configura comunicação
  34:  {
  35:            /* 100 kHz clock do barramento I2C, TWPS = 0 => prescaler = 1 */
  36:          #if defined(TWPS0)/* has prescaler (mega128 & newer) */
  37:            {
  38:            TWSR = 0;
  39:            }
  40:          #endif
  41:          #if F_CPU < 3600000UL
  42:            TWBR = 10;            /* menor valor TWBR */
  43:          #else
  44:            TWBR = (F_CPU / 100000UL - 16) / 2; //se a frequencia do clock for maior que 3,6Mhz
  45:          #endif
  46:  }
  47:   
  48:   
  49:  int ler_bytes(uint16_t eeaddr, int len, uint8_t *buf)
  50:  {
  51:    uint8_t sla, twcr, n = 0;
  52:    int rv = 0;
  53:   
  54:    /* busca o endereço de memoria e seleciona qual banco de memoria vai usar */
  55:    sla = ENDE_ESCRITA | (((eeaddr >> 8) & 0x07) << 1);
  56:    restart:
  57:            if (n++ >= 200)//numero maximo de tentativas
  58:              return -1;
  59:    begin:
  60:   
  61:            TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* inicio de transmissao*/
  62:            while ((TWCR & _BV(TWINT)) == 0) ; /* espera interrupção */
  63:            switch ((twst = TW_STATUS))
  64:              {
  65:              case TW_REP_START:        /* OK,pula para proxima etapa*/
  66:              case TW_START:
  67:                break;
  68:   
  69:              case TW_MT_ARB_LOST:    /* informação perdida*/
  70:                goto begin;
  71:   
  72:              default:
  73:                return -1;        /* retorna erro */
  74:                  
  75:              }
  76:   
  77:            /* endeço mais bit de escrita SLA+W */
  78:            TWDR = sla | TW_WRITE;
  79:            TWCR = _BV(TWINT) | _BV(TWEN); /* inicio de transmissao*/
  80:            while ((TWCR & _BV(TWINT)) == 0) ; /* espera interrupção */
  81:            switch ((twst = TW_STATUS))
  82:              {
  83:              case TW_MT_SLA_ACK:
  84:                break;
  85:   
  86:              case TW_MT_SLA_NACK:    /*sem resposta manda reiniciar*/
  87:                goto restart;
  88:   
  89:              case TW_MT_ARB_LOST:    /* re-arbitrate */
  90:                goto begin;
  91:   
  92:              default:
  93:                goto error;        
  94:              }
  95:   
  96:            TWDR = eeaddr;                     /* coloca endereço*/
  97:            TWCR = _BV(TWINT) | _BV(TWEN);     /* limpa interrupção  */
  98:            while ((TWCR & _BV(TWINT)) == 0) ; /* espera para transmitir */
  99:            switch ((twst = TW_STATUS))
 100:              {
 101:              case TW_MT_DATA_ACK:
 102:                break;
 103:   
 104:              case TW_MT_DATA_NACK://se não receber dados aborta transmissao
 105:                goto quit;
 106:   
 107:              case TW_MT_ARB_LOST:
 108:                goto begin;
 109:   
 110:              default:
 111:                goto error;        
 112:              }
 113:   
 114:            /*
 115:             * modo master recebe
 116:             */
 117:            TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /*limpa interrupções*/
 118:            while ((TWCR & _BV(TWINT)) == 0) ; /* espera para inicia transmissaõ*/
 119:            switch ((twst = TW_STATUS))
 120:              {
 121:              case TW_START:        /* OK,vai para proxima etapa*/
 122:              case TW_REP_START:
 123:                break;
 124:   
 125:              case TW_MT_ARB_LOST:
 126:                goto begin;
 127:   
 128:              default:
 129:                goto error;
 130:              }
 131:   
 132:            /* send SLA+R */
 133:            TWDR = sla | TW_READ;
 134:            TWCR = _BV(TWINT) | _BV(TWEN); /* limpa interrupções */
 135:            while ((TWCR & _BV(TWINT)) == 0) ; /*espera para enviar dados */
 136:            switch ((twst = TW_STATUS))
 137:              {
 138:              case TW_MR_SLA_ACK:
 139:                break;
 140:   
 141:              case TW_MR_SLA_NACK:
 142:                goto quit;
 143:   
 144:              case TW_MR_ARB_LOST:
 145:                goto begin;
 146:   
 147:              default:
 148:                goto error;
 149:              }
 150:   
 151:            for (twcr = _BV(TWINT) | _BV(TWEN) | _BV(TWEA) /* Note [13] */;
 152:                 len > 0;
 153:                 len--)
 154:              {
 155:                if (len == 1)
 156:              twcr = _BV(TWINT) | _BV(TWEN); /* envia NACK*/
 157:                TWCR = twcr;        /* limpa interrupções */
 158:                while ((TWCR & _BV(TWINT)) == 0) ; /* espera para enviar dados */
 159:                switch ((twst = TW_STATUS))
 160:              {
 161:              case TW_MR_DATA_NACK:
 162:                len = 0;        /* fim do loop houve falha na resposta*/
 163:              case TW_MR_DATA_ACK:
 164:                *buf++ = TWDR;  //pega dados da memoria
 165:                rv++;
 166:                break;
 167:   
 168:              default:
 169:                goto error;
 170:              }
 171:              }
 172:    quit:
 173:   
 174:            TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* envia stop bit */
 175:   
 176:    return rv;
 177:            error:
 178:            rv = -1;
 179:            goto quit;
 180:  }
 181:   
 182:  ///////////////////////////////////função que escreve 1 pagina(8 bytes)///////////////
 183:   
 184:  int escreve_pagina(uint16_t endereco, int taman, char *dados)
 185:  {
 186:    uint8_t sla, n = 0;
 187:    int rv = 0;
 188:    uint16_t fim_ende;
 189:   
 190:    if (endereco + taman < (endereco | (PAGE_SIZE - 1)))//verifica se cabe na pagina atual
 191:      fim_ende = endereco + taman;
 192:    else
 193:      fim_ende = (endereco | (PAGE_SIZE - 1)) + 1;
 194:      taman = fim_ende - endereco;
 195:   
 196:    /* pega os bits altos da memoria */
 197:    sla = ENDE_ESCRITA  | (((endereco >> 8) & 0x07) << 1);
 198:   
 199:    restart://rotina de reinicio
 200:                if (n++ >= 200)//numero de interações
 201:                  return -1;
 202:    begin:
 203:                TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* limpa interrupções */
 204:                while ((TWCR & _BV(TWINT)) == 0) ; /* espera pra enviar*/
 205:                switch ((twst = TW_STATUS))
 206:                  {
 207:                  case TW_REP_START:        /* OK, vai para proxima etapa */
 208:                  case TW_START:
 209:                    break;
 210:   
 211:                  case TW_MT_ARB_LOST:
 212:                    goto begin;
 213:   
 214:                  default:
 215:                    return -1;        /* inicio de transmissão falhou*/
 216:                              /* não fará uma condição de finalização*/
 217:                  }
 218:   
 219:                /* send SLA+W */
 220:                TWDR = sla | TW_WRITE;//coloca os 8 bits alto do endereço
 221:                TWCR = _BV(TWINT) | _BV(TWEN); /* limpa interrupções para iniciar uma transmissão*/
 222:                while ((TWCR & _BV(TWINT)) == 0) ; /* espera terminar transmissão */
 223:                switch ((twst = TW_STATUS))
 224:                  {
 225:                          case TW_MT_SLA_ACK:
 226:                            break;
 227:   
 228:                          case TW_MT_SLA_NACK:    /* ainda está escrevendo reinicia*/
 229:                            goto restart;
 230:   
 231:                          case TW_MT_ARB_LOST:    /* tentar novamente*/
 232:                            goto begin;
 233:   
 234:                          default:
 235:                            goto error;        /* pede fim de transmissão */
 236:                  }
 237:   
 238:                TWDR = endereco;        /*copia os 8 bits baixo do endereço*/
 239:                TWCR = _BV(TWINT) | _BV(TWEN); /* limpa interrupções para iniciar uma transmissão*/
 240:                while ((TWCR & _BV(TWINT)) == 0) ; /* espera terminar transmissão */
 241:                switch ((twst = TW_STATUS))
 242:                  {
 243:                  case TW_MT_DATA_ACK:
 244:                    break;
 245:   
 246:                  case TW_MT_DATA_NACK:
 247:                    goto quit;
 248:   
 249:                  case TW_MT_ARB_LOST:
 250:                    goto begin;
 251:   
 252:                  default:
 253:                    goto error;        /* pede fim de transmissão */
 254:                  }
 255:   
 256:                    for (; taman > 0; taman--)
 257:                      {
 258:                         TWDR = *dados++;
 259:                         TWCR = _BV(TWINT) | _BV(TWEN); /* limpa interrupções para iniciar uma transmissão*/
 260:                         while ((TWCR & _BV(TWINT)) == 0) ; /* espera terminar transmissão */
 261:                         switch ((twst = TW_STATUS))
 262:                          {
 263:                          case TW_MT_DATA_NACK:
 264:                            goto error;        /* indica que local de memoria é protegido */
 265:   
 266:                          case TW_MT_DATA_ACK:
 267:                            rv++;
 268:                            break;
 269:   
 270:                          default:
 271:                            goto error;
 272:                          }
 273:                      }
 274:    quit: ///rotina para sair 
 275:                    TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* finaliza transmissão*/
 276:   
 277:                    return rv;//retorna o numero de bytes escrito
 278:   
 279:    error:
 280:                    rv = -1;
 281:                    goto quit;
 282:  }
 283:  ////////////////////////////escreve uma frase //////////////////////////////////////////////////////////////////////////
 284:  ///////repete escrita até que todos os caracteres sejam escritos ou a função retorne um erro
 285:  int escreve_frase(uint16_t ende, int tamanho, char *frase)//endereço inicial ,quantidade de caracteres , string(frase)
 286:  {
 287:            int ret_valor, total=0;
 288:   
 289:            do
 290:              {
 291:                      ret_valor = escreve_pagina(ende , tamanho, frase);
 292:                      if (ret_valor == -1)
 293:                           {
 294:                            return -1;///se erro retorna -1
 295:                           }
 296:                        ende += ret_valor;
 297:                        tamanho -= ret_valor;
 298:                        frase += ret_valor;
 299:                        total += ret_valor;
 300:              }while (tamanho > 0);
 301:   
 302:            return total;//retorna a quantidade de caracteres escritos
 303:  }
 304:   
 305:   
 306:  int main(void)
 307:  {
 308:        int valor_retornado;
 309:        uint8_t frase_lida[16];
 310:        DDRD = 0XFF;
 311:        PORTD = 0X00;
 312:   
 313:        I2C_inicializar();
 314:         valor_retornado = escreve_frase(450,50, "TESTANDO ENVIO DE DADOS");// local a ser escrito(endereço inicial) /tamanho da frase(numero de caracteres/ frase (string)
 315:        valor_retornado = escreve_frase(23,1,"X");//escreve um caracter
 316:            if(valor_retornado<0)
 317:          {
 318:           //aqui deve colocar o que fazer se tiver uma falha de escrita
 319:          }
 320:          else
 321:          {
 322:           //aqui deve colocar o que fazer se não tiver nenhuma falha de escrita
 323:   
 324:          }  
 325:         //para ler bytes da memoria faça
 326:          valor_retornado = ler_bytes (1, 15, frase_lida);//local inicial de leitura / quantidade de caracteres a ler / bytes lido
 327:          if(valor_retornado<0)
 328:          {
 329:           //aqui deve colocar o que fazer se tiver uma falha de leitura
 330:           PORTD = 0X0F;
 331:          }
 332:          else
 333:          {
 334:           //aqui deve colocar o que fazer se não tiver nenhuma falha de leitura
 335:           PORTD = 0X05;
 336:   
 337:          } 
 338:           
 339:  }

6 comentários :

  1. Muito bom, ajudou bastante no projeto que estou trabalhando.

    ResponderExcluir
  2. Olá, primeiramente quero agradecer ao criado do blog, pelo, desempenho e dedicação no compartilhamento de conhecimento. Assim, sim, seremos um país melhor(Fica a dica para todos).
    Minha dúvida é o seguinte: no seu esquema você está usando as portas 28 e 27, tem como eu usar outras, ou é fixa essas portas?(Desculpe minha ignorância, sou novato).\
    Obrigado.

    Max

    ResponderExcluir
    Respostas
    1. Sim é fixa pois para o I2C funcionar é preciso de um hardware especifico(registrador de deslocamento), mas talvez existam outras formas,mas como o dispositivo já com tudo pronto para estes pinos então "por que reinventar a roda?" obrigado por visitar o site, e sempre que puder ou quiser compartilhar algo é só falar,que dai posto seu arquivo e coloco seu nome.

      Excluir
  3. Opa amigo, blz.

    Cara, sou leigo em AVR, porem gostaria de gravar algumas informações no uC, entretando não entendi a diferença entre IC2 e EPROMM, ou é necessário IC2 para gravar na EPROMM?

    Grato.

    ResponderExcluir
    Respostas
    1. neste tópico é abordado a comunicação i2C para gravar neste tipo de memoria externa(não tem nada a ver com a eeprom do microcontrolador),em outras postagens aqui mesmo no blog tem um exemplo de gravar na eeprom do avr,vê isso:
      ////////////////////////////////////////////////////////////////////////funçoes da eeprom
      unsigned char ler_eeprom(int ende)
      {
      /* espera completar alguma escrita */
      while(EECR & (1<<EEWE));
      EEAR = ende;
      //pega dados que estão na posição 5 da eeprom
      /* inicia leitura da eeprom */
      EECR |= (1<<EERE);
      /* retorna dados da memoria */
      return EEDR;
      }

      ////////////////////////////////////////////////////////////////////////
      void escr_eeprom(int ende,char valor)
      {
      cli(); //desabilita interrupções
      /* espera completar alguma escrita */
      while(EECR & (1<<EEWE)) ;
      /* lê o endereço 10 */
      EEAR = ende; // endereço
      EEDR = valor;// dados
      /*habilita escrita de eeprom */
      EECR |= (1<<EEMWE);
      /*inicia escrita na eeprom, escreve 1 em EEMWE*/
      EECR |= (1<<EEWE);
      sei();//Habilita interrupções
      }

      para usar faz se assim:

      escr_eeprom(5,'P');//escreve na posição 5 o caracter 'P'

      variavel = ler_eeprom(5);// lê a memoria no endereço 5 da eeprom

      Excluir
  4. Este comentário foi removido pelo autor.

    ResponderExcluir

olá,digite aqui seu comentário!