Almacenamiento de información (parte 2)


Retomando el tema de almacenamiento de información, hablaremos de la memoria EEPROM externa.

Memoria EEPROM por I2C

¿Qué es el protocolo I2C (Inter-Integrated circuit)? es un protocolo que se usa ampliamente para enviar o recibir la información de varios microcontroladores en un mismo bus o algún otro hardware, en este caso una memoria EEPROM (24LC256, 24LC16B, etc.). Este protocolo se caracteriza porque tiene un bus de datos de 2 hilos SDA y SCL, además que los dispositivos esclavos tienen una identificación única en el bus (ej: %10101110), algunas veces esta dirección esta asignada por defaul dentro del IC.

El protocolo I2C puede trabajar a ciertas velocidades máximas de 100Khz, 400Khz y 1Mhz (según la EEPROM). Visita el sitio I2C para más información sobre el protocolo I2C.

Aquí tenemos algunas características de las EEPROM 24LCxxx:
  • La dirección de las 24LCxxx siempre empieza con %1010.
  • El pin WP (pin 7) es un pin de protección de escritura, si el pin esta conectado a 5v se activa la protección de escritura, si esta a GND se habilita la escritura.
  • Los pines A0, A1, A2 son los que definen la dirección de la memoria EEPROM.
  • Las memorias tienen una página de almacenamiento para evitar desbordamientos o que se atrase, aproximadamente una memoria EEPROM se tarda 10 ms en grabar un dato.

Te recomiendo que revises los laboratorios de PICAXE sobre protocolo I2C para mayor explicación de su implementación y de sus comandos.

Diagrama a utilizar:

CÓDIGO FUENTE (maestro escribe PICAXE20X2):
hi2csetup i2cmaster, %10100000, i2cslow, i2cword
low c.7
main:
for b1 = 0 to 15
b1=b1+3
hi2cout 0,(b1)
pause 12
next b1

