I2C BitBang Codigo Genérico
Autor: Alexandre Pereira | Publicado: 2010-08-31T16:30:00-03:00

Pessoal,

Depois de muito penar com (PASMEM!) uma 24C02, eu decidi rever meu código de I2C e encontrei um problema que foi solucionado (com o auxilio do nosso amigo Arão, lá da Onipresente PICLIST!), nesta nova versão que apresento do meu código de I2C.
O problema básico é que não estava sendo resetando o BUS I2C a cada transação, o que as vezes ocasionava uma travada no BUS que só voltava após o reset do circuito.
Também notei (à duras penas!) que os Datasheets em sua maioria não falam sobre este Reset no BUS, o que confundiu um pouco. Mas vamos deixar e palavras e vamos ao código.

Primeiro um .C + .H para as 24C02:

- Inicio de 24C02.c ----------------------------------------------------------------------------#include "sfr_r81b.h"#include "24C02.h"
// ---------------------- Low Level Functions ---------------
void waitFactor(unsigned int factor) { unsigned int fc=0; factor*=waitUnit; for(fc=0; fc&lt;factor; fc++) asm("NOP");}unsigned char getSDAState(void) { _24C02_sda_d = 0; asm("NOP"); return(_24C02_sda); }unsigned char getSCLState(void) { _24C02_scl_d = 0; asm("NOP"); return(_24C02_scl); }void setSDAHigh(void) { _24C02_sda_d = 1; _24C02_sda = 1; }void setSCLHigh(void) { _24C02_scl_d = 1; _24C02_scl = 1; }void setSDALow(void) { _24C02_sda_d = 1; _24C02_sda = 0; }void setSCLLow(void) { _24C02_scl_d = 1; _24C02_scl = 0; }void clockToHigh(void) { setSCLHigh(); waitFactor(1); }void clockToLow(void) { setSCLLow(); waitFactor(1); }void clockPulse(void) { clockToHigh(); clockToLow(); }void sendBit(unsigned char bit) { if(bit) {  setSDAHigh(); } else {  setSDALow();  } waitFactor(1); setSCLHigh(); waitFactor(1); setSCLLow(); &nbsp;waitFactor(1);}unsigned char resetBus (void) { unsigned char sdaStatus; clockToHigh(); sdaStatus=getSDAState(); clockToLow(); return(sdaStatus==0?BUSY:ONLINE);}void startCondition(void) { setSDAHigh(); waitFactor(1); setSCLHigh(); waitFactor(1); setSDALow(); waitFactor(1); setSCLLow(); waitFactor(1);}void stopCondition(void) { setSDALow(); waitFactor(1);  setSCLHigh(); waitFactor(1); setSDAHigh(); waitFactor(1); setSCLHigh(); waitFactor(1);}void writeByte(unsigned char byte) { unsigned char rotateLeft; unsigned char tmp; unsigned char toReturn; rotateLeft = 0; while(rotateLeft&lt;8) {  tmp=byte;  tmp=(tmp &lt;&lt; rotateLeft) &gt;&gt; 7;  rotateLeft++;  sendBit(tmp); }}unsigned char readByte(void) { unsigned char byte=0; unsigned char pos=0; _24C02_sda_d=0; while(pos&lt;8) {  clockToHigh();  byte|=getSDAState();  if(pos&lt;7) byte&lt;&lt;=1;  pos++;  clockToLow(); } return(byte);}unsigned char readAck (void) { unsigned char sdaStatus; clockToHigh(); sdaStatus=getSDAState(); clockToLow(); return(sdaStatus==0?OK:NOK);}
// ---------------------- High Level Functions ---------------
void Write_24C02(unsigned char deviceAddress, unsigned char menAddress, unsigned char byte) { unsigned char myAck=0; reset_bus:  while(resetBus()==BUSY);  device_address:  startCondition();  writeByte(deviceAddress);  myAck=readAck();  if(myAck==NOK) goto reset_bus;  men_address:  writeByte(menAddress);  myAck=readAck();  if(myAck==NOK) goto reset_bus;  send_byte:  writeByte(byte);  myAck=readAck();  if(myAck==NOK) goto reset_bus; stopCondition();}
unsigned char Read_24C02(unsigned char deviceAddress, unsigned char menAddress) { unsigned char myAck=0; unsigned char byte=0; reset_bus:  while(resetBus()==BUSY);  device_address:  startCondition();  writeByte(deviceAddress);  myAck=readAck();  if(myAck==NOK) goto reset_bus;  men_address:  writeByte(menAddress);  myAck=readAck();  if(myAck==NOK) goto reset_bus; restart_condition:  startCondition(); device_address_read:  writeByte(deviceAddress | 0x01);  myAck=readAck();  if(myAck==NOK) goto reset_bus;  read_byte:  byte = readByte();  sendBit(1); stopCondition(); return(byte);}
-&nbsp;Final de 24C02.c&nbsp;----------------------------------------------------------------------------
-&nbsp;Inicio de 24C02.h&nbsp;----------------------------------------------------------------------------#ifndef _24C02_H#define _24C02_H
#define _24C02_sda_d pd3_4#define _24C02_sda  p3_4#define _24C02_scl_d pd3_5#define _24C02_scl  p3_5
#define BUSY   0#define ONLINE   1#define OK    1#define NOK    0
#define waitUnit   2
// ---------------------- High Level Functions ---------------
void Write_24C02(unsigned char deviceAddress, unsigned char menAddress, unsigned char byte);unsigned char Read_24C02(unsigned char deviceAddress, unsigned char menAddress);
#endif-&nbsp;Final de 24C02.h&nbsp;----------------------------------------------------------------------------

