# Como usar la EEPROM de los PICs



## Marcelo (Oct 3, 2005)

*Usando la EEPROM de los PICs*  (ejemplo PIC 16x84)

Hemos visto que en muchos de los post y discusiones de este foro, hablamos de guardar los datos en la memoria EEPROM de los microcontroladores.

En realidad no sabemos hasta donde llega el conocimiento de todos los que leemos esos escritos, por lo tanto trataremos de hacer una pequeña introducción de cómo proceder para usar la memoria EEPROM.

Entonces, este mini tutorial está orientado a aquellos que no conocen o nuncan han intentado usar esta memoria.

Muchas veces (si no la mayoría de ellas) subutilizamos el MP (microprocesadores) basándonos en el software de control desarrollado en nuestras PC para guardar y leer los datos necesarios para el correcto funcionamiento de nuestras interfaces y circuitos de control, en lugar de emplear a fondo las facilidades que nos prestan.

Existen muchas ventajas en guardar los datos en la memoria no volátil del MP. La más inmediata y evidente es disponer en forma instantánea de las condiciones iniciales o de arranque para el funcionamiento de la electrónica de control. 

Por ejemplo, imagínense que hemos diseñado un circuito que utiliza un motor paso a paso para colocar en determinado lugar una banda transportadora. Sabemos que el motor deberá moverse desde 0 (inicio de la banda) hasta X pasos (final de la banda).  Dentro de la memoria EEPROM podríamos almacenar el valor de X (numero de pasos totales para recorrer la banda) y el valor de Y (lugar o número de pasos en donde se detuvo por última vez el motor). De esta forma, el circuito podría usar su “memoria” para conocer estos datos al encenderlo en lugar de esperar que algún otro proceso externo se lo informe. Otros datos que pudiéramos guardar serían por ejemplo, el valor de corrección de “backslash” o de movimiento inercial de la banda para corregir ese error acumulativo.

Para explicar como usar la EEPROM, vamos a basarnos en nuestro PIC de pruebas que es el ya famoso 16x84. Para utilizar cualquier otro, haremos uso de las datasheets para conocer la equivalencia de los comandos, el tamaño de la EEPROM y sus direcciones de inicio y final. En el caso de 16x84 tenemos los siguientes datos:

*Tamaño de la EEPROM: 64 bytes  - 8 Bits por byte
Dirección de Inicio: 	0h
Dirección Final:	3Fh*

Para acceder a esos 64 bytes usamos un direccionamiento indirecto. Esto quiere decir que la DIRECCIÓN específica de la memoria EEPROM que nos interesa (de los 64 disponibles) estará almacenada en un registro determinado y por consiguiente, para que el programa del MP sepa donde leer o grabar tendremos que buscarlo en ese registro específico.

Este registro junto con otros cuatro que sirven para controlar todo el proceso de lectura y escritura, son los siguientes:

*EEADR
EEDATA
EECON1
EECON2*

1)	*EEADR* contiene la dirección o posición de la memoria EEPROM que queremos acceder bien sea para leerla o escribirla. Como este registro es un BYTE de 8 Bits, pudiéramos entonces representar 256 distintos valores sin embargo solo necesitamos 64 de ellos para acceder a toda la memoria por lo que, los bit 6 y 7 no se usan y deberán ser siempre cero (recuerden que los 8 bits los numeramos desde el 0 al 7).

2)	*EEDATA* va a contener como su nombre lo indica, el dato leido o el que deseamos guardar.

3)	La misión de *EECON1* es controlar los procesos de escritura/lectura de la memoria. De sus 8 bits disponibles solo se usan los 5 de menos peso.  Estos bits son: 
a.	Bit0: *RD* de  “Read Data”, se pone a 1 cuando se va a realizar un ciclo de LECTURA desde la EEPROM, y vuelve automáticamente a 0 cuando se temina ese proceso.

b.	Bit 1: *WR* de “Write Data”, se pone a 1 cuando se va a realizar un ciclo de ESCRITURA hacia la EEPROM, y vuelve automáticamente a 0 cuando se temina ese proceso.

c.	Bit 2: *WREN* de “Write Register ENable”. Si está a 1 PERMITE el proceso de escritura hacia la EEPROM y si está a 0, no lo permite.

d.	Bit 3: *WRERR* de “Write Register ERRor”. Se va a 1 cuando un proceso de ESCRITURA  no se realizó correctamente y a 0 en caso contrario. 

e.	Bit 4: *EEIF* de “EEprom Interrupt Finalization”. Al colocarse a 1, indica que la operación de ESCRITURA a finalizado con éxito. Si se quiere colocarla a 0, deberá hacerse por programa.

4)	*EECON2* no está físicamente implementado y es empleado como un dspositivo de seguridad durante el proceso de escritura de la EEPROM. Si se lee, todos sus bits estarán a 0.

Un ciclo de escritura de una localidad de memoria de la EEPROM tarda aproximadamente para estos MP con cristales de 4 MHz, unos 10 ms.  Este tiempo es muy largo comparado con la velocidad del MP y por esta razón se hacen tantos esfuerzos en controlar su escritura y lectura.

*Leer los datos de la EEPROM*:

Según lo que vimos anteriormente, para leer los datos de la EEPROM deberemos hacer lo siguiente:

1)	Cargar la dirección que deseamos leer en EEADR
2)	Poner a 1 el Bit RD del registro EECON1 indicándole al MP que lea la dirección
3)	Y por último transferir al acumulador o al literal deseado el dato leído desde EEDATA

El código típico sería así (Recuerden que debemos de haber incluido el archivo 16F84A.INC donde se definen los registros del PIC). La variable DIRE debimos haberla declarado al comienzo del programa.


```
bcf          ESTADO,RP0	;Seleccionamos el Banco 0
movlw	     DIRE			;Ponemos en W la dirección que vamos a leer
movwf	     EEADR		;y pasamos W al registro EEADR, definiendo la dirección a leer
bsf		ESTADO,rp0		; Seleccionamos el Banco 1
bsf		EECON1,RD		;Hacemos la lectura colocando RD a 1 
bcf		ESTADO,RP0	;y regresamos al Banco 0
movf	      EEDATA,W		;para finalmente rescatar el dato desde EEDATA hacia W
```

Esta es una codificación básica que puede servir de modelo de arranque para sus diseños.

*Escribir los datos en la EEPROM*:

Anteriormente dijimos que EECON2 no estaba implementado en forma física y que si lo leíamos obtendríamos 0 pero, cumple funciones de control sobre la escritura que si deberemos considerar. 

Para esto, usaremos dos valores específicos, el 55h y el AAh.

Dado el tiempo que tarda el proceso de escritura comparado con el tiempo de ejecución del MP, estos dos valores permitirán al MP realizar acciones de sincronismo y control en el proceso de escritura de la EEPROM, así es que el código deberá tener un par de instrucciones de escrituras en EECON2 que parecieran no tener sentido pero que siempre deberemos usar, al menos en esta gama de PICs.

El código sería el siguiente:
Las variables DIRE y ESCR la debimos de haber declarado al comienzo del programa.



```
bcf		STATUS,RP0		;Seleccionamos Banco 0
movlw		DIRE			;Ponemos en W la dirección que vamos a escribir
movwf		EEADR		;y la guardamos en EEADR
movlw		ESCR			onemos ahora el dato a escribir en W
movwf		EEDATA		;y lo guardamos en EEDATA

bsf		STATUS,RP0		;Seleccionamos Banco 1
bsf 		EECON1,WREN 	;Colocamos el permiso de escritura (WREN) en EECON1 a 1
					;Aquí da inicio la secuencia de escritura

movlw		0x55 h			;Inicio de las intrucciones para EECON2
movwf		EECON2
movlw		0xAA h		
movwf		EECON2		;Fin de las intrucciones para EECON2

bsf		EECON1,WR		;Comienza la escritura propiamente dicha.
```

Cuando se complete todo el proceso de escritura, el Bit WR se pondrá a 0 automáticamente y el señalizador de interrupciones  EEIF pasará a valer 1  (y allí se quedará hasta que lo coloquemos a 0 por programa).

