Uso de EEPROM interna en XC8

Hola, quiero aprender a usar la EEPROM interna del 16F84A usando como compilador el XC8.

En el programa la idea es almacenar 4 mensajes en la EEPROM e ir mostrándolos por un LCD 16x2. Me estoy basando en la estructura de un programa hecho en CCS.

Estoy dando palos de ciego a parte de que hay algún fallo de sintaxis.

El código:

PHP:
/* 
 * File:   main.c
 * Author: nimio
 *
 * 16F84A
 *
 * COMPILADOR XC8
 *
 * EN ESTE PROGRAMA SE USA LA EEPROM PARA ALMACENAR 4 MENSAJES QUE SE MOSTRARÁN
 * EN EL LCD 16X2
 *
 * Created on 5 de abril de 2013, 5:10
 */

#include <xc.h>
#include "LCD/LCDGeneric.h"

#define _XTAL_FREQ 4000000

#pragma config FOSC=XT, WDTE=OFF, PWRTE=ON, CP=OFF



void main(void) {

    char ultdire=0, dire;  // VARIABLES DE DIRECCIÓN ESCRITURA EEPROM Y MENSAJE.
                           // ÚLTIMA DIRECCIÓN Y DIRECCIÓN.

    //MENSAJES A ESCRIBIR EN EEPROM INTERNA Y MOSTRAR EN LCD.
    char mensaje1="MENSAJE 1";  // (30) MENSAJE 1
    char mensaje2="PRUEBA";  // (31) MENSAJE 2
    char mensaje3="FUNCIONAMIENTO EEPROM"; // (32) MENSAJE 3
    char mensaje4="nimio 2013";  // (33) MENSAJE 4

    vInitLCD();
    EECON1bits.WREN=1; // HABILITA ESCRITURA
    EEADR=ultdire; // SE ALMACENA LA POSICIÓN DE MEMORIA EN EEADR.
    EEDATA=mensaje1;  // ALMACENA EL DATO.
    ultdire++;
    EEADR=ultdire;
    EEDATA=mensaje2;
    ultdire++;
    EEADR=ultdire;
    EEDATA=mensaje3;
    ultdire++;
    EEADR=ultdire;
    EEDATA=mensaje4;

    for (;;) {

        for (ultdire=0;ultdire<4;ultdire++) {

            dire=EEADR(ultdire);  // (56) ALMACENA MENSAJE DE LA DIRECCIÓN EEPROM
            vPuts_LCD(dire);  // (57) MUESTRA MENSAJE POR PANTALLA LCD
            __delay_ms(500);
            vLCD_Putc('\f');  // BORRA LCD
        }
    }

}


Los errores que me da el compilador (He puesto en los comentarios del programa el número de línea correspondiente entre paréntesis):

main.c:30: warning: illegal conversion of pointer to integer
main.c:31: warning: illegal conversion of pointer to integer
main.c:32: warning: illegal conversion of pointer to integer
main.c:33: warning: illegal conversion of pointer to integer
main.c:56: error: function or function pointer required
main.c:56: error: pointer required
main.c:57: warning: illegal conversion of integer to pointer

He mirado por el foro pero no acabo de aclararme en cuanto al procedimiento (y sintaxis) de escribir/leer en EEPROM.

Agradecería ayuda.

1 Saludo.
 
Hola, indagando un poco y rompiéndome la cabeza creo que tengo una aproximación por así decirlo.
Me compila todo bien, pero me encuentro que no puedo mostrar el mensaje por el LCD.

Intuyo que el problema está en la sintaxis de vPuts_LCD para mostrar el mensaje contenido en la variable dire. Tal vez tenga que usar printf? He visto que usan este comando junto con % para indicar el contenido de una variable, pero no se usar printf. Aunque también puede que no haya conseguido grabar nada en la EEPROM y por eso no muestre el mensaje.

Agradecería ayuda con la sintaxis y forma adecuada del código.

El código está muy comentado ya que está reducido para hacer pruebas simples:

PHP:
/* 
 * File:   main.c
 * Author: nimio
 *
 * 16F84A
 *
 * COMPILADOR XC8
 *
 * EN ESTE PROGRAMA SE USA LA EEPROM PARA ALMACENAR 4 MENSAJES QUE SE MOSTRARÁN
 * EN EL LCD 16X2
 *
 * Created on 5 de abril de 2013, 5:10
 */

#include <xc.h>
#include "LCD/LCDGeneric.h"
//#include <eeprom_routines.h>
//#include <htc.h>