CÓDIGO FUENTE (maestro lee PICAXE20X2):
hi2csetup i2cmaster, %10100000, i2cslow, i2cword
main:
for b1 = 0 to 15
b1=b1+3
hi2cin 0,(w2)
sertxd ("dato: ", #w2, 13,10)
pause 12
next b1




CÓDIGO FUENTE (maestro lee y escribe):


Diagrama a utilizar (Tomado del ejemplo de laboratorios para Arduino):


#include <Wire.h>
#define eeprom 0x50    //Dirección de la memoria 24LC256
int estado1, estado2, estado3, busqueda;
int luz = LOW;
byte valormem = 0xFF;
unsigned int direccion = 0;
void setup(void){
  pinMode (8,INPUT);
  pinMode (9,INPUT);
  pinMode (10,INPUT);
  pinMode (13,OUTPUT);
  Wire.begin();
}
void loop(){
  estado1 = digitalRead(8);
  if (estado1 == HIGH)
  {
    delay(150);
    estado1 = digitalRead(8);
    if (estado1 == LOW)
    {
       writeEEPROM(eeprom, direccion, 78);
    }
  }
  estado2 = digitalRead(9);
  if (estado2 == HIGH)
  {
    delay(150);
    estado2 = digitalRead(9);
    if (estado2 == LOW)
    {
       writeEEPROM(eeprom, direccion, 66);
    }
  }
  estado3 = digitalRead(10);
  if (estado3 == HIGH)
  {
    delay(150);
    estado3 = digitalRead(10);
    if (estado3 == LOW)
    {
      Wire.beginTransmission(eeprom);
      Wire.write((int)(direccion >> 8));   // MSB
      Wire.write((int)(direccion & 0xFF)); // LSB
      Wire.endTransmission();
      Wire.requestFrom(eeprom,1);
      if (Wire.available()) valormem = Wire.read();
      if (valormem == 78)
      {
       for (int ciclo=0;ciclo <21;ciclo++)
       {
         luz = !luz;
         digitalWrite(13,luz);
         delay (300);
         valormem = 0;
       }
      }
    }
  }
}
void writeEEPROM(int deviceaddress, unsigned int eeaddress, word data ) {
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(data);
  Wire.endTransmission();
  delay(5);
}

Memoria EEPROM por SPI

¿Qué es el protcolo SPI (Serial Peripheral Interface)? Es bus de comunicación asincrónico que opera en el modo full duplex, emplea un simple registro de desplazamiento para transmitir la información. El bus SPI puede operar con un solo maestro o varios, los pines SPI son identificados MOSI (master output, slave input), MISO (master input, slave output), SCLK (serial clock) y SS (slave select). El bus SPI emplea un simple registro de desplazamiento para transmitir la información.

Para la 25LC256 su frecuencia máxiama de trabajo es 10 Mhz. Visita el sitio SPI para leer más del protocolo SPI.






PICAXE posee 2 métodos de comunicación por SPI, la primera es por software (podemos asignar los pines que deseemos para la comunicación) y la segunda por hardware.

  • spiout y spiin: son comandos por software para PICAXE, con los cuales podemos utilizar para comunicarnos con la memoria.
  • hspiout y hspiin: son comandos por hardware para PICAXE, donde únicamente nosotros tenemos que seleccionar el pin CS y los demás pines ya estan predefinidos. También este comando es más rapido en la comunicación que el de por software.

CÓDIGO FUENTE – SPI por SOFTWARE (maestro escribe y lee PICAXE20X2):


Diagrama a utilizar:

high b.7
pause 50
b0 = 0 'byte inferior de dirección
b1 = 0 'byte superior de dirección
b2 = 35 'dato a guardar
b3 = 3
main:
'habilita escritura spi
low b.7
spiout c.3,c.5,MSBFIRST_L,(6,2)
high b.7
'escribir el estado 0 al registro para desbloquear
low b.7
spiout c.3,c.5,MSBFIRST_L,(1,0)
high b.7
pause 5
'habilita escritura
low b.7
spiout c.3,c.5,MSBFIRST_L,(6)
high b.7
'escribe en EEPROM spi
low b.7
spiout c.3,c.5,MSBFIRST_L,(2,b1,b0,b2,b3)
high b.7
pause 5
debug
pause 500
'lee
low b.7
spiout c.3,c.5,MSBFIRST_L,(3,b1,b0)
spiin c.3,c.4, MSBPRE_L,(b6,b7)
high b.7
'habilita escritura
low b.7
spiout c.3,c.5,MSBFIRST_L,(6)
high b.7
'deshabilitar escritura
low b.7
spiout c.3,c.5,MSBFIRST_L,(4)
high b.7
'debug
debug
pause 1000
inc b2
inc b3
inc b0
goto main
CÓDIGO FUENTE – SPI por HARDWARE (maestro escribe):

Diagrama a utilizar (este circuito cambia al anterior):

NOTA: el LED en B.0 es un indicador cuando se ha terminado el ciclo:

b1 = 0
b0 = 0
hspisetup spimode11e, spimedium ; spi mode 1,1

low c.0
hspiout (6) ; envia escritura habilitada
high c.0

low c.0
hspiout (1,0) ; remueve protección de bloque
high c.0
pause 5

for b2 = 0 to 9
low c.0
hspiout (6) ; envia escritura habilitada
high c.0

low c.0
hspiout (2,0,b0,b1) ; Escribe b1 en la posición b0
high c.0
pause 5

low c.0
hspiout (6) ; envia escritura habilitada
high c.0

low c.0
hspiout (4) ; envia escritura deshabilitada
high c.0

inc b0
b1 = b1+8
debug
pause 1000
next b2

CÓDIGO FUENTE – SPI por HARDWARE (maestro lee):


hspisetup spimode11e, spimedium ; spi mode 1,1

pause 1000

for b3 = 0 to 9

low c.0
hspiout (3,0,b0) ; envia el comando de lectura a la dirección b0
hspiin (b2) ; almacena en b2
high c.0

inc b0
debug
pause 1000

next b3










Arduino posee una librería específica para protocolo SPI, la cual me causó un poco de confusión al momento de hacerla, por lo cual cree una entrada en el foro de Arduino, en la cual tuve el soporte necesario, puedes verlo dando click aquí FORO.

El algoritmo de programación para grabar en la memoria EEPROM es el mismo, únicamente había que adaptarlo al lenguaje de programación de Arduino.

Los pines para conectar SPI con Arduino son: pin digital 10 (SS), 11 (MOSI), 12 (MISO), y 13 (SCK). En el Arduino Mega: 50 (MISO), 51 (MOSI), 52 (SCK), y 53 (SS). El pin 10 (en el caso de Arduino UNO o el 50 para el Mega) debe configurarse con pinMode(10,OUTPUT); y cada vez que se mande una instrucción se pone digitalWrite(10,LOW); y cuando termina el comando se cierra con digitalWrite(10,HIGH);.

Para saber más de la librería SPI, visita http://arduino.cc/en/Reference/SPI.

Diagrama a Utilizar:




CÓDIGO FUENTE – SPI (maestro lee y escribe):
#include <SPI.h>
int variable = 2;
int resultado, registro=0;

void setup() {
  pinMode(10,OUTPUT);
  digitalWrite(10, HIGH);
  Serial.begin(9600);
  SPI.begin();
  SPI.setDataMode(SPI_MODE3);  //configura protocolo SPI
  SPI.setClockDivider(SPI_CLOCK_DIV2); // 10 Mhz max para 25LC256
  SPI.setBitOrder(MSBFIRST);

  digitalWrite(10, LOW);
  SPI.transfer(6);  //escritura habilitada 6
  digitalWrite(10, HIGH);

  digitalWrite(10, LOW);
  SPI.transfer(1); //remove block protection 1,0
  SPI.transfer(0);
  digitalWrite(10, HIGH);
  delay(5);

  for(int j=0; j<9; j++)
  {
      digitalWrite(10, LOW);
      SPI.transfer(6); //escritura habilitada 6
      digitalWrite(10, HIGH);
   
      digitalWrite(10, LOW);
      SPI.transfer(2); // escribe 2,0
      SPI.transfer(0);
      SPI.transfer(registro); // registro
      SPI.transfer(variable); // data
      digitalWrite(10, HIGH);
      delay(5);
   
      digitalWrite(10, LOW);
      SPI.transfer(6); // escritura habilitada 6
      digitalWrite(10, HIGH);
   
      digitalWrite(10, LOW);
      SPI.transfer(3); // lee 3,0
      SPI.transfer(0);
      SPI.transfer(registro); // registro
      resultado = SPI.transfer(0x00);
      digitalWrite(10, HIGH);
   
      Serial.print("direccion");
      Serial.print(registro);
      Serial.print(" : ");
      Serial.println(resultado);
      registro++;
      variable++;
  }
  digitalWrite(10, LOW);
  SPI.transfer(4); // escritura deshabilitada 4
  digitalWrite(10, HIGH);
}

void loop() {}

CÓDIGO FUENTE – SPI (maestro escribe):

NOTA: el LED en el pin digital 2 es un indicador cuando se ha terminado el ciclo. 
#include <SPI.h>
int variable = 56;
int resultado, registro=0;
void setup() {
  pinMode(10,OUTPUT);
  pinMode(2,OUTPUT);
  digitalWrite(10, HIGH);
  digitalWrite(2, HIGH);
  SPI.begin();
  SPI.setDataMode(SPI_MODE3);  //configura protocolo SPI
  SPI.setClockDivider(SPI_CLOCK_DIV2); // 10 Mhz max para 25LC256
  SPI.setBitOrder(MSBFIRST);

  digitalWrite(10, LOW);
  SPI.transfer(6);  // escritura habilitada 6
  digitalWrite(10, HIGH);

  digitalWrite(10, LOW);
  SPI.transfer(1); // remueve protección de bloque 1,0
  SPI.transfer(0);
  digitalWrite(10, HIGH);
  delay(5);

  for(int j=0; j<9; j++)
  {
      digitalWrite(10, LOW);
      SPI.transfer(6); // escritura habilitada 6
      digitalWrite(10, HIGH);
   
      digitalWrite(10, LOW);
      SPI.transfer(2); // write 2,0
      SPI.transfer(0);
      SPI.transfer(registro); // registro
      SPI.transfer(variable); // dato a almacenar
      digitalWrite(10, HIGH);
      delay(5);
   
      digitalWrite(10, LOW);
      SPI.transfer(6); // escritura habilitada 6
      digitalWrite(10, HIGH);
      registro++;  // +1
      variable++;  // +1
  }
  digitalWrite(10, LOW);
  SPI.transfer(4); // escritura deshabilitada 4
  digitalWrite(10, HIGH);
}
void loop() {
digitalWrite(2, LOW);
}

CÓDIGO FUENTE – SPI (maestro lee):
#include <SPI.h>
int resultado, registro=0;

void setup() {
  pinMode(10,OUTPUT);
  pinMode(2,OUTPUT);
  digitalWrite(10, HIGH);
  digitalWrite(2, HIGH);
  Serial.begin(9600);
  SPI.begin();
  SPI.setDataMode(SPI_MODE3);  //configura protocolo SPI
  SPI.setClockDivider(SPI_CLOCK_DIV2); // 10 Mhz max para 25LC256
  SPI.setBitOrder(MSBFIRST);

  for(int j=0; j<9; j++)
  {
      digitalWrite(10, LOW);
      SPI.transfer(3); // lee 3,0
      SPI.transfer(0);
      SPI.transfer(registro);
      resultado = SPI.transfer(0x00);
      digitalWrite(10, HIGH);
   
      Serial.print("direccion");
      Serial.print(registro);
      Serial.print(" : ");
      Serial.println(resultado);
      registro++;
  }
}

void loop() {
digitalWrite(2, LOW);
}