Si se quiere realizar un proceso simple de verificación de escritura adicional, podemos restar el dato que hemos escrito al valor actual del registro EEDATA. Si no hubo errores entonces esta resta debe dar 0 y por lo tanto el bit Z (cero) del registro de ESTADO se colocará a uno indicando esta condición, lo que nos servirá de bandera de comprobación.

Seguramente habrán diferencias notables en el manejo de lectura/escritura de otros modelos de PIC y de otra marca de microcontroladores pero su base de funcionamiento es prácticamente la misma.

Deberán tener en cuenta que el proceso de escritura de un byte, borra automáticamente la posición de memoria y luego escribe el dato es decir, borra antes de escribir, así es que tendrán que rescatar el dato anterior antes de su escritura si lo quieren utilizar para algo.

Las memorias EEPROM resisten hasta un millón de ciclos de Lectura/Escritura y además pueden almacenar sus datos en forma contínua sin degradación por alrededor de 40 años.

Para los que no lo saben, EEPROM significa: Electrically Erasable Programmable Read Only Memory, que en castellano podría ser algo como: Memoria Programable de Solo Lectura Borrable Eléctricamente (MPSLBE ?????).

Espero les sea de utilidad esta explicación y comiencen a sacarle más provecho a sus MC.

Saludos,
Marcelo.


----------



## roggers (Nov 13, 2009)

ooooooo ase tiempo que queria utilizar la eeprom pero no entiendo como funciona aun 
vamos a practicar y para ver cuanto entendi
siempre q uso algun pic lo apago y se borra la info de algun proceso o datos del trabajo xP
pero ahora podre realizar un proyecto mejor!
dommo arigato


----------



## RBX374 (Nov 17, 2009)

se puede grabar y leer la eeprom desde el ordenador?
gracias


----------



## roggers (Nov 17, 2009)

realize unas pequeñas pruebas y me funcionaron! 

ahora podre mejorar mas aun mis proyecto lo que no me gusto fue la rutina muy larga :enfadado: me desconfigura lo que es transmicion de datos
ahora estos datos se pueden leer con el pc
yo utilizo el icprog para grabar los datos al PIC, cuando leo el PIC no me sale en ningun lado  los datos 


muchas gracias
saludos


----------



## 0rland0 (Dic 10, 2009)

Bueno yo como necesito tener una constante estoy tratando de ponerla en la EEPROM y leerla pero no me funciona. Esto es lo q tengo escrito:

#include"p16F877.INC"
list p=16F877

NUM1 EQU 0X16F
NUM2 EQU 0X1EF
SUMA EQU 0X72
AUX EQU 0X20

ORG 0X00
BCF STATUS,RP0
MOVLW 0X00
MOVWF EEADR
BSF STATUS,RP0
BSF EECON1,RD
BCF STATUS,RP0
MOVF EEDATA,W
BANKSEL AUX
MOVWF AUX
END

Escribo esto a manera de "jugar" para ver si lo carga correctamente a la direccion 20h del registro, y por supuesto el problema es q no lo esta cargando. Apenas tengo 2 o 3 dias de haberme iniciado en esto asi q encontrar errores me cuesta por ahora


----------



## ELIUSM (Feb 7, 2010)

Hola!
Aquí les tengo otro programita, por si acaso, nada más.


```
;Configuración del PIC 16F84A
STATUS    EQU    0x03
PORTA    EQU    0x05
PORTB    EQU    0x06
TRISA    EQU    0x85
TRISB    EQU    0x86
EECON1    EQU    0x88
EECON2    EQU    0x89        ;Registro virtual
EEDATA    EQU    0x08
EEADR    EQU    0x09
INTCON    EQU    0x0B
W        EQU    0
RD        EQU    0
F        EQU    1
WR        EQU    1
RP0        EQU    5
GIE        EQU    7
WREN    EQU    2

RESULT    EQU    0x0C

;Seteo para la inicialización de puertos del 16F84A
    bsf        STATUS,RP0
    clrf    TRISA
    clrf    TRISB
    bcf        STATUS,RP0
;Limpiar puertos
    clrf    PORTA
    clrf    PORTB

;Ejemplo de escritura
    movlw    0x01            ;Referecia a la posición 01 de la memoria
    movwf    EEADR
    movlw    0x0A            ;Dato a escribir en la posición 01 de la memoria
    movwf    EEDATA
    call    WRITE_EEPROM    ;Mandar a escribir en EEPROM

;Ejemplo de lectura
    movlw    0x01            ;Referecia a la posición 01 de la memoria
    movwf    EEADR
    call    READ_EEPROM        ;Mandar a leer tal dirección
    movwf    RESULT            ;Meter dato leído en RESULT

    goto    FIN                ;Irse al fin.

WRITE_EEPROM        ;Ingrese EEADR y EEDATA (Dirección y dato a escribir)
    bsf        STATUS,RP0            ; Banco 1
    bcf        INTCON,GIE            ; Desactivar interrupciones.
    bsf        EECON1,WREN            ; Activar escritura en EEPROM
    movlw    0x55                ;                         Obligado
    movwf    EECON2                ; Escribir 55h             Obligado
    movlw    0xAA                ;                         Obligado
    movwf    EECON2                ; Escribir AAh             Obligado
    bsf        EECON1,WR            ; Mandar a escribir

    bcf        EECON1,WREN            ; Enable Write
    bcf        STATUS,RP0            ; Banco 0
;      bsf        INTCON,GIE            ; Activar INTs. (Solo para reactivar INTs
    clrw                        ;  por si acaso las tenía activadas de antes)

READ_EEPROM            ;Lea W
    bsf        STATUS,RP0            ; Banco 1
    bsf        EECON1,RD            ; Activar lectura
    bcf        STATUS,RP0            ; Banco 0
    movf    EEDATA,W            ; W = EEDATA
            ;EEDATA guardado en W, después leer de W.

FIN
    goto    FIN

END

;Este programa está hecho de la manera más simple posible para
;que se entienda cómo esribir y leer la EEPROM del PIC.
;Vienen dos subrutinas grandes que se pueden usar fácilmente con
;"call" para grabar o leer.
```

Saludos!


----------



## Jamual (Mar 18, 2010)

HOLA A TODOS, gracias MARCELO por la información esta muy buena, pero yo tengo una pregunta:
-Diseñé una consola de citofonia con MP 16F877A, en la memoria EEPROM grabamos los numeros correspondientes a cada pin. Por Ejemplo: 
RB1=101-RB2=102-RB3=103-RB4=104; Pero resulta que en algunas ocasiones se me borran los números o se alteran y no de toda la memoria EEPROM si no de uno o dos.

Al MP le entran señales de 5V por los pines, pero es posible que este Voltaje se incremente debido a sobre tensiones en la red, puede ser esta la causa de este problema???. Les agradezco cualquier aporte que me puedan hacer.


----------



## Chico3001 (Mar 19, 2010)

lo mas seguro es que sea un error en tu programa que le ordene al pic sobreescribir los valores de la EEPROM....


----------



## josb86 (Mar 27, 2010)

alguien sabe como se lee y escribe y se borra una eeprom con picbasic?



			
				josb86 dijo:
			
		

> alguien sabe como se lee y escribe y se borra una eeprom con picbasic?



Upss perdón ya lo encontré simplemente con el comando WRITE perdonen


----------



## wosuej (Ago 5, 2010)

holaa a todos, hay manera de escribir y leer en la eeprom pero en alto nivel?


----------



## PiTter M (Sep 10, 2010)

hola tengo problemas para guardar un dato en la eepron del pic 18f2550 en CCS
pongo #rom 2100 {'1','2','3','4'} no recuerdo si es parentecis o corchetes 
pero cuando simulo en el proteus en la eepron no guarda nada q se puede hacer


----------



## LxL (Oct 27, 2010)

Hola!
Yo tengo que pasar un numeros de 14BITs a BCD, entonces necesito saber como utilizar una EEprom, porque me han comentado que la direccion puede ser el numero en binario (00000001111111) y eso tendria como salida el numero en BCD, osea (0000 0000 0001 0010 0111). En otras palabras necesito una Eeprom de 14 inputs y 17 outputs. 

