Saltar al contenido
Control Automático Educación

Memoria EEPROM del PIC

Hola controlero o controlera, hoy vamos a ver como usar la EEPROM Interna PIC para poder almacenar datos cruciales en nuestros proyectos con microcontroladores.

Antes de comenzar, te invito a que veas el CURSO GRATIS DE MICROCONTROLADORES PIC

EEPROM INTERNA PIC

El microcontrolador tiene memoria eeprom interna donde almacenar información en esta memoria tiene la gran ventaja de que los datos almacenados en ésta no se borraran a menos que se sobrescriba sobre ellos, es decir la información almacenada allí, no se borrara así se desenergice el microcontrolador. Aunque esta memoria es limitada es de gran utilidad en algunos controles. Te voy a mostrar como guardar datos en la memoria EEPROM del PIC CCS.

En esta entrada vas a aprender como usar la memoria eeprom del pic 16f877a, 16f887, 18f4550 entre otros. El procedimiento es el mismo, sin importar el PIC que utilices, lo único que deberás hacer es cambiar en el encabezado la librería del PIC que estes utilizando.

Tambien podria interesarte el conocer como almacenar datos en la 👉 memoria eeprom externa del PIC cuando no tenemos el suficiente espacio en la memoria interna

Como guardar datos en la memoria EEPROM del PIC CCS

Estas sencillas instrucciones son las que debemos usar si lo que deseamos es guardar o almacenar datos en la memoria EEPROM del PIC usando PIC C Compiler CCS.

Características de la Memoria EEPROM

Antes de comenzar es necesario entender como está conformada la memoria EEPROM dentro del microcontrolador PIC. Para posteriormente proceder a grabar datos en ella.

Cada microcontrolador tiene un tamaño específico de memoria EEPROM la cual debe ser consultada en su datasheet.

Esta memoria está segmentada a 1 byte por dirección (celda). La lista a continuación ilustra la cantidad de memoria disponible para microcontroladores utilizados en nuestro curso de PIC con CCS C.

  • PIC16F887 – 256 bytes
  • PIC16F877A – 256 bytes
  • PIC18F4550 – 256 bytes

A modo de ejemplo, en la siguiente imagen podemos ver como se distribuye la memoria EEPROM en estos microcontroladores:

EEPROM dentro del microcontrolador PIC
Dirección de Memória EEPROM dentro de los microcontroladores

⚠️ ATENCIÓN ⚠️

Las memorias EEPROM tienen una vida útil de aproximadamente 100000 escritas por cada una de las celdas de la memoria del PIC. Por lo que no puedes indiscriminadamente estar grabando en esta memoria constantemente porque vas a alcanzar ese límite.

Por eso almacena los datos de tu programa en periodos espaciados en el tiempo, o cuando algún evento especifico suceda.

También es una buena práctica no utilizar solo una celda, si no que por el contrario utilizar las 256 celdas y cuando estas estén llenas, volver a comenzar desde la celda cero.

Escribir memoria EEPROM del PIC

La instrucción para almacenar información en la memoria eeprom interna es la siguiente:

WRITE_EEPROM(dirección, valor)

dirección: Es un valor que comienza de 0 hasta le tamaño de la memoria del microcontrolador empleado. Ejemplo: 16F887 va de 0 a 255.

Valor: Es un byte, el cual será almacenado en la dirección especificada.

Leer memoria EEPROM del PIC

La instrucción para leer información en la memoria eeprom interna es la siguiente:

READ_EEPROM(dirección)

dirección: Es un valor que comienza de 0 hasta le tamaño de la memoria del microcontrolador empleado. Ejemplo: 16F887 va de 0 a 255.

Como ves el uso de la memoria EEPROM del PIC es muy sencillo, y una ves veas el fabuloso ejemplo de implementación tendrás las bases para crear tu propio proyecto!! Pues ya sabes como guardar datos en el PIC y que estos no se borren después de que dejes de alimentarlo.

Guardar int16 o float en la EEPROM Interna con PIC

En ocasiones podemos querer guardar números con signos o números que ocupen más de 8 bits. Recordemos que la memoria interna solo permite datos de 0 a 255. Pero si necesitamos números mayores a esos?

Para eso, podremos en lugar de almacenar los datos en 1 celda, lo haremos en 2 celdas.

Para eso usaremos las instrucciones del CCS conocidas como make8(), make16() y make32().

Cuando tenemos un int16, lo que hacemos es dividirlo en 2 datos de 8 bits con make8().

 int8 Data_h, Data_L;
   int16 DataLong;
   
   Data_H=make8(DataLong,1);
   Data_L=make8(DataLong,0); 
   
   WRITE_EEPROM(0,Data_H);
   WRITE_EEPROM(1,Data_L);

Luego cuando queramos leer esos datos, los leemos en dos variables int8 y los juntamos nuevamente en una variable int16 usando la función make16().

