Recursos del PIC. Uso de la memoria EEPROM interna

Utilización de las funciones del compilador CCS para el uso de la memoria EEPROM interna

MICROCONTROLADORES

Biblioman

12/6/20095 min read

CCS implementa muchas funciones para trabajar con las memorias EEPROM, algunas de ellas son:

  • value = read_eeprom (address): función básica para leer el valor de la EEPROM interna del PIC. Devuelve un valor entero (int8) de un byte. "address" puede ser un entero de 8 ó 16 bit. Dependiendo del PIC que utilicemos dispondremos de mas ó menos memoria EEPROM, por ejemplo el PIC 16f84A dispone de 64 bytes y los pic16F87X tienen 256 bytes que se direccionan del 0 a 255.

  • write_eeprom (address, value): esta función escribe un dato (entero de 8 bit) en la dirección especificada en address en la memoria interna del PIC. Al igual que read_eeprom address puede ser un entero de 8 ó 16 bit.

Algunos dispositivos permiten leer y escribir datos en la memoria de programa en tiempo de ejecución, para los dispositivos que soportan esta funcionalidad CCS, nos proporciona las siguientes funciones:

  • value = read_program_eeprom (address): esta función lee un dato de la memoria de programa del PIC y devuelve el valor leído como un entero de 16 bits. Adrress es un entero de 16 ó 32 bits que depende del dispositivo empleado.

  • write_program_eeprom (address, data): función homologa a la anterior pero que nos permite escribir datos en la memoria de programa. data tiene que ser un entero de 16 bits.


CCS también incorpora funciones para leer y escribir en memorias EEPROM externas:

read_external_memory(address, dataptr, count )
write_program_memory( address, dataptr, count)


Como veis CCS nos aporta una serie de funciones para trabajar fácilmente con este tipo de memorias,

estas que he puesto aquí son algunas de ellas, pero todavía hay más. Mejor ir viéndolas poco a poco con ejemplos.

Algunas consideraciones a tener en cuenta sobre las memorias EEPROM es que son rápidas en el proceso de lectura, pero pueden tardar varios ms en realizar un proceso de escritura. Otro factor a tener en cuenta es que se pueden hacer operaciones de lectura sobre el valor de sus registros el numero de veces que se quiera, pero soportan un número limitado de ciclos de escritura / borrado. Ese número según Microchip es de aproximadamente un millón, el que quiera que lo compruebe.

La memoria EEPROM de datos no está mapeada en la zona de la memoria de datos donde se ubican los registros SFR y GPR, si programáramos en Ensamblador deberíamos realizar una serie de pasos para su lectura y escritura que aunque no difíciles resultan al menos laboriosos, CCS nos permite abstraernos por completo del proceso de lectura y escritura, lo único que tenemos que saber es las funciones que tenemos que aplicar y los parámetros y valores que devuelven dichas funciones.

Como 1º ejemplo del uso de este tipo de memorias vamos a utilizar las funciones básicas para leer y escribir datos en la memoria interna del PIC: read_eeprom (address) y write_eeprom (address, value).

El ejemplo es un contador del tipo "su turno" que solemos encontrar en algunos establecimientos como carnicerías y pescaderías. Como funcionalidades mínimas he puesto que sea capaz de contar del 0 al 99.
Y por supuesto que si se va la corriente guarde en memoria el último valor.

El esquema del circuito será el siguiente:

Cuando queremos utilizar mas de un display y minimizar el número de patillas en el PIC para su control hay varias formas de hacerlo, una de ellas (la que he utilizado en este ejemplo) es utilizar un decodificador BCD a 7 segmentos como el 7447, el datasseht lo tenéis aquí. Donde se puede ver el diagrama lógico y su tabla de verdad.

Otra forma es multiplexar las líneas de datos, es decir en cada instante solo habrá un display activo pero el cambio de uno a otro será tan rápido que para el ojo humano parecerá que los dos están activos a la vez, este sistema es bueno porque nos ahorramos los decodificadores, pero si utilizamos mas de cuatro display, notaremos un parpadeo molesto.

El código del programa será el siguiente:

/*-----------------------------------------------------------*\

| Uso de la memoria EEPROM del PIC |

| autor: biblioman |

| www.aquihayapuntes.com |

\*-----------------------------------------------------------*/

#include <16F877.h>

//Configuración de los fusibles.