¿Hay alguna?


----------



## biopic (Oct 28, 2010)

RBX374 dijo:


> se puede grabar y leer la eeprom desde el ordenador?
> gracias



si , de hecho casi cualquier software como el win pic o ic prog te da la opcion de borrar o escribir en la eeprom antes de programar el micro al igual que  configuras los fusibles . saludos


----------



## cesar Alvarez (Dic 12, 2010)

Hola A todos .
tengo un problema en gravar la EEPROM del PIC 16f877A.
He seguido las instrucciones del data sheet pero no me funciona.
Si reviso el programa con el debugger, me funciona perfecto , pero en la practica no guarda el ultimo numero.

ESTE ES MI PROGRAMA. por si alguien me puede ayudar. también quiero gravar varias posiciones de memoria.
Con el pic 16F628.
lo pude hacer y grave hasta 16 diferentes valores en la memoria , sin que se borraran al faltar la alimentación, Pero este PIC 16F877A me esta sacando canas verdes.
Gracias

```
;    *************************************    7_tes_22.ASM    ********************
;    ************************************    7_tes_20.asm    ****************************
;    ***************************************    7_tes-19.ASN    ****************]
;

    LIST    P=16f877A
    INCLUDE    <P16F877A.INC>

        __CONFIG    _CP_OFF &  _WDT_OFF & _PWRTE_OFF & _XT_OSC & _LVP_OFF & _BODEN_OFF
    CBLOCK    0x20
    ADDR_L
    DATA_L
    Refresca
    Guarda_DATOS

    Contador
    ENDC



    ORG    0x00
    NOP
    NOP
    GOTO    Inicio
;*************************************
Inicio
    BSF    STATUS,RP0
    BCF    STATUS,RP1
    CLRF    TRISA
    MOVLW    B'00000001'
    MOVWF    TRISB
    MOVLW    B'00000000'
    MOVWF    TRISC
    CLRF    TRISD
    CLRF    TRISE
    BCF    STATUS,RP0
    BCF    STATUS,RP1
    MOVLW    .90
    MOVWF    Refresca
    CLRF    PORTC
    GOTO    Principal
;***********************************
Principal
    MOVF    ADDR_L,W    
    CALL    LEER_EEPROM
    MOVF    Guarda_DATOS,W
    MOVWF    DATA_L
    MOVF    DATA_L,W
    CALL    Visualiza
    BTFSS    PORTB,0
    GOTO    Principal
    CALL    Espere
    GOTO    Incrementa
    GOTO    Principal
;********************************
Espere
    BTFSC    PORTB,0
    GOTO    Espere
    RETURN
;***********************************
Incrementa
    MOVF    Contador,W
    MOVWF    Contador
    INCF    Contador,F
    MOVF    Contador,W
    MOVWF    DATA_L
    MOVF    DATA_L,W
    MOVF    ADDR_L,W
    CALL    ESCRIBIR_EEPROM
    MOVF    DATA_L,W
    MOVWF    Contador
    MOVF    Contador,W
    MOVWF    Guarda_DATOS
    GOTO    Principal
;***********************************
Visualiza
    MOVF    DATA_L,W
    CALL    Tabla
    MOVWF    PORTC
    BSF    PORTC,6
    BCF    PORTC,5
    CALL    Retardo_500micros
    BCF    PORTC,6
    CALL    Retardo_500micros    
    DECFSZ    Refresca,F
    GOTO    Visualiza
    MOVLW    .90
    MOVWF    Refresca
    RETURN
;***********************************
ESCRIBIR_EEPROM
    BCF    STATUS,RP0
    BCF    STATUS,RP1
    MOVF    ADDR_L,W
    BCF    STATUS,RP0
    BSF    STATUS,RP1
    MOVWF    EEADR
    BCF    STATUS,RP0
    BCF    STATUS,RP1
    MOVF    DATA_L,W
    BCF    STATUS,RP0
    BSF    STATUS,RP1
    MOVWF    EEDATA
    BSF    STATUS,RP0
    BSF    STATUS,RP1
    BCF    EECON1,EEPGD
    BSF    EECON1,WREN
    BCF    INTCON,GIE
    MOVLW    55H
    MOVWF    EECON2
    MOVLW    0xAA
    MOVWF    EECON2
    BSF    EECON1,WR
    BSF    INTCON,GIE
Loop
    BTFSC    EECON1,WR
    GOTO    Loop
    BCF    PIR2,EEIF
    BCF    EECON1,WREN
    BCF    STATUS,RP0
    BCF    STATUS,RP1
    RETURN
;******************************
LEER_EEPROM
    BCF    STATUS,RP0
    BCF    STATUS,RP1
    MOVF    ADDR_L,W
    BCF    STATUS,RP0
    BSF    STATUS,RP1
    MOVWF    EEADR
    BSF    STATUS,RP0
    BSF    STATUS,RP1
    BCF    EECON1,EEPGD
    BSF    EECON1,RD
    BCF    STATUS,RP0
    BSF    STATUS,RP1
    MOVF    EEDATA,W
    BCF    STATUS,RP0
    BCF    STATUS,RP1
    MOVWF    DATA_L
    RETURN
;**********************************
Tabla
    ANDLW    B'00001111'
    ADDWF    PCL,F
    RETLW    B'00000000'
    RETLW    B'00000001'
    RETLW    B'00000010'
    RETLW    B'00000011'
    RETLW    B'00000100'
    RETLW    B'00000101'
    RETLW    B'00000110'
    RETLW    B'00000111'
    RETLW    B'00001000'
    RETLW    B'00001001'

    INCLUDE    <RETARDOS.ASM>
    END
```


----------



## Meta (Dic 12, 2010)

Un ejemplo.


```
;************************************ EEPROM_01.asm **********************************
;
;    ====================================================================
;      Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS".
;      E. Palacios, F. Remiro y L. López.        www.pic16f84a.com
;       Editorial Ra-Ma.  www.ra-ma.es
;    ====================================================================
;
; Este programa comprueba el funcionamiento de la lectura y escritura en la memoria
; EEPROM de datos. Cada vez que el sistema es reseteado se incrementa un contador que 
; se guarda en la primera posición de la memoria EEPROM de datos del PIC y es visualizado
; en el módulo LCD.
;
; ZONA DE DATOS **********************************************************************

    LIST        P=16F84A
    INCLUDE        <P16F84A.INC>
    __CONFIG    _CP_OFF &  _WDT_OFF & _PWRTE_ON & _XT_OSC

    CBLOCK   0x0C
    Contador
    ENDC        

    ORG    0x2100                ; Corresponde a la dirección 0 de la zona EEPROM de datos.
    DE    0x00                ; El contador en principio a cero.
    
; ZONA DE CÓDIGOS ********************************************************************

    ORG     0                        ; El programa comienza en la dirección 0.
Inicio
    call    LCD_Inicializa
    clrw                            ; Leerá la primera posición de memoria EEPROM.
    call    EEPROM_LeeDato
    movwf    Contador                ; Se guarda en Contador.
    call    BIN_a_BCD                ; Se visualiza en BCD
    call    LCD_Byte                ; con nibble alto apagado si es cero.
    movlw    MensajeReseteado
    call    LCD_Mensaje
    incf    Contador,W                ; Se incrementa y se graba en 
    call    EEPROM_EscribeDato        ; EEPROM de datos.
Principal
    sleep                            ; Pasa a modo de reposo.
    goto    Principal

; "Mensajes" ----------------------------------------------------------------------------
;
Mensajes
    addwf    PCL,F    
MensajeReseteado
    DT " reseteados.   ", 0x00
FinMensajes

    INCLUDE   <EEPROM.INC>            ; Subrutinas básicas de control de la EEPROM de
    INCLUDE   <RETARDOS.INC>        ; datos del PIC.
    INCLUDE   <BIN_BCD.INC>
    INCLUDE   <LCD_4BIT.INC>
    INCLUDE   <LCD_MENS.INC>
    END

;    ====================================================================
;      Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS".
;      E. Palacios, F. Remiro y L. López.        www.pic16f84a.com
;       Editorial Ra-Ma.  www.ra-ma.es
;    ====================================================================
```