int8 Data_h, Data_L;
   int16 DataLong; 
   
   Data_H=READ_EEPROM(0);
   Data_L=READ_EEPROM(1); 
   DataLong=make16(Data_H,Data_L);

el mismo procedimiento puede ser aplicado con un float que posee 4 bytes, para eso podemos usar la instrucción make32(), y utilizar 4 bytes de la memoria eeprom.

Memoria EEPROM PIC

Para entender un poco mejor este concepto de como usar la memoria eeprom del pic 16f877a, pic 18f4550, pic 16f887, etc lo haremos a través de los siguientes ejemplos:

Primero, antes que nada debes saber que al final de este post, se encuentra el código gratuito para que aprendas a usar la memoria EEPROM interna del microcontrolador PIC, el ejemplo está hecho con el PIC16F887, sin embargo si deseas hacerlo con otro PIC, simplemente cambias el encabezado por las siguientes instrucciones

Memoria EEPROM interna pic 18f4550 o familia 18F

#include <18f4550.h>
#byte porta = 0xf80 // Identificador para el puerto A. 
#byte portb = 0xf81 // Identificador para el puerto B. 
#byte portc = 0xf82 // Identificador para el puerto C. 
#byte portd = 0xf83 // Identificador para el puerto D. 
#byte porte = 0xf84 // Identificador para el puerto E.

De esta forma conseguiras almacenar los datos en la memoria eeprom pic 18f4550.

Memoria EEPROM interna pic 16f877a o familia 16F

#include <16f877a.h>;

EEPROM PIC CCS

Para esto Preparé el siguiente video donde te explico la teoria de usar la memoria interna EEPROM del PIC, te explico el código que encontrarás en la parte inferior de la página, y te explico como podemos simularlo para que lo lleves a la práctica. No olvides suscribirte a mi canal de youtube dando click en el siguiente botón, para que puedas recibir toda la información que allí voy publicando.

Como guardar datos en la memoria EEPROM del pic ccs

Modificar el ejemplo visto en la entrada anterior, donde se solicitaba una contraseña por medio del teclado telefónico y se visualizaba en el LCD en forma de asteriscos.

La idea es entonces que el usuario pueda modificar la contraseña de acceso, pero para que haga esto, el programa deberá validar que el usuario conozca la contraseña actual.