E agora o mesmo para 24C256:

-&nbsp;Inicio de 24C256.c&nbsp;----------------------------------------------------------------------------#include "sfr_r81b.h"#include "24C256.h"
// ---------------------- Low Level Functions ---------------void waitFactor(unsigned int factor) { unsigned int fc=0; factor*=waitUnit; for(fc=0; fc&lt;factor; fc++) asm("NOP");
}unsigned char getSDAState(void) { _24C256_sda_d = 0; asm("NOP"); return(_24C256_sda); }unsigned char getSCLState(void) { _24C256_scl_d = 0; asm("NOP"); return(_24C256_scl); }void setSDAHigh(void) { _24C256_sda_d = 1; _24C256_sda = 1; }void setSCLHigh(void) { _24C256_scl_d = 1; _24C256_scl = 1; }void setSDALow(void) { _24C256_sda_d = 1; _24C256_sda = 0; }void setSCLLow(void) { _24C256_scl_d = 1; _24C256_scl = 0; }void clockToHigh(void) { setSCLHigh(); waitFactor(1); }void clockToLow(void) { setSCLLow(); waitFactor(1); }void clockPulse(void) { clockToHigh(); clockToLow(); }void sendBit(unsigned char bit) { if(bit) {  setSDAHigh(); } else {  setSDALow();  } waitFactor(1); setSCLHigh(); waitFactor(1); setSCLLow(); &nbsp;waitFactor(1);}unsigned char resetBus (void) { unsigned char sdaStatus; clockToHigh(); sdaStatus=getSDAState(); clockToLow(); return(sdaStatus==0?BUSY:ONLINE);}void startCondition(void) { setSDAHigh(); waitFactor(1); setSCLHigh(); waitFactor(1); setSDALow(); waitFactor(1); setSCLLow(); waitFactor(1);}void stopCondition(void) { setSDALow(); waitFactor(1);  setSCLHigh(); waitFactor(1); setSDAHigh(); waitFactor(1); setSCLHigh(); waitFactor(1);}void writeByte(unsigned char byte) { unsigned char rotateLeft; unsigned char tmp; unsigned char toReturn; rotateLeft = 0; while(rotateLeft&lt;8) {  tmp=byte;  tmp=(tmp &lt;&lt; rotateLeft) &gt;&gt; 7;  rotateLeft++;  sendBit(tmp); }}unsigned char readByte(void) { unsigned char byte=0; unsigned char pos=0; _24C256_sda_d=0; while(pos&lt;8) {  clockToHigh();  byte|=getSDAState();  if(pos&lt;7) byte&lt;&lt;=1;  pos++;  clockToLow(); } return(byte);}unsigned char readAck (void) { unsigned char sdaStatus; clockToHigh(); sdaStatus=getSDAState(); clockToLow(); return(sdaStatus==0?OK:NOK);}
// ---------------------- High Level Functions ---------------void Write_24C256(unsigned char deviceAddress, unsigned int menAddress, unsigned char byte) { unsigned char myAck=0;  unsigned int tmsb,tlsb; unsigned char msb, lsb; tlsb = tmsb = menAddress; tmsb = tmsb &gt;&gt; 8;&nbsp; tlsb = (tlsb &lt;&lt; 8) &gt;&gt; 8; msb = (unsigned char) tmsb;&nbsp; lsb = (unsigned char) tlsb;  reset_bus:  while(resetBus()==BUSY);  device_address:  startCondition();  writeByte(deviceAddress);  myAck=readAck();  if(myAck==NOK) goto reset_bus;  men_address:  writeByte(msb);  myAck=readAck();  if(myAck==NOK) goto reset_bus;  men_address1:  writeByte(lsb);  myAck=readAck();  if(myAck==NOK) goto reset_bus;  send_byte:  writeByte(byte);  myAck=readAck();  if(myAck==NOK) goto reset_bus; stopCondition();}
unsigned char Read_24C256(unsigned char deviceAddress, unsigned int menAddress) { unsigned char myAck=0; unsigned char byte=0;  unsigned int tmsb,tlsb; unsigned char msb, lsb; tlsb = tmsb = menAddress; tmsb = tmsb &gt;&gt; 8;&nbsp; tlsb = (tlsb &lt;&lt; 8) &gt;&gt; 8; msb = (unsigned char) tmsb;&nbsp; lsb = (unsigned char) tlsb;  reset_bus:  while(resetBus()==BUSY);  device_address:  startCondition();  writeByte(deviceAddress);  myAck=readAck();  if(myAck==NOK) goto reset_bus; men_address:  writeByte(msb);  myAck=readAck();  if(myAck==NOK) goto reset_bus;  men_address1:  writeByte(lsb);  myAck=readAck();  if(myAck==NOK) goto reset_bus;  restart_condition:  startCondition(); device_address_read:  writeByte(deviceAddress | 0x01);  myAck=readAck();  if(myAck==NOK) goto reset_bus;  read_byte:  byte = readByte();  sendBit(1); stopCondition(); return(byte);}
-&nbsp;Final de 24C256.c&nbsp;----------------------------------------------------------------------------
-&nbsp;Inicio de 24C256.h&nbsp;----------------------------------------------------------------------------#ifndef _24C256_H#define _24C256_H
#define _24C256_sda_d pd3_4#define _24C256_sda  p3_4#define _24C256_scl_d pd3_5#define _24C256_scl  p3_5
#define BUSY   0#define ONLINE   1#define OK    1#define NOK    0
#define waitUnit&nbsp;  2
// ---------------------- High Level Functions ---------------
void Write_24C256(unsigned char deviceAddress, unsigned int menAddress, unsigned char byte);unsigned char Read_24C256(unsigned char deviceAddress, unsigned int menAddress);
#endif-&nbsp;Final de 24C256.h&nbsp;----------------------------------------------------------------------------
Para utilizar os códigos é bem simples.
Basta incluir o arquivo equivalente no header do programa onde vai usar,&nbsp;obviamente&nbsp;colocar o arquivo .C no projeto para ser compilado, e chamar as funções do que se deseja fazer, ler ou gravar.
Exemplo:#include "24C02.h"
// Protótiposvoid main(void);
// Variáveis Globaisunsigned char i=0;unsigned char carToWrite;unsigned char car;unsigned char paraGravar;unsigned char inicio, final;unsigned char sdaState; // Ponto de Entradavoid main(void) { carToWrite=0; car=0; for(;;) {  inicio=0;  final=255;  for(i=inicio;i   Write_24C02(0xA0, i, i);   car=0xFF;   car=Read_24C02(0xA0, i);   if(i!=car) {    asm("nop");   }  }  asm("nop"); }}
Bom é isso ...
Espero que o código ajude... se precisarem de algo, tipo um projeto pronto e rodando para o R8C/1A por exemplo.. é só me avisar que eu posto um link de download aqui!
Enjoy!