Y ahora el esquemático:
Y por supuesto lo más importante el scketch para el arduino:
#include <Wire.h> // Includes the Wire library for I2C communication
#include <LiquidCrystal_I2C.h> // Includes the LiquidCrystal_I2C library
#define lcdAddress 0x3f // LCD I2C Address
#define CTL 0X50 //Byte de control para memorias 24C00 hasta la 24C512
#define CTLM1 0x51 //Byte de control para memorias 24LC1024, 24LC1026 y AT24CM01
#define CTLM2 0X52 //Byte de control para memorias AT24CM02
#define CTL1025 0x54 //Byte de control para memoria 24LC1025
#define VDD_SRC 4 // Define digital port 4 as VDD for source memory
#define VDD_TAR 5 // Define digital port 5 as VDD for target memory
#define START_SW 3 // Define digital port 3 as Start switch
#define SEL_SW 2 // Define digital port 2 as Selector switch
#define CE 6 //Chip Enable for Timer
#define RST 7 //Reset for Timer
LiquidCrystal_I2C lcd( lcdAddress ); // Create instance of LiquidCrystal_I2C and set the LCD I2C address
char buff[16];
byte ACK,model_flag;
unsigned int model,model0;
long num;
// Definición de funciones
void NO_MEM_SRC(); //Función para mostrar que no se encontró la memoria fuente
void NO_MEM_TARG(); //Función para mostrar que no se encontró la memoria destino
void enable_source(); //Función para habilitar la memoria fuente y deshabilitar la memoria destino
void enable_target(); //Función para habilitar la memoria destino y deshabilitar la memoria fuente
void i2cmemdtc(); //Función para detectar el tipo de memoria. Desde 24C00 hasta la 24CM02
void done_msg(); //Función para mostrar en la LCD el mensaje de que la copia se realizó correctamente
void copy_mem_24C00(); //Función para realizar la copia de la memoria 24C00
void copy_mem(); //Función para realizar la copia de las memorias 24CXXXX
void setup()
{
pinMode(CE,OUTPUT);
pinMode(RST, OUTPUT);
pinMode(VDD_SRC, OUTPUT);
pinMode(VDD_TAR, OUTPUT);
pinMode(START_SW, INPUT_PULLUP);
pinMode(SEL_SW, INPUT_PULLUP);
digitalWrite(VDD_SRC, LOW);
digitalWrite(VDD_TAR, LOW);
digitalWrite(CE, LOW);
digitalWrite(RST,LOW);
digitalWrite(RST,HIGH);
Serial.begin(9600); //Set serial port @9600 bps for debugging
lcd.begin(16,2); // initialize the lcd as a 16 characters by 2 row display
Wire.setClock(400000); // Set I2C clock at 400KHz
lcd.setBacklight(HIGH); // Turn on the LCD's backlight
lcd.home (); // set the cursor to the home position (first row, first column)
lcd.print(" 24XXX SERIES");//
//sprintf(buff, " 24XXX SERIES");
//lcd.print(buff);
lcd.setCursor ( 0, 1 ); // set cursor to first character of line 2
lcd.print(" CLONER VER 1.0");
delay(1500);
lcd.clear();
lcd.print(" DESIGNED BY:");
lcd.setCursor(0,1);
lcd.print(" MIGUEL MEZA");
delay(1500);
lcd.clear();
lcd.print(" ARDUINO NANO");
lcd.setCursor(0,1);
lcd.print("ARDUINO V: 1.8.4");
}
void loop()
{
model_flag = 0;
while (model_flag==0)
{
ACK = 2; //Set NACK value received on transmit of address
while (ACK==2)
{
while (ACK==2)
{
delay(1500);
lcd.clear();
lcd.print(" INSERT MEMORIES");
lcd.setCursor(0,1);
lcd.print(" PRESS START");
while(digitalRead(START_SW));
//enable_source(); //Enable source memory
digitalWrite(VDD_SRC,HIGH);
delayMicroseconds(100);
Wire.beginTransmission(CTL); //Send a start bit and Send CTL Byte to the source memory
ACK = Wire.endTransmission(); //Send a stop bit and wait the ACK from the source memory
if (ACK==2) //Is a NACK bit?
NO_MEM_SRC(); //Yes, then show there is no source memory
}
enable_target(); //No, it is an ACK bit, then enable target memory
Wire.beginTransmission(CTL); //Send a start bit and Send CTL Byte to the target memory
ACK = Wire.endTransmission(); //Send a stop bit and wait the ACK from the target memory
if (ACK==2) //Is a NACK bit?
NO_MEM_TARG(); //Yes, then show there is no target memory
}
//digitalWrite(VDD_SRC,LOW);
//digitalWrite(VDD_TAR,LOW);
//lcd.clear();
//lcd.print("Memories OK");
enable_source();
i2cmemdtc();
//digitalWrite(VDD_SRC, LOW); //Disable source memory for debugging
model0=model;
lcd.clear();
lcd.print("SRC MEM:24C");
if (model<10)
{
sprintf(buff,"%02u",model);
lcd.print(buff);
}
else
{
sprintf(buff,"%u",model);
lcd.print(buff);
}
enable_target();
i2cmemdtc();
lcd.setCursor(0,1);
lcd.print("TARG MEM:24C");
if (model<10)
{
sprintf(buff,"%02u",model);
lcd.print(buff);
}
else
{
sprintf(buff,"%u",model);
lcd.print(buff);
}
delay(1500);
if (model==model0)
{
if ((model==32) && (model0==32) && (digitalRead(SEL_SW)==1))
{
digitalWrite(VDD_SRC, LOW);
digitalWrite(VDD_TAR, LOW);
lcd.clear();
lcd.print("CAN'T COPY");
lcd.setCursor(0,1);
lcd.print("CHANGE COPY MODE");
}
else
model_flag = 1;
}
else
{
lcd.clear();
lcd.print("UNMATCH MEMORIES");
lcd.setCursor(0,1);
lcd.print("REPLACE MEMORIES");
digitalWrite(VDD_SRC, LOW);
digitalWrite(VDD_TAR, LOW);
}
}
lcd.clear();
lcd.print("MATCHED MEMORIES");
lcd.setCursor(0,1);
lcd.print("COPYING...");
digitalWrite(RST, LOW);
digitalWrite(RST, HIGH);
digitalWrite(CE, HIGH);
if (model==0)
copy_mem_24C00();
else
copy_mem();
digitalWrite(CE, LOW);
done_msg();
}
void NO_MEM_SRC()
{
digitalWrite(VDD_SRC,LOW); // Turn off source memory
digitalWrite(VDD_TAR,LOW); //Turn off target memory
lcd.clear(); // Clear LCD display
lcd.print("NO SOURCE MEMORY"); // Show "NO SOURCE MEMORY" in LCD
lcd.setCursor(4,1);
lcd.print("IN SOCKET");
return;
}
void NO_MEM_TARG()
{
digitalWrite(VDD_TAR,LOW); // Turn off target memory
digitalWrite(VDD_SRC,LOW); //Turn off source memory
lcd.clear();
lcd.print("NO TARGET MEMORY");
lcd.setCursor(4,1);
lcd.print("IN SOCKET");
return;
}
void enable_source()
{
digitalWrite(VDD_TAR,LOW); //Turn off Target memory
delay(1);
digitalWrite(VDD_SRC,HIGH); //Turn on Source Memory
delayMicroseconds(100);
return;
}
void enable_target()
{
digitalWrite(VDD_SRC,LOW); //Turn off Source memory
delay(1);
digitalWrite(VDD_TAR,HIGH); //Turn on Target Memory
delayMicroseconds(100);
return;
}
void done_msg()
{
lcd.clear();
lcd.print("MEMORY COPIED");
lcd.setCursor(0,1);
lcd.print("SUCCESSFUL COPY");
digitalWrite(VDD_SRC, LOW);
digitalWrite(VDD_TAR, LOW);
return;
}
void i2cmemdtc()
{
byte backup,ctl_byte,temp,temp0,new_value;
byte OK_flag;
unsigned long top_num;
if (digitalRead(SEL_SW)==0) //¿Se ha seleccionado el modo smart?
{
Wire.beginTransmission(CTLM2); // Sí, entonces envía el byte de control de la memoria de 2Mbits
ACK = Wire.endTransmission(); // Envía el bit de paro y revisa si llegó un ACK
if (ACK==0) //¿Se recibió un bit de ACK?
{
model = 2048; //Sí, entonces asigna el modelo de memoria de 2Mb
num = 262144; //Asigna la capacidad máxima
return; //Termina subrutina de detección
}
Wire.beginTransmission(CTLM1); // Sí, entonces envía el byte de control de la memoria de 1Mbits
ACK = Wire.endTransmission(); //Envía el bit de paro y revisa si llegó un ACK
if (ACK==0) //¿Se recibió un bit de ACK?
{
model = 1024; //Sí, entonces asigna modelo de memoria de 1Mb
num = 131072; //Asigna la capacidad máxima
return; //Termina subrutina
}
Wire.beginTransmission(CTL1025); // Sí, entonces envía el byte de control de la memoria de 1Mbits
ACK = Wire.endTransmission(); //Envia el bit de paro y revisa si llegó un ACK
if (ACK==0) //¿Se recibió un bit de ACK?
{
model = 1025; //Sí, entonces asigna modelo de memoria de 1Mb
num = 131072; //Asigna la capacidad máxima
return; //Termina subrutina
}
}
num = 16; //Inicializa valor de desborde para la memoria 24C00
model = 0; //Inicializa el modelo de memoria en 00, indicando memoria 24C00
top_num = 2048; //Inicializa el valor máximo de desborde para memorias standard
if (digitalRead(SEL_SW)==0) //¿Se ha selleccionado el modo smart?
{
num = 4096; //Sí, entonces inicializa el valor de desborde para la memoria 24C32
model = 32; //Inicializa modelo de memora 24C32
top_num = 65536; //Inicializa valor máximo de desborde para memorias de modo smart
}
while (num<=top_num) //¿Ya se ha alcanzado el valor máximo de desborde?
{
Wire.beginTransmission(CTL); //Envía el byte de control
if (digitalRead(SEL_SW)==0) //¿Se ha seleccionado modo smart?
Wire.write(0); //Sí, entonces envía la parte alta de la dirección 0x0000
Wire.write(0); //Envía la dirección a leer 0x00
Wire.endTransmission();
Wire.requestFrom(CTL,1); // Solicita la lectura de un byte
if(Wire.available()) //Existe un dato disponible?
backup = Wire.read(); //Sí, entonces realiza lectura del byte en la dirección 0x00 (0x0000 smart) sin bit de ACK
num--; //Decrementa en uno el valor de desborde
OK_flag=0; //Limpia la bandera de OK
ctl_byte = num>>8; //Prepara el byte de control de escritura
//sprintf(buff,"%X",top_num);
//Serial.print(buff);
//Serial.println(num, HEX);
//Serial.print(" ");
//Serial.println(ctl_byte, HEX);
//ctl_byte = ctl_byte<<1;
ctl_byte = ctl_byte | CTL;
//Serial.println(ctl_byte, HEX);
if (digitalRead(SEL_SW)==0) //¿se ha seleccionado el modo smart?
ctl_byte=CTL; //Sí, entonces asigna el valor por default (0XA0) del byte de control
Wire.beginTransmission(ctl_byte); //Envía el byte de control de escritura
if (digitalRead(SEL_SW)==0) //¿Se ha seleccionado el modo smart?
Wire.write((int)(num>>8)); //sí, entonces envia el la parte alta de la dirección de desborde
Wire.write((int)(num & 0xFF)); //Envía la dirección de desborde
Wire.endTransmission();
Wire.requestFrom(ctl_byte,2); //Envía el byte de control de lectura
if (Wire.available())
temp = Wire.read(); //Recibe dos datos consecutivos
if (Wire.available())
temp0 = Wire.read();
if (temp0 == backup); //¿El segundo dato es igual al valor contenido en la dirección 0x00 (0x0000 para modo smart)?
{
new_value = backup + 1; //Sí, entonces incrementa el valor contenido en la dirección 0x00 (0x0000 para modo smart) a la variable new_value
Wire.beginTransmission(CTL); //Envía el byte de control de escritura (0xA0)
if (digitalRead(SEL_SW)==0) //¿Se ha seleccionado el modo smart?
Wire.write(0); //Sí, entonces escribe la parte alta de la dirección 0x0000
Wire.write(0); //Envía la dirección a escribir 0x00 (parte baja de la dirección en modo smart)
Wire.write(new_value); //Envía el valor de la variable new_value
Wire.endTransmission();
delay(10); //Espera 10ms para que se escriba el dato
Wire.beginTransmission(ctl_byte); //Envía el byte de control de escritura
if (digitalRead(SEL_SW)==0) //¿Se ha seleccionado el modo smart?
Wire.write((int)(num>>8)); //Sí, entonces envía la parte alta de la dirección de desborde
Wire.write((int)(num & 0xFF)); //Envía la dirección de desborde
Wire.endTransmission();
Wire.requestFrom(ctl_byte,2); //Envía el byte de control de lectura
if (Wire.available())
temp = Wire.read(); //recibe dos datos consecutivos
if (Wire.available())
temp0 = Wire.read();
if (temp0==new_value) //¿Son iguales el segundo dato y el valor de New_value?
OK_flag = 1; //Sí, entonces levanta la bandera OK_flag
}
Wire.beginTransmission(CTL); //Envía el byte de control de escritura default (0XA0)
if (digitalRead(SEL_SW)==0) //¿Se ha seleccionado el modo smart?
Wire.write(0); //Sí, entonces envía la parte alta de la dirección 0x0000
Wire.write(0); //Envía la dirección 0x00 (parte baja de 0x0000)
Wire.write(backup); //Envía el dato original
Wire.endTransmission();
delay(10); //Espera 10ms para que se escriba el dato
num++; //Incrementa el valor de desborde
if (OK_flag==1) //¿Se ha levantado la bandera de OK?
return;
else //No, entonces
{
num = num*2; //Duplica el valor de desborde
model = model*2; //Duplica el modelo de la memoria
if (num==32) //¿el modelo de memoria es 24C32?
{
num = 128; //Sí, entonces asigna el valor de desborde para la memoria 24C01
model = 1; //Inicializa el modelo de memoria 24C01
}
}
//Serial.print("num= ");
//Serial.println(num, DEC);
}
return; //Termina la subrutina
}
void copy_mem_24C00()
{
byte i=0, page_buff[16];
enable_source(); //Enable source memory
Wire.beginTransmission(CTL);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(CTL,16);
while(Wire.available())
{
page_buff[i] = Wire.read();
i++;
}
enable_target();
for(i=0; i<16; i++)
{
Wire.beginTransmission(CTL);
Wire.write(i);
Wire.write(page_buff[i]);
Wire.endTransmission();
lcd.setCursor(11,1);
lcd.print(i, DEC);
delay(5);
}
return;
}
void copy_mem()
{
byte page_size,ctl_byte,temp,ee_data[128];
long i2c_addr;
page_size = 8; //Initialize page size of 8 byte
if((model>2) && (model<17))
page_size = 16;
if ((model>31) && (model<65))
page_size = 32;
if ((model>127) && (model<257))
page_size = 64;
if (model>511)
page_size = 128;
i2c_addr = 0;
while(i2c_addr<=(num-1))
{
ctl_byte = CTL;
if(digitalRead(SEL_SW)==1)
{
ctl_byte = (int)(i2c_addr>>8);
ctl_byte = ctl_byte | CTL;
}
if(model>1023)
{
ctl_byte = (int)(i2c_addr>>16);
if(model==1025)
ctl_byte = ctl_byte<<2;
ctl_byte = ctl_byte | CTL;
}
enable_source();
Wire.beginTransmission(ctl_byte);
if(digitalRead(SEL_SW)==0)
Wire.write((int)(i2c_addr>>8));
Wire.write((int)(i2c_addr & 0xFF));
Wire.endTransmission();
temp = 0;
Wire.requestFrom(ctl_byte, page_size);
while(Wire.available())
{
ee_data[temp] = Wire.read();
temp++;
}
enable_target();
Wire.beginTransmission(ctl_byte);
if(digitalRead(SEL_SW)==0)
Wire.write((int)(i2c_addr>>8));
Wire.write((int)(i2c_addr & 0xFF));
for(temp=0; temp < page_size; temp++)
{
Wire.write(ee_data[temp]);
}
Wire.endTransmission();
lcd.setCursor(10,1);
lcd.print(i2c_addr, DEC);
if(model < 512)
delay(10);
else
delay(5);
i2c_addr = i2c_addr + page_size;
}
return;
}
Importante:
La librería WIRE de arduino tiene limitado el buffer máximo para escritura a 32 bytes, así que tendremos que editarla para incrementar el buffer a 130 bytes. Para ello debemos editar el archivo Wire.h que se encuentra localizado en:
C:\....\Arduino\hardware\arduino\avr\Wire\src
Originalmente el buffuer está definido así:
#define BUFFER_LENGTH 32
Por lo que hay que cambiarlo a:
#define BUFFER_LENGTH 130
Se recomienda usar un editor de textos como notepad o mejor aún Notepad++
Saludos y cualquier pregunta, por favor no duden en hacerla.
elreypic.