Grabar una tabla Array en una EEPOM 93c66. Lectura secuencial.

Este programa se basa en la escritura de un array en una memoria EEPROM 93c66 ( microwire) y su posterior lectura para la comprobacion del dato grabado. Este programa lo he realizado yo, con motivos de aprendizaje por lo que desconozco si existen más funciones o librerias para programar memoiras microwire ( 3 cables). He visto algo sobre SPI pero no me convence mucho. No descarto traspasar o modificar el programa para que se adapte a SPI pero ya debo de modificar tambien los pines de conexion hacia el SPI de arduino.

/*Programa que toma una tabla de datos de un array y lo
 * graba en la memoria eeprom 93c66.Para le escritura de un
 * byte se necesita habilitar el chip con una instruccion
 * EWEN porque al conectarlo a alimentación está desactivada
 * la escritura y borrado.
 * Despues de la escritura de todos los datos, protegemos con 
 * la instruccion EWDS.
 */

const int CS=5;
const int DI=3;
const int DO=2;
const int CLK=4;
const byte OPcode_Lectura=2;
const byte OPcode_Escritura=1;
byte Buffer;


void setup()
{
  pinMode(CS, OUTPUT);//Pin CS como salida
  pinMode(DI, OUTPUT);
  pinMode(CLK, OUTPUT);
  pinMode(DO, INPUT);// Pin DO como entrada
  Serial.begin(9600);//Velocidad de conexion terminal
  //condicion de inicio
   startBit();
   EWEN();//Habilitamos para escritura
   }

void EWEN()
{
  int datoEWEN=0x0180;//intruccion ewen+direccion
    byte contador=11;
    escribe(datoEWEN,contador);
}

void EWDS()
{
  int datoEWDS=0;//intruccion ewds+direccion
    byte contador=11;
    escribe(datoEWDS,contador);
}

void startBit()
{
  digitalWrite(CS, LOW);//condicion de inicio
    delayMicroseconds(1);
    digitalWrite(CLK, LOW);
    digitalWrite(DI, LOW);
    digitalWrite(CS, HIGH);
    delayMicroseconds(1);
    digitalWrite(DI, HIGH);
    delayMicroseconds(1);
    digitalWrite(CLK, HIGH);//Flanco de subida de reloj
    delayMicroseconds(1);//Se ha escrito el bit SB
    digitalWrite(CLK,LOW);
    delayMicroseconds(1);
    
}
void ProcesoEscritura(int direccion,byte dato)
  {
    startBit();
    escribe(OPcode_Escritura,2);
    escribe(direccion,9);
    digitalWrite(CLK,LOW);
    escribeByte(dato);
    comprobarBusy();
    digitalWrite(CS,LOW);
    
  }

void escribe(int dato, byte contador)
{
   
  while(contador>0)//repite el ciclo tantas veces
    {
    delayMicroseconds(1);
    digitalWrite(DI, bitRead(dato,(contador-1)));
    //Posicionamos el bit a leer de dato y lo copiamos a DI
    delayMicroseconds(1);
    digitalWrite(CLK, HIGH);
    delayMicroseconds(1);
    digitalWrite(CLK,LOW);
    delayMicroseconds(1);
    contador--;//necesario para el ciclo se repita
    }
    
}

void escribeByte(byte Byte)
{
  
  shiftOut(DI,CLK,MSBFIRST,Byte);
 
}


void leeMemoria()//solo para 8 bits de datos
{
    
    Buffer=0;//limpia el Buffer
    Buffer=shiftIn(DO,CLK,MSBFIRST);
/*
Esta funcion obtiene el dato por DO, utiliza como reloj CLk
y se recepciona primero el MSB desde la memoria. El resultado
es un byte que se almacena en una variable tipo byte que he 
llamado Buffer.
*/
    Serial.print("Resultado de la lectura: ");
    Serial.println(Buffer);
    delayMicroseconds(1);
    
 }

void comprobarBusy()
{
 delay(10);//RETARDO para autoescritura de la EEPROM.
 Serial.println("Dato grabado correctamente");
}
void leeAutomatico(int inicio, int alcance)
{
  int direccionInicio=inicio;
  startBit();//condicion de inicio CS,DI y CLK A 1
  escribe(OPcode_Lectura,2);//mandamos el codigo op que es de 2 bits
  Serial.println("Mandamos la direccion");
  escribe(direccionInicio,9);//9 bits de direccion
  if (alcance>direccionInicio)
  {
   while(direccionInicio<=alcance)//Tope de dirección a leer ( el máximo)
    {
      leeMemoria();
      delay(10);
      digitalWrite(CLK,LOW);
      delayMicroseconds(1);
      digitalWrite(DI,LOW);
      Serial.print("Direccion leida: ");
      Serial.println(direccionInicio);
      direccionInicio++;
    }
  }
  else 
  {
    Serial.println("ERROR.Alcance debe ser mayor que inicio. Se imprime solo inicio");
  leeMemoria();
  delay(10);
  digitalWrite(CLK,LOW);
  delayMicroseconds(1);
  digitalWrite(DI,LOW);
  Serial.print("Direccion leida: ");
  Serial.println(direccionInicio);
  }
}