Librería EEPROM.INC

```
;***************************** Librería "EEPROM.INC" **********************************
;
;    ====================================================================
;      Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS".
;      E. Palacios, F. Remiro y L. López.        www.pic16f84a.com
;       Editorial Ra-Ma.  www.ra-ma.es
;    ====================================================================
;
; Estas subrutinas permiten realizar las tareas básicas de escritura y lectura de la
; memoria EEPROM de datos del PIC.
;
; Subrutina "EEPROM_LeeDato" ------------------------------------------------------------
;
; El microcontrolador lee el dato que hay escrito en la posición de la EEPROM del PIC apuntada
; por el contenido del registro de trabajo W. El resultado se proporciona en el mismo W.
;
; Entrada: En (W) la dirección de la memoria EEPROM a leer.
; Salida :  En (W) el byte leído.

EEPROM_LeeDato
    bcf        STATUS,RP0            ; Asegura que trabaja con el Banco 0.
    movwf    EEADR                ; Dirección a leer.
    bsf        STATUS,RP0            ; Banco 1.
    bsf        EECON1,RD            ; Orden de lectura.
EEPROM_SigueLeyendo
    btfsc    EECON1,RD            ; El PIC indica que ha terminado la lectura
    goto    EEPROM_SigueLeyendo    ; poniendo en bajo este bit.
    bcf        STATUS,RP0            ; Banco 0.
    movf    EEDATA,W            ; El byte leído al registro W.
    return

; Subrutina "EEPROM_EscribeDato" --------------------------------------------------------
;
; Escribe el dato introducido en el registro de trabajo W en la posición de memoria EEPROM del
; PIC apuntada por el registro EEADR.
;
; Como altera el valor del registro INTCON al posicionar el flag GIE, éste se debe guardar al
; principio de la subrutina y restaurarlo al final.
;
; Entradas:    En el registro EEADR la dirección de la memoria EEPROM a escribir.
;        En el registro W el byte a escribir.
;
    CBLOCK
    EEPROM_GuardaINTCON
    ENDC

EEPROM_EscribeDato
    bcf        STATUS,RP0            ; Asegura que trabaja con el Banco 0.
    movwf    EEDATA                ; El byte a escribir.
    movf    INTCON,W            ; Reserva el valor anterior de INTCON
    movwf    EEPROM_GuardaINTCON
    bsf        STATUS,RP0            ; Acceso al Banco 1.
    bcf        INTCON,GIE            ; Deshabilita todas las interrupciones.
    bsf        EECON1,WREN            ; Habilita escritura.
;
; El fabricante especifica que hay que seguir esta secuencia para escritura en EEPROM:
;
    movlw    0x55
    movwf    EECON2
    movlw    0xAA
    movwf    EECON2
    bsf        EECON1,WR            ; Inicia la escritura.
EEPROM_TerminaEscribir
    btfsc    EECON1,WR            ; Comprueba que termina de escribir en la EEPROM.
    goto    EEPROM_TerminaEscribir
    bcf        EECON1,WREN            ; Desautoriza la escritura en EEPROM.
    bcf        EECON1,EEIF            ; Limpia este flag.
    bcf        STATUS,RP0            ; Acceso al Banco 0.
    movf    EEPROM_GuardaINTCON,W ; Restaura el valor anterior de INTCON.
    movwf    INTCON
    return

;    ====================================================================
;      Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS".
;      E. Palacios, F. Remiro y L. López.        www.pic16f84a.com
;       Editorial Ra-Ma.  www.ra-ma.es
;    ====================================================================
```


----------



## cesar Alvarez (Dic 13, 2010)

Bueno mis apreciados amigos.
Ayer escribi solicitando ayuda para poder escribir y leer en la memoria EEPROM del PIC 17F877A.
La verdad estaba mas enredado que un bulto de anzuelos.
Agradezco la intervención de Meta.
la grabación y lectura de la EEPROM de datos ya la había realizado con el PIC 16F628. Pero infortunadamente el único que tenia se me dano, y tuve que migrar al 877a. La verdad no lo conozco bien.
Después de muchas canas logre hacer un programita donde gravo 4  posiciones EEPROM, y me las conserva aun después de perder la alimentación.
Es un programa bien TONTO, pero solo es para aprender a como grabarlas,
Imagino debe haber mejores maneras, pero esta fue la única que se ocurrió, y "" Funciono"".
Dejo el programa por si a alguien le puede ayudar . Saludos.