#define _XTAL_FREQ 4000000

#pragma config FOSC=XT, WDTE=OFF, PWRTE=ON, CP=OFF
//__EEPROM_DATA(0, 0, 0, 0, 0, 0, 0, 0);
//__eeprom char ultdire[64];
#_EEPROMSIZE 64;

void main(void) {
    //INTCONbits.GIE=0;
    char ultdire=0, dire;  // VARIABLES DE DIRECCIÓN ESCRITURA EEPROM Y MENSAJE.
                           // ÚLTIMA DIRECCIÓN Y DIRECCIÓN.

    //char dire;

    //MENSAJES A ESCRIBIR EN EEPROM INTERNA Y MOSTRAR EN LCD.
    char mensaje1="MENSAJE 1";  // MENSAJE 1
    //char mensaje2="PRUEBA";  // MENSAJE 2
    //char mensaje3="FUNCIONAMIENTO EEPROM"; // MENSAJE 3
    //char mensaje4="nimio 2013";  // MENSAJE 4

    
    EEADR=0x00;

    //eeprom_write(EEADR,mensaje1);
    eeprom_write(0,mensaje1);
    __delay_ms(500);  // DELAY PARA DAR TIEMPO A LA ESCRITURA ¿?
    while(WR==1) {  // SI HA ESCRITO YA PUEDE LEER
        continue;
        EECON1bits.RD = 1; // Inicializa lectura de la EEPROM
    //dire=eeprom_read(EEADR);
        dire=eeprom_read(0);
    }

    vInitLCD();
    vPuts_LCD(dire);  // MUESTRA MENSAJE POR PANTALLA LCD
     __delay_ms(500);
     
}

Sigo investigando.

Saludos
 
Hola.
- La función eeprom_write() solo escribe un carácter a la vez y no toda una cadena. Debes acceder a la cadena de texto a modo de array o usando punteros.

Por ejemplo:
char msg[] = {"Hola"};

for(i=0 ; i<sizeof(msg) ; i++)
eeprom_write(i, msg);

Siendo 'i' la dirección en eeprom donde se va a escribir en carácter de la cadena de texto.

- La función printf() te sirve generalmente cuando se usa el modulo USART y '%' es para convertir valores a cadenas en distintos formatos representativos. ("%02d" por ejemplo escribe una cadena de texto decimal con un mínimo de dos dígitos).

Puedes usar el fprintf() para hacer convenciones como antes mencioné, solo necesitas de una variable de buffer en array de la longitud que se necesite.

Saludos
 
Hola ByAxel, gracias por la respuesta.

Ahora probaré tu ejemplo.

Lo que quiero aclarar es si tengo que usar printf obligatoriamente, dicho de otra forma... puedo usar vPuts_LCD() para mostrar el contenido (texto en este caso) de una variable? si así fuera la sintaxis de vPuts_LCD(dire); es correcta? Porque para eso siempre veo que usan printf (junto con %).

Como dije estoy aprendiendo y desconozco aún el uso del comando printf, USART, variables de buffer..., pero lo investigaré!.


Una vez más muy agradecido.

Sigo en ello!

Saludos
 
Buenas sigo sin conseguir que funcione.

Este es el código con el ejemplo sugerido por ByAxel:

PHP:
/* 
 * File:   main.c
 * Author: nimio
 *
 * 16F84A
 *
 * COMPILADOR XC8
 *
 * EN ESTE PROGRAMA SE USA LA EEPROM PARA ALMACENAR 4 MENSAJES QUE SE MOSTRARÁN
 * EN EL LCD 16X2
 *
 * Created on 5 de abril de 2013, 5:10
 */

#include <xc.h>
#include "LCD/LCDGeneric.h"

#define _XTAL_FREQ 4000000

#pragma config FOSC=XT, WDTE=OFF, PWRTE=ON, CP=OFF

void main(void) {
    
    char mem; // VARIABLE PARA UBICAR LA POSICIÓN DE MEMORIA.
    char mensa; // VARIABLE PARA UBICAR EL MENSAJE LEÍDO DE LA EEPROM.

    char msg[]={"HOLAHOLA"};

    for (mem=0; mem<sizeof(msg); mem++)
        eeprom_write(mem, msg[mem]);

        for (mem=0; mem<sizeof(msg); mem++) {
            mensa=eeprom_read(mem);
            
            vInitLCD();
             vPuts_LCD(mensa);  // MUESTRA MENSAJE POR PANTALLA LCD
        }
 
}