La nueva contraseña debe escribir en la memoria EEPROM del PIC con el objetivo de que esta no se borre cuando el microcontrolador es des-energizado. (# Es el enter para la clave y * es la tecla para cambiar la clave)

Nota: Para saber cual es la clave actual dentro del proteus, cargar en el microcontrolador el archivo .cof en lugar del archivo .hex (como se muestra en el video), Luego le dan simular y seguidamente le dan pause. Les debe salir unas ventanas con el codigo del pic y con las variables. Buscar la variable que se llama contra, el valor de dicha variable es la contraseña.

Memoria EEPROM del PIC

Uso de la memoria EEPROM del PIC

Descargar el código de implementación de como usar la memoria eeprom del pic es muy simple, solo debes compartir el contenido de este POST utilizando uno de los siguientes tres botones que se encuentran aqui abajo.

[sociallocker id=”948″]

>> DESCARGAR CÓDIGO Y CIRCUITO EN PROTEUS <<

/****************************************************************
*****************************************************************
******                                                  *********
******    Ejemplo del uso de la memoria interna EEPROM  *********
******                                                  *********
******    By: Sergio Andres Castaño Giraldo             *********
******    https://controlautomaticoeducacion.com/       *********
******                                                  *********
*****************************************************************
****************************************************************/
#INCLUDE <16f887.h>
//#USE DELAY(CLOCK=4000000) // Reloj 4MHz
#use delay(clock=4000000,crystal)//Crystal Externo 4MHz
#FUSES XT,NOPROTECT,NOWDT,NOBROWNOUT,NOPUT,NOLVP
//Definiciones para colocar el LCD y el teclado en el puerto B
#DEFINE USE_PORTB_LCD TRUE
#DEFINE USE_PORTB_KBD TRUE  
//Librerías del LCD y Teclado
#INCLUDE <LCD.C>
#INCLUDE <KBD.C> 
//Definiciones
#BYTE PORTC= 7
#BYTE PORTB= 6
#DEFINE LED1 PORTC,4
#DEFINE LED2 PORTC,7
//Variables Globales
CHAR K;
INT8 MIL,CEN,DEC,UNI,VAL;
INT16 contra=9999; //Variable entera para almacenar la contraseña
INT8 sinal; //Variable para saber si tengo contraseña
VOID TECLADO()
{
k=kbd_getc(); //Llamar la función del teclado y almacenar
//el valor digitado en una variable tipo
//carácter. Si no se oprime ninguna tecla el
//teclado retornara el carácter nulo.*/
WHILE(k=='\0') //si no se oprime ninguna tecla sigue llamando al teclado.
{
k=kbd_getc();
}
IF( (k!='\0'))
{
IF(K=='0')//Si K es igual a cero
VAL=0;//Val es igual a cero
IF(K=='1')
VAL=1;
IF(K=='2')
VAL=2;
IF(K=='3')
VAL=3;
IF(K=='4')
VAL=4;
IF(K=='5')
VAL=5;
IF(K=='6')
VAL=6;
IF(K=='7')
VAL=7;
IF(K=='8')
VAL=8;
IF(K=='9')
VAL=9;
}
}
//Rutina para pedir la clave
void pedir_clave(void)
{
TECLADO();
IF((k!='#')&&(k!='*'))
{
lcd_putc('*');
MIL=VAL;
}
if(k=='*' || k=='#')
return;
TECLADO();
IF((k!='#')&&(k!='*'))
{
lcd_putc('*');
CEN=VAL;
}
if(k=='*' || k=='#')
return;
TECLADO();
IF((k!='#')&&(k!='*'))
{
lcd_putc('*');
DEC=VAL;
}
if(k=='*' || k=='#')
return;
TECLADO();
IF((k!='#')&&(k!='*'))
{
lcd_putc('*');
UNI=VAL;
}
if(k=='*' || k=='#')
return;
}
int validar_clave(void)
{
//Variables locales
int16 clave=0,m,c,d,u;
/* Para realizar la multiplicación cuando se tienen numeros del tipo int8, 
como por ejemplo 100 con otro tipo int8 como por ejemplo CEN, el programa
hará un producto int8, sin embargo se desea un resultado int16, por lo 
tanto debe informarce al compilador por medio de un 'cast' (c=(int16)CEN*100)
o utilizando la función de multiplicación de tipos del compilador (_mul)*/
m=MIL*1000; //Convierto miles a numero
//c=_mul(CEN,100); //Otra alternativa para multiplicar int8*int8=int16
c=(int16)CEN*100; //Convierto centemas, haciendo un CAST para obtener un int16
d=DEC*10; //Convierto decenas a numero 
u=UNI; //Convierto unidades a numero 
clave=m+c+d+u;
//Borra lo último que fue digitado en el teclado
MIL=0;CEN=0;DEC=0;UNI=0; 
if(clave==contra) //Si la clave es igual a la contraseña
return(1);
else
return(0);
}
void cambio_clave(void)
{
int bandera=0;
int16 clave=0,m,c,d,u;
LCD_PUTC("\f");
LCD_GOTOXY(1,1);
LCD_PUTC("CLAVE ACTUAL");
LCD_GOTOXY(1,2);      
pedir_clave(); //Llama la funcion de pedir la clave
bandera=validar_clave(); //Compruebo si la clave actual es correcta
if(bandera==1)
{
LCD_PUTC("\f");
LCD_GOTOXY(1,1);
LCD_PUTC("CLAVE NUEVA  ");
LCD_GOTOXY(1,2);   
TECLADO();
IF((k!='#')&&(k!='*'))
{
lcd_putc('*');
MIL=VAL;
}
TECLADO();
IF((k!='#')&&(k!='*'))
{
lcd_putc('*');
CEN=VAL;
}
TECLADO();
IF((k!='#')&&(k!='*'))
{
lcd_putc('*');
DEC=VAL;
}
TECLADO();
IF((k!='#')&&(k!='*'))
{
lcd_putc('*');
UNI=VAL;
}
m=MIL*1000; //Convierto miles a numero
c=CEN*10; //Convierto centemas a numero y lo sumo al anterior
c=c*10;
d=DEC*10; //Convierto decenas a numero y lo sumo al anterior
u=UNI; //Convierto unidades a numero y lo sumo al anterior
clave=m+c+d+u;
contra=clave;
WRITE_EEPROM(0,MIL); //Guarda en la eemprom posicion cero la nueva contraseña
WRITE_EEPROM(1,CEN);
WRITE_EEPROM(2,DEC);
WRITE_EEPROM(3,UNI);
WRITE_EEPROM(4,12); //Guardo un 12 en la posicion 1 de la EEPROM, para decir que tengo
//una contraseña guardada
}
else
{
LCD_PUTC("\f");
LCD_GOTOXY(1,2);
LCD_PUTC(" CLAVE INVALIDA ");
BIT_SET(LED2);
DELAY_MS(4000);
BIT_CLEAR(LED2);
LCD_PUTC("\f");
}
}
VOID MAIN()
{
//Variables Locales
int16 m,c,d,u;
INT8 m1,c1,d1,u1;
//Puerto C como Salida
SET_TRIS_C(0B00000000);
PORTC=0; //Limpia Puerto C
lcd_init(); //Inicializa el LCD
kbd_init(); //Inicializa el Teclado
//Configura las Resistencias PULL-UP del Puerto B
port_b_pullups(0xFF); //PIC16F887
//port_b_pullups(TRUE); //PIC16F877A
sinal=READ_EEPROM(4); //Averiguo si tengo una contraseña guardada o no
if(sinal!=12)
contra=9999;
else
{ 
//Lee los datos del EEPROM
m1=READ_EEPROM(0); 
c1=READ_EEPROM(1); 
d1=READ_EEPROM(2); 
u1=READ_EEPROM(3); 
/* Para realizar la multiplicación cuando se tienen numeros del tipo int8, 
como por ejemplo 100 con otro tipo int8 como por ejemplo CEN, el programa
hará un producto int8, sin embargo se desea un resultado int16, por lo 
tanto debe informarce al compilador por medio de un 'cast' (c=(int16)CEN*100)
o utilizando la función de multiplicación de tipos del compilador (_mul)*/
m=m1*1000; //Convierto miles a numero
//c=_mul(c1,100); //Otra alternativa para multiplicar int8*int8=int16
c=(int16)c1*100; //Convierto centemas, haciendo un CAST para obtener un int16
d=d1*10; //Convierto decenas a numero 
u=u1; //Convierto unidades a numero 
contra=m+c+d+u;
}
WHILE(TRUE)
{
LCD_PUTC("\f");
LCD_GOTOXY(1,1);
LCD_PUTC(" DIGITE CLAVE ");
LCD_GOTOXY(1,2);
DELAY_MS(1000);
pedir_clave(); //Llama la funcion de pedir la clave
if(k=='*')
cambio_clave();
else
{
WHILE((k!='#'))
{
TECLADO();
if(k=='*')
cambio_clave();
}
IF(validar_clave()==1) //Aquí se compara si
//los números digitados
//están correctos.*/
{
LCD_PUTC("\f"); //Se borra LCD
LCD_GOTOXY(1,1);//Se ubica en la posición 1,1
LCD_PUTC(" CLAVE CORRECTA ");
BIT_SET(LED1);
DELAY_MS(2000);
BIT_CLEAR(LED1);
}
ELSE
{
LCD_PUTC("\f");
LCD_GOTOXY(1,2);
LCD_PUTC(" CLAVE INVALIDA ");
BIT_SET(LED2);
DELAY_MS(4000);
BIT_CLEAR(LED2);
}
}
}
}

[/sociallocker]

Eso es todo por la entrada del dia de hoy, espero les haya gustado y hayan aprendido algo nuevo. Si te ha servido el contenido de esta entrada, de los videos y los códigos de implementación y deseas apoyar mi trabajo invitandome a un café super barato, puedes hacerlo en el siguiente link:

👉 Invitar a Sergio a un Café ☕️

Que esten muy bien, nos vemos en la siguiente entrada.

Entradas relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Comentarios (8)

Profe buenas noches, estoy haciendo un trabajo final que incluye está codificación, quisiera saber si en lugar de cambiar la clave presionando “*”, habría la posibilidad de cambiar con la interrupción externa 0. Lo que hice fue colocar el código del cambio_clave en la rutina de interrupción, pero me sale error al momento de llamar a las demás subrutinas como TECLADO, VALIDAR_CLAVE, no se si podría ayudarme por favor

Responder

Siempre que trabajes con rutinas de interrupción, tu código debe ser lo más corto posible y no quedarse haciendo muchas cosas dentro de ella. Podrías por ejemplo crear una bandera (variable) que únicamente cambie de estado lógico dentro de la interrupción y se salga. Y dentro del programa principal, colocas un condicional, si dicha bandera es verdadera, entonces que llame la función de cambio_clave. Es algo así que se me ocurre en este momento. Suerte.

Responder

Hola.
Después de almacenar datos en la eeprom de un 16f628A, los puedo leer correctamente mientras no apague el circuito.
Cuando apago y enciendo de nuevo, los datos almacenados en la eeprom han cambiado.

Podrías darme alguna luz?
No encuentro la razon del cambio en los valores almacenados.

Responder

Es muy extraño Luis, fíjate si talvez no estas sobre escribiendo los datos en alguna parte del código, especialmente antes de entrar al ciclo infinito. Realmente es muy raro que te pase eso.

Responder

Cuál es la capacidad de almacenamiento de la memoria EEPROM del microcontrolador 16F887?

Responder

Hol Ivan, el 16f887 tiene 256 bytes e EEPROM.

Responder

long int clave=0,m,c,d,u;

profe me perdi en la linea 101 no se que hace esta linea de instrucción

Responder

solo se están definiendo las variables de la función “validar_clave”. Se definen las 5 variables, clave,m,c,d,u. Solo que clave se carga con cero.

Responder