```
;*************************************    7_tes_24.ASN;        
;Cesar Alvarez  CAAV_1    

    LIST    P=16f877A
    INCLUDE    <P16F877A.INC>

        __CONFIG    _CP_OFF &  _WDT_OFF & _PWRTE_OFF & _XT_OSC & _LVP_OFF & _BODEN_OFF

    CBLOCK    0x20        ; Macro para el Cblock desde la posicion 0x20 Comensarea guardar variables            

    DIR_GRAL        ; Variable para las diferentes posiciones
                ; de Memoria que voy a gravar y Leer ( ADRESS)
    DATO            ; Variable para almacenar el dato, QUE: voy a leer y luego 
                ; a Gravar.
    Refresca        ; Demora para la visualizacion
    
    ENDC
    ORG    0x2100        ; Esta es una parte que no he entendido bien
    DE    H'0'        ; Pero la utilize con el pic 16f628
    DE    H'0'        ; y funciona, Ahora bien Si no coloco esto
    DE    H'0'        ; NO FUNCIONARA.
    DE    H'0'        ; Si alguien me puede explicar esta parte lo agradecereia mucho.
                ; Creo que si voy a gravar mas posiciones debere colocar mas DE H'0'


    ORG    0x00
    NOP
    NOP
    GOTO    Inicio
;*************************************
Inicio
    BSF    STATUS,RP0
    BCF    STATUS,RP1
    CLRF    TRISA
    MOVLW    B'00000001'        ; PORTB,0 Como entrada de pulsador
    MOVWF    TRISB
    MOVLW    B'00000000'
    MOVWF    TRISC            ; PORTC  Como Salida para display 7 seg Con DM 7447 
    CLRF    TRISD
    CLRF    TRISE
    BCF    STATUS,RP0
    BCF    STATUS,RP1
    MOVLW    .200
    MOVWF    Refresca        ; Demora para visualizar
    CLRF    PORTC
    MOVLW    0x06
    MOVWF    ADCON1
    MOVLW    .0            ; Comienzo dato en 0
    MOVWF    DATO
    CLRF    EEDATA
    GOTO    Principal
;***********************************
Principal
                    ; primero que todo leo lo que hay en cada posicion
    
                    ; de memoria y luego la visualizo
    MOVLW    .1            ; desde la posicion 1 hasta la 4
    MOVWF    DIR_GRAL
    CALL    LEE_EEPROM
    MOVF    DATO,W
    CALL    Visualiza

    MOVLW    .2            ;  numero de direccion a leer
    MOVWF    DIR_GRAL        ; La cargo a DIR_GRAL para que luego vaya a ADDR
    CALL    LEE_EEPROM
    MOVF    DATO,W            ; Traigo el Dato leido en esta posicion de memoria
    CALL    Visualiza        ; y lo visualizo

    MOVLW    .3
    MOVWF    DIR_GRAL
    CALL    LEE_EEPROM
    MOVF    DATO,W
    CALL    Visualiza

    MOVLW    .4            ; Al comenzar y hasta que no digite el pulsador
    MOVWF    DIR_GRAL        ; se quedara leyendo las 4 posiciones de memoria 
    CALL    LEE_EEPROM
    MOVF    DATO,W            ; y las visualizara
    CALL    Visualiza
;*******************************

    BTFSS    PORTB,0            ; Cuando digito el pulsador
    GOTO    Principal
Uno    BTFSC    PORTB,0            ; Comenzara a gravar en EEPROM
    GOTO    Uno

    MOVLW    .3            ; Coloco el dato que quiero gravar en EEPROM            
    MOVWF    DATO            ; a variable DATO luego ira a EEDATA
    MOVLW    .1            ; Coloco numero de direccion que quiero leer
    MOVWF    DIR_GRAL        ; En  DIR_GRAL luego ira  a EEADR
    CALL    ESCRIBA_EEPROM        ; GRAVO EL NUMERO 3 En LA POSICION 1 DE EEPROM
    ;MOVF    DATO,W

    MOVLW    .6
    MOVWF    DATO
    MOVLW    .2
    MOVWF    DIR_GRAL
    CALL    ESCRIBA_EEPROM        ; ASI susesivamente gravare las 4 posiciones
    ;MOVF    DATO,W
                    ; Este es un ejercicio algo tono 
    MOVLW    .9
    MOVWF    DATO            ; pero lo utilize solo para ver como podia gravar
    MOVLW    .3
    MOVWF    DIR_GRAL
    CALL    ESCRIBA_EEPROM
    ;MOVF    DATO,W

    MOVLW    .1
    MOVWF    DATO
    MOVLW    .4
    MOVWF    DIR_GRAL
    CALL    ESCRIBA_EEPROM
    ;MOVF    DATO,W    

    GOTO    Principal
;********************************

Visualiza
    MOVF    DATO,W            ; Traigo el dato leido de EEPROM de la 
    CALL    Tabla            ; respectiva direccion , llamo la tabla
    MOVWF    PORTC            ; y lo envio al DM 7447 y de ahi al Disp 7 seg
    BSF    PORTC,6            ; Habilito el anodo de Display para que ilumine
    
    CALL    Retardo_500micros    ; Durante este tiempo
    BCF    PORTC,6
    CALL    Retardo_500micros    ; Apago el display durante este tiempo    
    DECFSZ    Refresca,F
    GOTO    Visualiza        ; Visualizare este mnismo dato 200 veces 
    MOVLW    .200            ; con diferncia de 1000micros cada vez 
    MOVWF    Refresca        ; es solo para verlo funcionar mas adelante lo haremos mejor
    RETURN
;***********************************
ESCRIBA_EEPROM
    BCF    STATUS,RP0        ;Estas rutinas son las data sheet PIC 16F87 Para 
    BCF    STATUS,RP1
    MOVF    DIR_GRAL,W        ; Escritura y Lectura
    BCF    STATUS,RP0
    BSF    STATUS,RP1
    MOVWF    EEADR
    BCF    STATUS,RP0
    BCF    STATUS,RP1
    MOVF    DATO,W
    BCF    STATUS,RP0
    BSF    STATUS,RP1
    MOVWF    EEDATA
    BSF    STATUS,RP0
    BSF    STATUS,RP1
    BCF    EECON1,EEPGD
    BSF    EECON1,WREN
    BCF    INTCON,GIE
    MOVLW    55H
    MOVWF    EECON2
    MOVLW    0xAA
    MOVWF    EECON2
    BSF    EECON1,WR
    BSF    INTCON,GIE
Loop
    BTFSC    EECON1,WR
    GOTO    Loop
    BCF    PIR2,EEIF
    BCF    EECON1,WREN
    BCF    STATUS,RP0
    BCF    STATUS,RP1
    RETURN
;******************************
LEE_EEPROM
    BCF    STATUS,RP0
    BCF    STATUS,RP1
    MOVF    DIR_GRAL,W
    BCF    STATUS,RP0
    BSF    STATUS,RP1
    MOVWF    EEADR
    BSF    STATUS,RP0
    BSF    STATUS,RP1
    BCF    EECON1,EEPGD
    BSF    EECON1,RD
    BCF    STATUS,RP0
    BSF    STATUS,RP1
    MOVF    EEDATA,W
    BCF    STATUS,RP0
    BCF    STATUS,RP1
    MOVWF    DATO
    RETURN
;**********************************
Tabla
    ANDLW    B'00001111'
    ADDWF    PCL,F
    RETLW    B'00000000'
    RETLW    B'00000001'
    RETLW    B'00000010'
    RETLW    B'00000011'
    RETLW    B'00000100'
    RETLW    B'00000101'
    RETLW    B'00000110'
    RETLW    B'00000111'
    RETLW    B'00001000'
    RETLW    B'00001001'

    INCLUDE    <RETARDOS.ASM>
    END
```


----------



## Lvcios (Ene 16, 2011)

Oigan, tengo una  duda. Mi grabador de pics me dice que hay error en la memoria flash del pic16f628a en la posición 0x0000000 . Significa que ya no sirve para nada?


----------



## mcaco (Ene 28, 2011)

Estimados tengo una duda existencial, alguien pudo escribir la EEPROM de un 16f84A. Dado que esto me esta volviendo loco, si bien recién arranco con los microcontroladores ha programado en c durante mucho tiempo por lo que me fue mas fácil comenzar usando CCS. He leído muchos post de este y otros foros tratando de encontrar la forma de hacer esto, el tema esta que las funciones read_eeprom y write_eeprom me funcionan cuando simulo en prteus pero al grabar el pic no puedo escribir, si leer, ya que si modifico la EEPROM en el firmware luego puedo leer los daos, pero no modificarlos. Ha armado distintas variantes incluyendo código ASM dentro del código c y hasta arme un programita en assembler para que me grabe una posición de memoria pero no he logrado que funcione, siempre lo mismo en la simulación anda pero en la vida real no.


  Desde ya les agradezco cualquier ayuda que puedan brindarme.

  Les dejo los ejemplos con los que estuve probando:

  En C:

```
#include <16f84a.h>
  //#include <def_F84.h>
  #fuses XT,NOWDT
  #use delay(clock= 4000000)
  #include <lcdpic16f84a.c>
  #use standard_io (A)
  #use standard_io (B)
  int v1,v2,v3;
   
   
  void Leer () {
  v1=read_eeprom (4);
  v2=read_eeprom (5);
  v3=read_eeprom (6);
  }
   
  void Escrbir () {
  write_eeprom (4,4);
  write_eeprom (5,5);
  write_eeprom (6,6);
  }
  void Poncero() {
  write_eeprom (4,0);
  write_eeprom (5,0);
  write_eeprom (6,0);
  }
   
  void main () {
  lcd_init();
  while (1){
        if (input(PIN_A0)==1) { //escribo
        delay_ms (200);
        Escrbir();
        lcd_putc('\f');
        lcd_gotoxy(1,1);
        printf (lcd_putc,"Mem.Escrita");
        }
        if (input(PIN_B0)==1) {//Leo
        delay_ms (200);
        Leer();
        lcd_putc('\f');
        lcd_gotoxy(1,1);
        printf (lcd_putc,"MEM:%u | %u | %u",v1,v2,v3);
        }
        if (input(PIN_A4)==1) {//Borro
        delay_ms (200);
        Poncero();
        lcd_putc('\f');
        lcd_gotoxy(1,1);
        printf (lcd_putc,"Mem.Borrada");     
        }
  }
   
  }
```
  El ASM:


```
; **** Encabezado ****
  list p=16F84A
  #include P16F84A.inc
  __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
   
  GUARDAR
  BANKSEL    EEDATA
  movf H'A', W  
  movwf EEDATA
  movlw H'18'
  movwf EEADR
  bcf INTCON, GIE
  bsf STATUS,RP0
  bcf EECON1,WRERR
  bsf EECON1,WREN
  movlw H'55'
  movwf EECON2
  movlw H'AA'
  movwf EECON2
  bsf EECON1,WR
  ES1 nop
  btfss EECON1,EEIF
  goto ES1
  nop
  btfsc EECON1,WRERR
  goto GUARDAR
  nop
  bcf EECON1,EEIF
  bcf EECON1,WREN
  bcf STATUS,RP0
  bsf INTCON, GIE
  ESPERA
  nop
  goto ESPERA
  end
```


----------



## mcaco (Ene 29, 2011)

Me respondo a mi mismo.
Despues de un dia sin dormir (algunos diran, esta loco, pero bue, soy asi) les cuento que el problema aparentemente estaba en el osilador dado que probe con otro pic, un 16f873 que es mucho mas groso que 16f84 para descartar problemas de el chip y ademas como estoy usando CCS quiza el codigo que generase fuera distinto, me paso exactamente lo mismo hasta que reubique el xtal, lo puse lo mas cerca que pude del pic y magicamente empezo a funcionar,es verdad lo que se dice que el xtal tiene que estar lo mas proximo el pic posible, este caso lo demuestra. Una vez que funciono el 16f873 hize lo mismo para el 16f84 y "magia otra vez" ya los tengo andando.