He deducido que para leer el mensaje almacenado en la EEPROM también tendría que ir cargando cada posición de memoria para leerlo letra por letra e ir mostrando el contenido en el LCD. Pero una vez más doy palos de ciego. No se en que parte de la sintaxis me equivoco, que me falta... que me sobra... que está mal... . Sólo se ilumina tenuemente la primera fila del LCD.

Decir que haciendo pruebas más simples veo que soy incapaz de mostrar por LCD un mensaje almacenado en una variable (ni con vPuts_LCD() ni con printf).

Saludos.
 
- vPuts_LCD() sirve para enviar cadenas, usa la otra función de la libraria del LCD que es para enviar caracter por caracter ya que tomas uno a uno de la memoria.

- Deten en programa luego del segundo FOR con un while(1); por ejemplo ya que de lo contrario vuelve a main() y repite la secuencia una y otra vez. Toma en cuenta que usas vInitLCD(); y éste borra el LCD y como se repite indefinidamente, entonces se borra indefinidamente por más que escriba en el LCD, éste se borra en la siguiente pasada.

PD: Ordena tu lógica

Saludos.
 
He hecho lo que sugieres y funciona!!:

CÓDIGO:

PHP:
/*  
 * File:   main.c 
 * Author: nimio 
 * 
 * 16F84A 
 * 
 * COMPILADOR XC8 
 * 
 * EN ESTE PROGRAMA SE USA LA EEPROM PARA ALMACENAR 4 MENSAJES QUE SE MOSTRARÁN 
 * EN EL LCD 16X2 
 * 
 * Created on 5 de abril de 2013, 5:10 
 */ 

#include <xc.h> 
#include "LCD/LCDGeneric.h" 

#define _XTAL_FREQ 4000000 

#pragma config FOSC=XT, WDTE=OFF, PWRTE=ON, CP=OFF 

void main(void) { 
     
    char mem; // VARIABLE PARA UBICAR LA POSICIÓN DE MEMORIA. 
    char mensa; // VARIABLE PARA UBICAR EL MENSAJE LEÍDO DE LA EEPROM. 

    char msg[]={"HOLAHOLA"}; 

    for (mem=0; mem<sizeof(msg); mem++) 
        eeprom_write(mem, msg[mem]);
 
        vInitLCD(); 
        for (mem=0; mem<sizeof(msg); mem++) { 
            mensa=eeprom_read(mem); 
             
            
             vLCD_Putc(mensa);  // MUESTRA MENSAJE POR PANTALLA LCD 
        } while(1);
  
}


Ahora al mostrar el mensaje en el LCD siempre deja el cuadrado siguiente totalmente negro. Alguna forma para solucionarlo? o a qué es debido? mientras lo investigo.

Probaré a almacenar 4 mensajes que es el programa inicial que quería hacer.

Buff... hay que ver como me cuesta... pero a trancas y barrancas voy avanzando, gracias al foro claro!

Una vez más sólo puedo decir que estoy muy agradecido por el tiempo y paciencia.


Saludos!!
 
Hola de nuevo.

He intentado hacer lo mismo pero almacenando 4 mensajes en la EEPROM para luego leerlos e ir mostrándolos sucesivamente en el LCD.

No se si tengo algún error de código porque el error que me da parece ser de espacio (uso 16F84A):

error: could not find space (1 byte) for variable _NLinea

Este error hace referencia a la librería del LCD que uso en todos estos proyectos y va perfectamente. Lo curioso es que hace referencia a la librería, pero de otro proyecto que también va bien (incluyo la carpeta LCD en todos los proyectos).

Dejando esto de lado... no se si mi código es válido como forma de lectura/escritura de 4 mensajes o es algo bruto... etc. o si se puede optimizar más y reducir memoria que supongo que si.

CÓDIGO:

PHP:
/* 
 * File:   main.c
 * Author: nimio
 *
 * 16F84A
 *
 * COMPILADOR XC8
 *
 * EN ESTE PROGRAMA SE USA LA EEPROM PARA ALMACENAR 4 MENSAJES QUE SE MOSTRARÁN
 * EN EL LCD 16X2
 *
 * Created on 5 de abril de 2013, 5:10
 */

#include <xc.h>
#include "LCD/LCDGeneric.h"


#define _XTAL_FREQ 4000000