void loop()
{
  
  Serial.println("");
  Serial.println("Inicio del programa");
  
  byte midato[6]={15,20,22,33,25,7};
  int direccion=0;
  for(int i=0; i<6; i++)
  {
    direccion=i;
    Serial.print("direccion es: ");
    Serial.println(direccion);
    Buffer=midato[i];
    Serial.print("midato[] vale: ");
    Serial.println(Buffer);
   startBit();
  ProcesoEscritura(direccion,Buffer);
  delay(10);
  }
  startBit();
  EWDS();
  Serial.println("leemos...");
  int inicio=0;//Direccion de inicio de la lectura.
  int alcance=10;//POsicion final.DEBE SER MAYOR QUE inicio.
  //El numero maximo es 511 ya que la memoria no tiene mas capa
  //cidad por lo que si pasamos de este valor, volemos al 
  //principio.
  leeAutomatico(inicio,alcance);
  digitalWrite(CS, LOW);
  delayMicroseconds(1); 
  Serial.println("Fin del programa");
}

Cuidado, la instrucción shiftIn y shiftOut mandan 8 bits por lo que para enviar un código op para seleccionar el modo de trabajo ( lectura, escritura, borrado, etc) no puede usarse esta instrucción. Esto se debe a que para introducir el código,primero debemos hacer una condición de inicio, que consta de que Chip Selection esté a cero, el dato DI esté a cero, y la señal Clock tambien. En este momento hay que poner DI a 1 , Chip Selection ( cs) a 1 y CLK a 1 tambien. En esta situacion están los tres pines a nivel alto y debemos de poner a 0 CLK y DI para los dos bits correspondientes a la instrucción op. En esta situación hemos enviado el bit SB, ahora hay que enviar el bit MSB de la instruccion OP. Para ello enviamos el bit escribiendo el bit en DI y pasando la señal de reloj CLK de bajo a alto y debe permanecer al menos 1 micosegundo en ese nivel. Acto seguido, enviaremos el segundo bit del OP y por tanto el úlitimo bit del OP. Para su envio por supuesto, el dato DI debe estar presente 1 microsegundo antes que el flaco ascendente de la señal de reloj CLK. Escribimos en DI de forma directa el valor de dicho bit. En este punto ya hemos introducido el SB y los dos bits del OP. Si la instrucción OP requiere más bits como el caso de EWEN, EWDS, etc, se deberán tener en cuenta que se "roban a los bits de mas peso de la "dirección".
Una vez introducidos como hemos dicho los bits anteriores, queda por introducir los 9 bits de la dirección. Para esto, puede hacer lo mismo de antes, o enviar el bit A8 ( bit MSB) de la dirección en primer lugar y por separado, como hemos visto antes y a continuación utilizar la instrucción shiftOut con el resto de bits (A7-A0) de la dirección.
En lectura, se envia SB=1 o condicion de inico, la instruccion de lectura que es 10 ( dos bits) y a continuación se envía la dirección de inicio de la lectura ( suponga que sea la primera osea la cero). En ese caso A8 es el MSB y A0 el LSB. Pasados esos nueve ciclos de reloj, el chip está dispuesto y muestra el primer bit por la patilla DO. Ojo, en el flaco de subida del A0, el dato que se muestra en DO es un cero. Pero en el flaco nº10 mostrará el bit MSB del dato a leer.
En este punto, donde hemos pasado 12 pulsos de relosj (1 para SB, 2 para OPcode y 9 para direccion) es ahora cuando debemos de utilizar la instrucción shiftIn() que leerá el byte completo. Acto segudio, estas EEPROM permite la lectura secuencial automática, de forma que a partir de la primera lectura, ya no necesita que se le introuduzca el SB, ni OP, NI LA DIRECCION, por lo que al ejecutar de nuevo shiftIn() se lee el siguiente dato ya que se autoincrementa la direccion de la EEPROM. Por esta razón se ve el programa mio de esa forma, porque de otra NO FUNCIONA.