Si les intereza les puedo subir el proyecto completitio asi lo usan como base para ortas cosas o se arman un temporizador que llega has 225 hs 59 mins 59 sec.


Saludos a todos.

PD: las funciones que use para grabar y escribir son las que vienen con CCs write_eeprom y read_eeprom.


----------



## HUEVOCOP (Feb 24, 2011)

compañeros soy nuevo en esto de microprosesadores  me podrian enseñar o dar una idea de como hacer un programa que tenga un cliclo que cuando sea 10 se termine 

saludos


----------



## biopic (Feb 25, 2011)

hola pues puedes hacerlo mediande un contador, tu le asignas el valor y cuando llege al avlor deseado termina el lazo, podira ser algo asi

PRINCIPAL MOVLW .10 ; CARGO EL PALOR PARA EL CONTADOR 10 DECIMAL EN TU CASO
                  MOVWF 0X20 ; LO MUEVO AL CONTADOR (REGISTRO DE LA MEMORIA RAM) 
                   .
                   .
                   . AQUI IRIA EL RESTO DE TU CODIGO
                   .
                   .
                   DECFSZ 0X20  ;INCREMENTO EL CONTADOR EN UNO Y HASTA QUE SEA CERO TERMINA 
                   GOTO PRINCIPAL  ; EL LAZO ES DECIR SOLO LO HARA LAS 10 VECES QEU DESEAS
                   END
ESPERO TE SIRVA DE ALGO, YO TAMMBIN ESTOY EMPEZANDO JAJAJ UN SALUDO A TODO EL FORO


----------



## peterdbp (Abr 26, 2011)

Hola! 

Yo tengo un problema no se si sea cosa de electrónica o del software, resulta que utilizo un pic16f84a, lo utilizo para controlar posiciones de motores y guardo datos en la EEPROM, en la protoboard arme el circuito y funciona de maravilla, pero una vez que hice el circuito impreso, el motor reacciona adecuadamente y el PIC manda los mensajes correctamente pero al momento de guardar los datos en la EEPROM esta se pasma, pense que era cosa de los pulsadores al dar la orden de guardado pero no fue asi, los pulsadores envian la señal correctamente y sin rebotes, pienso que tal vez sea cosa de la alimentacion del PIC, pues utilizo pilas de 9v en conjunto con un lm7805. 

Agradesco cualquier comentario, critica, propuesta, maña, etc.

Saludos!


----------



## biopic (Abr 26, 2011)

hola , ponle un capacitor de 100nf entre la alimentaciona y la tierra del pic lo mas cercano que puedas , o pues prueba con al 16f628a es "guerrero" jaja de hecho es el sucesor del 84a


----------



## peterdbp (Abr 27, 2011)

Ok biopic, voy a seguir tu consejo y publico lo que sucedio, por el momento gracias!

Puse el capacitor y siguió igual, pero esta vez se me ocurrió sustituir la pila temporalmente por una fuente de voltaje, y para mi sorpresa el circuito logro borrar la EEPROM, puse los mismos 9V para que el 7805 lo redujera a 5v(mas o menos) y pude utilizar la EEPROM de manera correcta, ¿sera que la pila de 9v no me da la corriente necesaria para que se logre la interrupcion de la EEPROM? voy a mejorar la fuente de alimentacion posiblemente sea por eso.

Hay luego les platico como me fue.


----------



## biopic (Abr 27, 2011)

pues de hecho el pic no consume mucha corriente , estamos hablando de µAmperes lo que consume el pic estando activo por lo que deberia funcionar correctamente con la pila pero pues ahora si que la excepcion hace la regla o la rompe ???? jajaj pero pue si ya te vas a ventar la fuente de alimentacion  escoge una de 5v ya para que conectes el pic directamente sin necesidad de regular la corriente en tu circuito de la aplicacion yo las que he usado han sido desde 750mA hasta 2 amperes , pues ai nos cuentas  como te fue y si encontraste alguna otra solicion , saludos


----------



## peterdbp (May 9, 2011)

Hola, perdón la tardanza, encontré la posible causa de que la EEPROM no funcionara adecuadamente, y es un viejo enemigo de todos los que entramos al mundo de la electrónica: la electricidad estática, aun no estoy muy convencido de lo que suceda al 100% pero note que en mi escritorio donde realizo los proyectos, si el circuito lo alimento con la fuente regulada, el circuito funciona, pero cuando usa la pila, comienza a fallar. Ahora, si ese mismo circuito lo llevo a otro lugar y lo vuelvo a activar con la pila de 9v, el sistema funciona correctamente, lo que me hace pensar que es la estática, y afecta al funcionamiento de la EEPROM, solo es una teoría, hasta ahorita ha funcionado, al menos que alguien la contradiga(y me gustaría para saber mas del tema). Para aislar la cara del circuito donde tengo las pistas de cobre pienso ponerle una base de caucho o de madera para evitar lo mas que se pueda la estática.

Creo que hablar mas del tema se saldría de la sección de EEPROM, así que hasta aquí le dejo, voy a intentarlo y luego posteo un tema acerca de los resultados.


----------



## aszul (Jun 1, 2011)

hola a todos soy nuevo en ese foro.... y quisiera aprender a programar  la eeprom de un pic en PIC BASIC


por ejemplo 
cont var BYTE

:ini
if porta.0 = 1 then up
if porta.1 = 1 then down
goto ini


:up
pause 200
cont=cont+1
if cont=10 then accion
goto ini


:down 
pause 200
cont=cont-1
goto ini


:accion
high portb.0
goto ini


quiero almasenar el ultimo estado del pic...

aunque lo desconecte de la alimentacion........  

otra pregunta.... como puedo independisar una rutina del resto del programa.......

gracias


----------



## Palvulito (Jun 24, 2011)

Hola estoy utilizando el 16f886 y como puedo saber las direccion para guardar datos en la eeprom en c, estaba programando en ccs c y utilice esto

#rom 0x2100 = { '2', '3', '4' } //Posicion 0,1,2 de la eeprom con los datos 2,3,4.

pero cuando quise guardar otros numeros en otra posicion como en 4,5,6 no reconoce los datos guardados,no se si las direcciones siguientes son estas, espero que me puedan ayudar gracias.

#rom 0x2101 = {}
   #rom 0x2109 = {}
   #rom 0x210A = {}
   #rom 0x2112 = {}
   #rom 0x211A = {}
   #rom 0x2122 = {}
   #rom 0x212A = {}
   #rom 0x2132 = {}


----------



## loudness (Jul 3, 2012)

Me rindo . Estre unas cosas y otras estoy a punto de rendirme con esto de los pics. Os cuento:

OBJETIVO: Estoy intentado hacer pruebas con la EEPROM de un 16F877A. Para ello he escrito un programa en assembler (ni idea de c) que incrementa un registro (CONTADOR) cada vez que un pulsador (PORTC ,0) es accionado. El resultado de este registro se visualiza por un LCD (PORTD). Cada vez que el pulsador se acciona y se incrementa el registro, este deberia guardarse en la posicion 0x00 de la eeprom para que cuando el PIC se encienda otra vez despues de un reset o un apagado no se pierda el numero de veces.

PROBLEMA: EL pulsador funciona, y cada vez que se pulsa se ve el incremento en la pantalla... el caso es que el resultado no se guarda en la eeprom asi que cuando reseteo, el contador esta a cero   Probando en el simulador del MPLAB parece que la cosa no va mal (a lo mejor me equivoco en la forma de probar) pero probado con proteus y en un protoboard no funciona..... 

He probado con las rutinas que vienen en el datasheet de microchip, con las del libro de pic16f84 (desarrollo de proyectos) intentando adaptarlas, con otras que encontre en internet y hasta me anime a escribir las mias propias..... nada, que no lo consigo. Cada vez que reseteo se pone a cero 