#pragma config FOSC=XT, WDTE=OFF, PWRTE=ON, CP=OFF


void main(void) {
   

    char mem=0; // VARIABLE PARA UBICAR LA POSICIÓN DE MEMORIA.
    char letra=0; // VARIABLE PARA IR CARGANDO LETRA A LETRA EL TEXTO.
    char mensa; // VARIABLE PARA UBICAR EL MENSAJE LEÍDO DE LA EEPROM.

    
    //MENSAJES A ESCRIBIR EN EEPROM INTERNA Y MOSTRAR EN LCD.
    char mensa1[]={"MENSAJE 1"};  // MENSAJE 1
    char mensa2[]={"PRUEBA"};  // MENSAJE 2
    char mensa3[]={"FUNCIONAMIENTO EEPROM"}; // MENSAJE 3
    char mensa4[]={"nimio 2013"};  // MENSAJE 4



       while (letra<=sizeof(mensa1)) {

           eeprom_write(mem, mensa1[letra]);
           letra++;
            mem++;
        }
        letra=0;
        
        while (letra<=sizeof(mensa2)) {

            eeprom_write(mem,mensa2[letra]);
            letra++;
            mem++;
        }
        letra=0;
        
        while (letra<=sizeof(mensa3)) {

            eeprom_write(mem,mensa3[letra]);
            letra++;
            mem++;
        }
        letra=0;
        
        while (letra<=sizeof(mensa4)) {

            eeprom_write(mem,mensa4[letra]);
            letra++;
            mem++;
        }
        letra=0;
        mem=0;

        vInitLCD();

        do {

            while (letra<=sizeof(mensa1)) {

                mensa=eeprom_read(mem);
                letra++;
                mem++;
                vLCD_Putc(mensa);  // MUESTRA MENSAJE POR PANTALLA LCD (VISUALIZA CARACTER POR CARACTER)
            }
            letra=0;
            __delay_ms(2000); // DELAY DE 2 SEGUNDOS HASTA MOSTRAR SIGUIENTE MENSAJE

            while (letra<=sizeof(mensa2)) {

                mensa=eeprom_read(mem);
                letra++;
                mem++;
                vLCD_Putc(mensa);  // MUESTRA MENSAJE POR PANTALLA LCD (VISUALIZA CARACTER POR CARACTER)
            }
            letra=0;
            __delay_ms(2000);

            while (letra<=sizeof(mensa3)) {

                mensa=eeprom_read(mem);
                letra++;
                mem++;
                vLCD_Putc(mensa);  // MUESTRA MENSAJE POR PANTALLA LCD (VISUALIZA CARACTER POR CARACTER)
            }
            letra=0;
            __delay_ms(2000);

            while (letra<=sizeof(mensa4)) {
                
                mensa=eeprom_read(mem);
                letra++;
                mem++;
                vLCD_Putc(mensa);  // MUESTRA MENSAJE POR PANTALLA LCD (VISUALIZA CARACTER POR CARACTER)
            }
            letra=0;
            __delay_ms(2000);
            mem=0;
        }while(1);

}

Decir que también he probado comentando todo el código referente a mensaje1 y mensaje 2 por si reducía espacio (en un proyecto anterior no fui capaz de reproducir el abecedario completo en el LCD, sólo la mitad).

Sigo investigando.

Saludos
 
Hola.
He probado el código y escribe normalmente en el LCD, ahora mi detalle es que no se activan las rutinas de eeprom para el PIC16F84 así que hice rutinas de lectura/escritura eeprom y funciona (revisa eeprom_routines.h y acóplalo para el pic), supongo que es algo de configuración.

Prueba uno simple:
Código:
 char mem; // VARIABLE PARA UBICAR LA POSICIÓN DE MEMORIA.  
 char msg[]={"HOLAHOLA"};

void main(void) {  
    vInitLCD();   
         
    for (mem=0; mem<sizeof(msg); mem++) {  
        vLCD_Putc(msg[mem]);  // MUESTRA MENSAJE POR PANTALLA LCD  
    } 

    while(1); 
   
}

Si no funciona, ya es la librería LCD que has modificado.
Si usas proteus, puedes usar la simulación paso a paso con el archivo *.cof, es una especie de debugger y podras ver el codigo, variables, memorias, etc

Saludos
 
Hola de nuevo!

Siento la demora pero he estado ocupado en otros temas...

A ver, he mirado como sugieres eeprom_routines.h pero sinceramente... ni idea, me considero muy novato como para pretender querer entender la estructura interna de las librerías. La he incluído como librería en el proyecto y tampoco funciona, da el mismo error.