#FUSES NOWDT, XT, NOPUT, NOPROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG

#use delay(clock=4000000) //Frecuencia de reloj 4MHz

#byte puerto_D = 0x08 // Identificador para el puerto C.

#int_EXT

void EXT_isr( void )

{

if ((read_eeprom(0)==0x99)||(read_eeprom(0)==0xFF))

{

write_eeprom(0,0);

puerto_D=read_eeprom(0);

}

else if ((read_eeprom(0) & 0x0F)<0x09)

{

write_eeprom(0,(read_eeprom(0))+1);

puerto_D=read_eeprom(0);

}

else if ((read_eeprom(0) & 0x0F)>=0x09)

{

write_eeprom(0,(read_eeprom(0))+7);

puerto_D=read_eeprom(0);

}

}

void main()

{

set_tris_b(0xFF); //Puerto B como entrada

set_tris_d(0x00);//Puerto D como salida

enable_interrupts(GLOBAL); // Se habilita la interrupción global

enable_interrupts(INT_EXT); // Se habilita la interrupción externa

puerto_D =0xFF; //inicializo puerto D

//write_eeprom(0,0xFF);Resetear EEPROM

while(true)

{

//Resto del programa

}

}

Comentario del programa:

El ejemplo básicamente es un contador ascendente de 0 a 99 que incrementa su valor cada vez que pulsamos el pulsador "su turno" para evitar que el contador se reinicie y empiece a contar desde cero cada vez que se vaya la corriente, el valor actual del contador se almacenará en la memoria EEPROM del PIC en vez de en la memoria RAM. Como solo queremos guardar un valor que estará comprendido entre 0 y 99, solo utilizaremos el primer byte de la memoria EEPROM. Para detectar cuando se pulsa el pulsador, se utiliza la interrupción externa en la patilla RB0/INT.

Dentro de la función de interrupción nos encontramos con tres sentencias condicionales:

if ((read_eeprom(0)==0x99)||(read_eeprom(0)==0xFF))
{
write_eeprom(0,0);//escribo el valor 0 en la dirección 0 de la memoria EEPROM
puerto_D=read_eeprom(0);//asigno al puerto D el valor devuelto por la función de lectura de la EEPROM
}

La primera vez que se ejecute el programa el valor de la EEPROM es 0xFF (viene así de fabrica) por lo que tendremos que sobreescribir su valor a 0 para iniciar el contaje, después de esto esta condición solo se cumplirá cuando el contador llegue a 99.

else if ((read_eeprom(0) & 0x0F)<0x09)
{
write_eeprom(0,(read_eeprom(0))+1);
puerto_D=read_eeprom(0);
}


Cada "nibble" del puerto D está conectado a un decodificador por lo que tenemos RD0-RD3 al decodificador U2 y su salida conectado al display de las unidades a través del bus de datos (hay que hacer un zoom sobre el esquema en Proteus para ver las conexiones) y RD4-RD7 al decodificador U3, que está conectado al display de las decenas.


Pues bien, si tenemos 4 bits por "nibble" tendremos 16 combinaciones posibles, incrementamos con 1 el valor de la EEPROM mientras el valor del "nibble" de menor peso sea < 9. Fijaros como la función de escritura en la EEPROM nos permite poner como parámetro la función de lectura por lo que no es necesario declarar una variable local para hacer de intercambio.


Una vez incrementado el valor de la EEPROM, hacemos una nueva lectura y asignamos su valor al puerto D.

else if ((read_eeprom(0) & 0x0F)>=0x09)
{
write_eeprom(0,(read_eeprom(0))+7);
puerto_D=read_eeprom(0);
}


Los valores del "nibble" de menor peso correspondientes al rango 10-15 los saltamos sumando 7 en vez de uno. El nibble de mas peso de la lectura de la EEPROM no me interesa ya que el primer if ya se encarga de ponerlo a cero cuando el valor llegue a 0x99. Para discriminar el "nibble" de mas peso de la EEPROM lo enmascaramos antes de hacer la comparación

Podemos ver los registros de la EEPROM interna del PIC, si en Proteus seleccionamos Debug-->PIC CPU EPROM Memory.

Proteus simula bastante bien el uso de la memoria EEPROM del PIC, si paramos la simulación y volvemos a iniciarla vemos como los valores de la EEPROM se mantienen.