Se que es Julio y la gente ya esta de vacaciones pero si hay alguien por aqui le agradecere cualquier ayuda o consejo. 
Adjunto el programa:




```
LIST      P=16F877A
   INCLUDE      <P16F877A.INC>
   
   __CONFIG    _CP_ALL & _DEBUG_OFF & _WRT_OFF & _CPD_ON & _LVP_OFF & _BODEN_ON & _HS_OSC & _WDT_OFF & _PWRTE_ON

CONTADOR         equ      0x049      
EEPROM_GuardaINTCON   equ      0x04A

#DEFINE   Pulsador   PORTC, 0         

V_RESET      org          0x000
         nop
         nop
             goto         main

main   bcf      STATUS,   RP0
      clrf   PORTC
      clrf   PORTD
      bsf      STATUS,   RP0
      clrf   PORTD
      movlw   b'11111111'
      movwf   PORTC
      bcf      STATUS, RP0

;****************************** INICIO *********************************

Inicio   
      call      LCD_Inicializa
      movlw      0x00            ;carga la posicion de memoria donde esta el dato
      call      EEPROM_LeeDato      ;lee el dato y lo trae a w 
      movwf      CONTADOR         ;mueve el dato al registro contador
      call       LCD_Linea1   
      movfw      CONTADOR
      clrf      NumH
      movwf      NumL
      call       LCD_Dec      
      movfw      Tenk
      call      LCD_Caracter
      movfw      Thou   
      call       LCD_Caracter   
      movfw      Hund
      call       LCD_Caracter
      movfw      Tens
      call       LCD_Caracter
      movfw      Ones
      call       LCD_Caracter

Principal
      btfss   Pulsador            ; Lee el pulsador.
      call   IncrementaVisualiza      ; Salta a incrementar y visualizar el contador.
      goto   Principal

IncrementaVisualiza
      call   Retardo_20ms
      btfsc   Pulsador
      goto   Fin_Visualiza
      call       LCD_Linea1   
      incf   CONTADOR,F   
      movfw      CONTADOR
      clrf      NumH
      movwf      NumL
      call       LCD_Dec      
      movfw      Tenk
      call      LCD_Caracter
      movfw      Thou   
      call       LCD_Caracter   
      movfw      Hund
      call       LCD_Caracter
      movfw      Tens
      call       LCD_Caracter
      movfw      Ones
      call       LCD_Caracter         ; Incrementa el contador y lo visualiza.
Visualiza
      movlw   b'00000000'
      movwf   EEADR               ; datos donde se guarda el turno. En este caso en 
      movfw   CONTADOR            ; la posici 00h de la EEPROM.
      call   EEPROM_EscribeDato
EsperaDejePulsar
      btfss   Pulsador
      goto   EsperaDejePulsar
Fin_Visualiza
      return

;***********************************RUTINAS PARA LA MEMORIA EEPROM**************************************
;************************************RUTINA DE LECTURA**************************************************
; Entrada: En (W) la direcci de la memoria EEPROM a leer.
; Salida :  En (W) el byte le冝o.
EEPROM_LeeDato
   bsf      STATUS, RP1
   bcf      STATUS, RP0         ; Asegura que trabaja con el Banco 0.
   movwf   EEADR            ; Direcci a leer.
   bsf      STATUS,RP0         ; Banco 1.
   bcf      EECON1,EEPGD
   bsf      EECON1,RD         ; Orden de lectura.
EEPROM_SigueLeyendo
   btfsc   EECON1,RD         ; El PIC indica que ha terminado la lectura
   goto   EEPROM_SigueLeyendo   ; poniendo en bajo este bit.
   bcf      STATUS,RP0         ; Banco 0.
   movf   EEDATA,W         ; El byte le冝o al registro W.
   bcf      STATUS,RP1
   return

;*************************************RUTINA DE ESCRITURA**********************************************
; Entradas:   En el registro EEADR la direcci de la memoria EEPROM a escribir.
;      En el registro W el byte a escribir.
;
EEPROM_EscribeDato
   bsf      STATUS,RP1
   bcf      STATUS,RP0         ; Asegura que trabaja con el Banco 0.
   movwf   EEDATA            ; El byte a escribir.
   bcf      STATUS,RP1
   movlw   b'00000100'
   bsf      STATUS,RP1
   movwf   EEADR
   bsf      STATUS,RP0
   bcf      EECON1, EEPGD
   bsf      EECON1,WREN         ; Habilita escritura.
   movlw   0x55
   movwf   EECON2
   movlw   0xAA
   movwf   EECON2
   bsf      EECON1,WR         ; Inicia la escritura.
;   movf   INTCON,W         ; Reserva el valor anterior de INTCON
;   movwf   EEPROM_GuardaINTCON
DES   btfsc   EECON1,WR         ; Comprueba que termina de escribir en la EEPROM.
   goto   DES
   goto   EEPROM_TerminaEscribir

;   bsf      STATUS,RP0         ; Acceso al Banco 1.
;   bcf      INTCON,GIE         ; Deshabilita todas las interrupciones.

EEPROM_TerminaEscribir
   bcf      EECON1,WREN         ; Desautoriza la escritura en EEPROM.
;   bcf      EECON1,EEIF         ; Limpia este flag.
   bcf      STATUS,RP0         ; Acceso al Banco 0.
   bcf      STATUS,RP1
;   movf   EEPROM_GuardaINTCON,W ; Restaura el valor anterior de INTCON.
;   movwf   INTCON
   return

   #INCLUDE  <LCD_4BIT.INC>         
   #INCLUDE  <RETARDOS.INC>
   #INCLUDE  <BIN_DEC.INC>

   END
```


Si es necesario os puedo enviar las rutinas <LCD_4BIT>, <BIN_DEC> y <RETARDOS>, pero siempre utilizo las mismas y hasta ahora ningun problema asi que de momento no las pongo.

Gracias por adelantado.
Saludos.


----------



## johenrod (Jul 29, 2012)

Marcelo dijo:


> *Usando la EEPROM de los PICs*  (ejemplo PIC 16x84)
> 
> Hemos visto que en muchos de los post y discusiones de este foro, hablamos de guardar los datos en la memoria EEPROM de los microcontroladores.
> 
> ...



cordial saludo..
te cuento mi hermano que tenia unas notas para escribir en la eeprom y por alguna razon no las encuentro, pero con tu explicacion apenas fue.
soy mas bien novato en esto de los pic´s y nunca tuve la necesidad de usarla hasta ahora. voy a tratar de implementarla, mi idea es almacenar varios numeros /claves y despues validarlas.
me gustaria hacerlo con este pic 16f1827, que problemas crees que tendria ..
un abrazo desde Medallo.
gracias por todo.


----------



## Meta (Ago 2, 2012)

Hola:

En el datasheet página 102 sobre la EEPROM te indica como debes hacerlo.

http://ww1.microchip.com/downloads/en/DeviceDoc/41391D.pdf


```
BANKSEL EEADRL ;
MOVLW DATA_EE_ADDR ;
MOVWF EEADRL ;Data Memory
;Address to read
BCF EECON1, CFGS ;Deselect Config space
BCF EECON1, EEPGD;Point to DATA memory
BSF EECON1, RD ;EE Read
MOVF EEDATL, W ;W = EEDATL
```

Un saludo.


----------



## ilcapo (Ago 12, 2014)

que tal, les comento que estuve viendo que siempre guardan o leen enteros, pero se puede guardar en la memoria EEPROM un valor decimal ( float ) ?? por ejemplo si queremos guardar un valor entre 0 y 1 ,,, el 0,3 como tendriamos que hacer ? si no se puede guardar decimales la verdad que la EEPROM es de muy poca utilidad en la practica real ya que casi nunca un resultado nos va a dar un numero entero, espero sus comentarios, saludos !


----------



## Miembro eliminado 356005 (Ago 12, 2014)

Pues hay varias técnicas, pero lo fundamental es saber el rango de esos números flotantes.

Un ejemplo. Supongamos que queremos guardar una temperatura, en un rango que va desde el 0.0 al 25.5. Entonces podemos guardar ese dato en un solo byte: sólo tenemos que multiplicar la temperatura por diez 