Modifiqué la librería para LCD para mis requerimientos y porque explicaban como hacerlo. Hasta ahora he usado la misma librería LCD en todos los proyectos (sencillos, de mostrar texto en LCD), con las mismas modificaciones y sin problema, todo perfecto.

Tal vez me repita pero el tema está en que ahora me da error de la librería LCD que es exáctamente la misma en todos los proyectos de LCD, pero lo raro es que me dice que el error está en la librería LCD de otro proyecto que no es el actual que trato aquí. Algo muy raro dado que no guardan relación alguna (incluyo la librería individualmente en todos los proyectos).

El error hace referencia al archivo de la librería LCDGeneric.c (la librería LCD consta de 3 archivos). Esta librería es de http://www.micros-designs.com.ar/libreria-generica-en-c-control-lcd/ que creo que me la recomendaste tu ByAxel.

Adjunto el error completo haciendo referencia al otro proyecto por si sirve de ayuda:


../LCD FRASE DESLIZANTE FUNCIONES DERECHA IZQUIERDA.X/LCD/LCDGeneric.c:28: error: could not find space (1 byte) for variable _NLinea
(908) exit status = 1
make[2]: *** [dist/default/production/LCD_MUESTRA_4_MENSAJES_ALMACENADOS_EN_EEPROM.X.production.hex] Error 1
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2
make[2]: Leaving directory `/Volumes/HD/Users/nimio/MPLABXProjects/LCD MUESTRA 4 MENSAJES ALMACENADOS EN EEPROM.X'
make[1]: Leaving directory `/Volumes/HD/Users/nimio/MPLABXProjects/LCD MUESTRA 4 MENSAJES ALMACENADOS EN EEPROM.X'

BUILD FAILED (exit value 2, total time: 1s)


LCD FRASE DESLIZANTE FUNCIONES DERECHA IZQUIERDA.X -----> es el nombre del otro proyecto.

Pone que el error es de la variable _NLinea, aunque en el archivo de la librería es NLinea (sin guión bajo).

El error hace referencia a esta línea: UINT8 NLinea;

Si elimino la carpeta LCD del otro proyecto donde está la librería me da el siguiente error:

make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-conf
make[1]: Entering directory `/Volumes/HD/Users/nimio/MPLABXProjects/LCD MUESTRA 4 MENSAJES ALMACENADOS EN EEPROM.X'
make -f nbproject/Makefile-default.mk dist/default/production/LCD_MUESTRA_4_MENSAJES_ALMACENADOS_EN_EEPROM.X.production.hex
make[2]: Entering directory `/Volumes/HD/Users/nimio/MPLABXProjects/LCD MUESTRA 4 MENSAJES ALMACENADOS EN EEPROM.X'
"/Applications/microchip/xc8/v1.12/bin/xc8" --pass1 --chip=16F84A -Q -G --asmlist --double=24 --float=24 --emi=wordwrite --opt=default,+asm,-asmfile,+speed,-space,-debug,9 --addrqual=ignore -P -N255 --warn=0 --summary=default,-psect,-class,+mem,-hex,-file --runtime=default,+clear,+init,-keep,-no_startup,+osccal,-resetbits,-download,-stackcall,+config,+clib,+plib "--errformat=%f:%l: error: %s" "--warnformat=%f:%l: warning: %s" "--msgformat=%f:%l: advisory: %s" -obuild/default/production/main.p1 main.c
make[2]: *** No rule to make target `../LCD FRASE DESLIZANTE FUNCIONES DERECHA IZQUIERDA.X/LCD/LCDGeneric.c', needed by `build/default/production/_ext/1443147684/LCDGeneric.p1'. Stop.
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2
make[2]: Leaving directory `/Volumes/HD/Users/nimio/MPLABXProjects/LCD MUESTRA 4 MENSAJES ALMACENADOS EN EEPROM.X'
make[1]: Leaving directory `/Volumes/HD/Users/nimio/MPLABXProjects/LCD MUESTRA 4 MENSAJES ALMACENADOS EN EEPROM.X'

BUILD FAILED (exit value 2, total time: 169ms)

He probado con el código que sugieres y compila bien, lo cual me desconcierta.

No puedo usar Proteus ya que soy usuario mac.

Seguiré investigando mirando la librería.

Gracias por la atención.


Saludos
 
Atrás
Arriba