Y lo mismo si el rango es entre 20.0 y 45.5 (sólo tenemos que restar 20.0 antes de multiplicar por diez).

Si el rango es distinto, necesitaremos más bytes.

Si, por ejemplo, queremos guardar un dato entre 0.00 y 655.35, podemos guardarlo en dos bytes, con tan solo multiplicar el valor por cien.

O si es entre 0.000 y 65.535, multiplicando por mil.
O entre 0.0000 y 6.5535, multiplicando por diez mil.
O entre 0.00000 y 0.65536, multiplicando por cien mil.

Finalmente, si queremos más precisión (más decimales significativos) necesitaremos más bytes. Según la biblioteca que estés usando, los valores en punto flotante pueden estar en formato parecido al IEEE 754.

O hacerlo de forma manual.

Por otra parte, en los micros que almacenan más de 8 bits por palabra, ya hay bibliotecas que permiten guardar números en punto flotante de forma directa (como era el caso de los DSP).


----------



## Meta (Ago 12, 2014)

He leído en Internet que PIC18F puede multiplicar y dividir directmente en asm. Los 16F solo restar y sumar. ¿Es cierto?


----------



## Miembro eliminado 356005 (Ago 12, 2014)

Ejemplo de división.


----------



## cesar Alvarez (Ago 12, 2014)

Para Loudness

Mira Creo que te falta una expresion al final del programa .
Copio el final de tu programa

EEPROM_TerminaEscribir
   bcf      EECON1,WREN         ; Desautoriza la escritura en EEPROM.
;   bcf      EECON1,EEIF         ; Limpia este flag.
   bcf      STATUS,RP0         ; Acceso al Banco 0.
   bcf      STATUS,RP1
;   movf   EEPROM_GuardaINTCON,W ; Restaura el valor anterior de INTCON.
;   movwf   INTCON
   return

*ORG 0x2100

      DE  H'0'
*
   #INCLUDE  <LCD_4BIT.INC>         
   #INCLUDE  <RETARDOS.INC>
   #INCLUDE  <BIN_DEC.INC>

   END

De todas maneras manana en el dia revisare tu programa , pero prueba esto para ver.
OK ?


----------



## Daniel Meza (Oct 12, 2014)

Meta dijo:


> He leído en Internet que PIC18F puede multiplicar y dividir directmente en asm. Los 16F solo restar y sumar. ¿Es cierto?



Sólo multiplicar 

Ando con un problema ahora que ando trabajando con la EEPROM interna de los PIC18; quiero definir unos bytes de inicio desde el MPLAB para lo cual hago uso de la directiva DE:


```
ORG			0XF00000			;Vector de inicio de la EEPROM
	
	DE	0x00					;Contador de segundos almacenado en EEPROM
	DE	0x30					;Contador de minutos almacenado en EEPROM
	DE	0x05					;Contador de horas almacenado en EEPROM
	DE	0x12					;Día de mes de inicialización
	DE	0x10					;Mes de inicialización
	DE	0x14					;Año de inicialización
```

Pero al momento de compilar y ver los datos en la EEPROM, los valores que quiero me los define como palabras de 16 bits:



¿Cómo puedo hacer para que estos datos se definan como bytes?

Saludos


----------



## Miembro eliminado 356005 (Oct 12, 2014)

Según la documentación, *de* en los PIC18 empaqueta palabras, mientras que en los PIC16 empaqueta bytes.

Prueba con esto:

    de 0x0030
    de 0x0512


----------



## Daniel Meza (Oct 12, 2014)

Justo eso ando leyendo ahora Joaquín, parece que hallé una solución más "elegante"... en el manual de MPASM página 85 comenta el uso de una directiva: "code_pack" pero parece que tengo que guardar los datos en otro archivo, no lo entiendo del todo 

http://ww1.microchip.com/downloads/en/DeviceDoc/33014L.pdf

Puedo zafarme del problema definiendo la palabra entera pero, por comodidad, me gustaría definir byte por byte


----------



## Miembro eliminado 356005 (Oct 12, 2014)

Tienes que usar code_pack como inicio de región, y luego poner las directivas *de:*


```
datos_eeprom	code_pack	0xF00000	; Puntero a la EEPROM

		de	0x00	;Contador de segundos almacenado en EEPROM
		de	0x30	;Contador de minutos almacenado en EEPROM
		de	0x05	;Contador de horas almacenado en EEPROM
		de	0x12	;Día de mes de inicialización
		de	0x10	;Mes de inicialización
		de	0x14	;Año de inicialización
```


----------



## Daniel Meza (Oct 12, 2014)

Eso hago pero al compilar me sale el error:

_*Error[149]   C:\MPLAB\PIC18F\PRENSA.ASM 1820 : Directive only allowed when generating an object file*_


```
ORG			0xF00000				;Vector de inicio de la EEPROM
	
EEPROM_DAtos code_pack 	

	DE	0x00							;Contador de segundos almacenado en EEPROM
	DE	0x30							;Contador de minutos almacenado en EEPROM
	DE	0x05							;Contador de horas almacenado en EEPROM
	DE	0x12							;Día de mes de inicialización
	DE	0x10							;Mes de inicialización
	DE	0x14							;Año de inicialización
```

¿Tendrá que ver con que uso la opción de _Quickbuild..XX_?


----------



## Miembro eliminado 356005 (Oct 12, 2014)

¿A qué línea corresponde la 1820?

Según la documentación, estás usando una directiva que es incompatible con la generación de código en modo absoluto.

No me gusta lo de mezclar ORG con code_pack. ¿Probaste como te dije?


----------



## Daniel Meza (Oct 12, 2014)

Corresponde a la línea donde coloqué la directiva Etiqueta code_pack 0xF00000
ya probé quitando el ORG y aún así me da error


----------



## Miembro eliminado 356005 (Oct 12, 2014)

Primero hay que saber si estás construyendo el programa en modo absoluto o relativo.

Como tienes directivas ORG, lo más seguro es que sea absoluto. Vete a las opciones del proyecto, y en la parte de mpasm (opciones globales), fíjate que esté activada la opción "Build in absolute mode".

En cuanto al código, fíjate que puse 0xF00000 después de code_pack, para indicar la dirección de comienzo de los 'de'.


----------



## Daniel Meza (Oct 12, 2014)

Que relajo, he metido los archivos .asm que incluye el programa en un proyecto para poder modificar las "option build", lo curioso es que funcionó al revés; es decir con la opción "Build in absolute mode" desactivada y "generate relocatable code" activada. 
He compilado el proyecto y los datos se acomodaron como quería, byte por byte 

Aquí el código:


```
ORG			0xF00000				;Vector de inicio de la EEPROM
	
EEPROM_DAtos code_pack 0xF00000 	

	DE	0x00							;Contador de segundos almacenado en EEPROM
	DE	0x30							;Contador de minutos almacenado en EEPROM
	DE	0x05							;Contador de horas almacenado en EEPROM
	DE	0x12							;Día de mes de inicialización
	DE	0x10							;Mes de inicialización
	DE	0x14							;Año de inicialización
```

Como siempre, gracias Joaquín por la ayuda


----------



## Miembro eliminado 356005 (Oct 12, 2014)

Generalmente, no es necesario activar la opción "Construir en modo absoluto", porque la sola presencia de directivas ORG es más que suficiente, ya que esta directiva indica que lo que sigue es una sección absoluta.

code_pack, en cambio, solo funciona en modo reposicionable o relativo, así que si queremos que cierto rango de bytes vayan en una determinada dirección, pues entonces hay que indicar la dirección de comienzo de esa sección a la derecha de la directiva code_pack.


----------



## Daniel Meza (Oct 12, 2014)

Entendido, vaya que fue un dolor de cabeza, desde la mañana andaba tratando de definir bien los bytes, me quedé con la costumbre de que en la serie 16F los DE si s definen por bytes.

 pero aún quitando la dirección a la derecha de code_pack se compila el código sin problemas, en la guía de usuario que puse en mensajes pasados dice que ese campo es opcional, si se pone, el compilador toma esa dirección para posicionar los datos, si no se coloca, el compilador coloca los datos en la dirección siguiente a la última instrucción que compiló


----------

