Guardar un dato de 16 bits en la eeprom de un 16f876a

Hola a todos, he leído este hilo y es el mismo problema que tengo.
Debo hacer un trabajo para mis estudios, las condiciones son:

1.- Tengo un numero entero y uno decimal(float)
2.- Se deben incrementar al pulsar un botón ( el valor a incrementar no interesa, solo es para visualización de entero y decimal(float))
3.- Con otro botón resetear o dejar en cero.
4.- Cuando se reinicie se debe partir del ultimo valor que se debe guardar en memoria interna del pic.
5.- Hacerlo indefinidamente.

Todo bien (gracias a los ejemplos aquí dejados)
El problema es cuando debo guardar el dato float(decimal) en la eeprom y luego leerlo


Aquí lo hecho hasta el momento



Código:
#include <16f877a.h>
#device  adc = 8 // a 8 bits
#use     delay(crystal = 4MHz)
#include <lcd420.c>

#define pulsador pin_c0 // pulsador para cambiar
#define reset pin_c1 //pulsador para resetear
void main (void)
{
int8 entero;
float decimal;
//leo las memorias
   entero = read_eeprom(0);
  decimal = read_eeprom(0x01);[COLOR=Red]// duda  [/COLOR]
lcd_init();                   // Inicializar la pantalla.
    while (true)
   {
      
     if(input(pulsador))
     {
   
   entero=entero + 1.9;             // varia el valor.
   decimal=decimal + 1.1;           // Varia el valor.
          }
            
     if(input(reset))
     {
  
   lcd_init();
   entero=00;             //`pone a cero la cuenta.
   decimal=0;             // pone a cero la cuenta.
          }
      
lcd_gotoxy(1,1);
printf(lcd_putc,"ent=");// imprime ent
lcd_gotoxy(8,1);
printf(lcd_putc,"dec=");//imprime dec
lcd_gotoxy(5,1);
printf(lcd_putc,"%d",entero);//imprime valor en entero
delay_ms(100);
lcd_gotoxy(13,1);
printf(lcd_putc,"%f",decimal);//imprime valor en decimal
delay_ms(100);
      
//aqui debo escribir en memoria

write_eeprom(0,entero);
delay_ms(10);
write_eeprom (0x01,decimal);         
delay_ms(10);
   }
}


¿Podrían ayudarme por favor? (No sé casi nada de programación por no decir nada)

Javier.
 
Última edición por un moderador:
El problema es cuando debo guardar el dato float(decimal) en la eeprom y luego leerlo

¿Podrían ayudarme por favor? (No sé casi nada de programación por no decir nada)
Utiliza la librería internal_eeprom.c que viene por defecto.

Esa librería tiene funciones para guardar y leer datos float hasta 64 bits:

Por ejemplo: write_float_eeprom(address, float data) y read_float_eeprom(address)

Suerte.
 
Utiliza la librería internal_eeprom.c que viene por defecto.

Esa librería tiene funciones para guardar y leer datos float hasta 64 bits:

Por ejemplo: write_float_eeprom(address, float data) y read_float_eeprom(address)

Suerte.

Estimado d@rkbytes, le agradezco todo la paciencia y ayuda entregada, así como el programa que me facilito, adjunto lo que me ha resultado hasta el momento, es una incubadora que realiza ;

1.- seteo de temperatura máxima y mínima y las muestra en pantalla
2.- Muestreo de temperatura y la muestra en pantalla
3.- Con pulsador automático, el motor pap funciona cada una hora por 5 min ( aquí los tiempos son menores para simulación)( la señal enable para el motor la asumo siempre uno por eso no esta acá)
4.-- Con pulsador automático abierto se puede hacer funcionar el motor a izquierda o derecha según necesidad
5.- ante corte de energía o reinicio guarda los últimos datos de seteo y tiempo en memoria

Esta de mas decir que es un programa de principiante por lo que se puede depurar, mejorar.

Lo dejo acá por si alguien le sirve, quiere mejorar o modificar, solo les pido que después lo suban

Juan Carlos
 

Adjuntos

  • incubadora ULTIMA VERSION.rar
    128.7 KB · Visitas: 31
Hola D@rkbytes, quiero ver que opinas de este modo de usar la eeprom, tengo que decir que estoy empezando a conocer el mundo de la eeprom y creo que ofrece una ayuda para mantener datos que no habia pensado antes, es para un sistema de calefaccion.

Tengo que decir que la idea parte de haberme fijado como la lavadora estaba en funcionamiento y cual fue mi sorpresa cuando se fue la corriente electrica y al volver, està, continuo con su programa en donde lo habia dejado.

He leido en unos posts mas arriba tuyos el sistema para dejar grabados los datos y por eso quiero saber si tal como lo hecho es un metodo correcto ya que tu utilizas el tiempo de descarga del condensador de filtrado de 4700µf.

Por cierto, igual hubiese sido mejor crear un tema nuevo, como no estaba seguro lo he puesto en este, espero que no sea incorrecto.

Adjunto el archivo.
 

Adjuntos

  • Termostato.rar
    26.5 KB · Visitas: 14
Última edición:
No me convence la forma que usas para guardar los datos.
Si guardas los datos cuando el usuario lo decida, se perderá el ciclo de trabajo.
Debes guardar los datos periódicamente usando un Timer y también en cada cambio de ciclo.

Si no vas a mandar datos a la pantalla, puedes omitir el printf.

Hola. Imposible abrir ese formato de archivo, súbelo en .txt o similar.
Los archivos .C se pueden abrir con el bloc de notas, ya que prácticamente es un archivo de texto.
El otro archivo que se incluye es de simulación en proteus y únicamente se puede ver con ese programa.
 
Código:
#include <16F877A.h>
#fuses XT,NOWDT,PUT,NOBROWNOUT,NOLVP
#use delay(clock =4MHz)

#include <1Wire-A0.c>
#include "flex_lcd 4x20.c"
#include <DS18B20.C>  

float temper;
int temp=0;

void ajustemp(void);

 void main()
     {
   int a=0;

  temp=read_eeprom(0);

 lcd_init();
 
     output_low(pin_D2);
       output_low(pin_D3);

 while(true)
 {
 if(a==10)
 {
 temper = DS18B20_read();
 lcd_gotoxy(2,2);
  printf(lcd_putc," Temperatura: %02.0fßC ",temper);
 lcd_gotoxy(2,3);
  printf(lcd_putc,"MODIFICAR VALOR A-1 ");
    a=0;
     }
 
 if(temper<temp){
 output_high(pin_D2);
 output_low (pin_D3);
    }
    
 if(temper>=temp){
 output_high(pin_D3);
 output_low (pin_D2);
    } 
    
 if(input(pin_A3)){  // Subir
    
    lcd_putc("\f");
    delay_ms(150);
       ajustemp();
         }
   delay_ms(100); 
   a++;         
     }
   }
 
void ajustemp(void)
    {

  while(true){
  
   lcd_gotoxy(1,2);
    printf(lcd_putc,"  Ajust_Temp: %02.0dßC  ",temp);
    
  if(input(pin_A1))   // GRABAR VALOR DE TEMP
      {   
  write_eeprom(0,temp); 
   lcd_gotoxy(1,3);
    printf(lcd_putc,"  GRABADO EL VALOR  ");

     delay_ms(3000); 
     lcd_putc("\f");
       break;
      }  
      
  if(input(pin_A2))  // BORRAR VALOR DE TEMP
     {
   temp=0;
    delay_ms(200);
        }    
 
  if(input(pin_A3)){  // SUBIR VALOR DE TEMP
      delay_ms(200); 
       temp++;       
         }  
         
   if(temp>50){temp=0;}             
  
  if(input(pin_A4)){ // BAJAR VALOR DE TEMP
     delay_ms(200);
      temp--;       
       } 
       
  if(temp==-1){temp=0;}
 
    }
  }

Este es el codigo.



No me convence la forma que usas para guardar los datos.
Si guardas los datos cuando el usuario lo decida, se perderá el ciclo de trabajo.
Debes guardar los datos periódicamente usando un Timer y también en cada cambio de ciclo.

Si no vas a mandar datos a la pantalla, puedes omitir el printf.


Los archivos .C se pueden abrir con el bloc de notas, ya que prácticamente es un archivo de texto.
El otro archivo que se incluye es de simulación en proteus y únicamente se puede ver con ese programa.

Lo de "guardar los datos", solo quiero quiero guardar el de la temperatura de referencia, en otro programa que tengo el valor lo tengo en una variable y claro si apago la corriente, al conectar de nuevo siempre tengo la que esta prefijada y yo lo que quiero es poder modificarla sin tenerla que grabar de nuevo.

El "printf" no se a cual te refieres, lo uso para saber que valor quiero guardar, de todas formas ya he dicho que estoy empezando a manejar la memoria eeprom.
 
Última edición:
Lo de "guardar los datos", sólo quiero quiero guardar el de la temperatura de referencia.
En otro programa que tengo el valor lo tengo en una variable y claro si apago la corriente, al conectar de nuevo siempre tengo la que esta prefijada y yo lo que quiero es poder modificarla sin tenerla que grabar de nuevo.
Entonces así está bien, no veo problema.
El "printf" no sé a cuál te refieres, lo uso para saber que valor quiero guardar, de todas formas ya he dicho que estoy empezando a manejar la memoria eeprom.
Me refiero a esto:
PHP:
    printf(lcd_putc,"  GRABADO EL VALOR  ");
No estás presentando ningún valor para darle formato.
Así que puede quedar así simplemente:
PHP:
    lcd_putc("  GRABADO EL VALOR  ");
Y ahorras memoria RAM.
 
Tienes razon con respecto al printf, hay veces que voy haciendo pruebas y no presto atencion por que igual he usado ese printf para otro fin y luego al quitar la variable pues se me olvida que ya no hace falta y que con un simple lcd_putc asunto resuelto, pequeños fallos que uno comete.

Una pregunta si me permites, en el while coloco un if con la variable a para que cuando llegue a 10 vuelva a 0 y empieze de nuevo, esto se me ha ocurrido asi ya que no quiero usar una interrupcion, de esta manera me entra bien la funcion de ajuste, como puedo hacerlo mejor, digo esto por que entra la funcion de la lectura de temperatura y aunque pulso ajuste resulta molesto pulsar y que no entre enseguida la funcion de ajuste.
 
Siguiendo tu consejo lo hecho de la siguiente forma, espero que sea correcta.

#int_timer1
void timer1_isr(void)
{
a++;
if(a>15)
{
b=1;
a=0;
}
set_timer1(0);
}

Te comento, he creado la variable "short b=0;", de esta forma cada vez que salta comprueba la temperatura, despues la pongo otra vez a 0.

El timer1 lo tengo configurado: set_timer1(3036);, con esto tengo mas que suficiente por lo que veo en las pruebas que hago en proteus, luego lo probare en el protoboard haber que tal.

Es correcto hacerlo de esta forma?.
 
Con el Timer 1 cargado a 3036 @ 4 MHz. desbordará cada 500 mS.
Entonces... if (a++ > 15) estarás poniendo "b" en 1 cada 8 segundos. (16 * 0.5) = 8
Pero si "b" lo compruebas dentro del bucle en donde tienes una secuencia con varios retardos, vendrás comprobando "b" después de que se cumplan todos.
Tal vez suceda un corte eléctrico durante ese proceso y adiós lectura de la temperatura.
Aparte, el Timer 1 lo debes volver a recargar con 3036 y no con 0.

Sería mejor que dicha lectura la realizaras dentro del servicio de interrupción del Timer 1.
 
Última edición:
Haber, lo que hecho es modificar un poco el codigo, en vez de poner la medicion de la temperatura dentro del timer la he dejado dentro del bucle con la condicion de que si b==1 haga la medida y lo ponga a 0 luego, de paso elimino el retardo, es que dentro del timer me marca 3 advertencias.

Tienes razon con lo de la carge del timer, error mio de escritura, ni me habia fijado, pense que estaba como tu dices (3036).

Por otro lado le bajo a 6 segundos que es tiempo mas que suficiente, no es algo critico, es para una caldera para calentar agua.

Asi es como queda, espero haberlo hecho bien ahora, no lo he probado en lo fisico, en proteus funciona bien.

Código:
#include <16F877A.h>
#fuses XT,NOWDT,PUT,NOBROWNOUT,NOLVP
#use delay(clock =4MHz)

#include <1Wire-A0.c>
#include <flex_lcd 4x20.c>
#include <DS18B20.C>  

int temper;
int temp=0;
int a=0;
short b=0;

void ajustemp(void);

#int_timer1
  void timer1_isr(void)
        {
      a++;
      if(a>11) // Parar 6 segundos
        {
       b=1;
       a=0;
      }
  
     set_timer1(3036);
       }   
          
 void main()
     {
    set_tris_D(0X00); // Puerto D como salida
    output_D(0);      // Limpio puerto D
 setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); 
  enable_interrupts(int_timer1);
  enable_interrupts(global);
   set_timer1(3036);
   
  temp=read_eeprom(0);
 
  if(temp==0xFF){temp=0;}      // Para eeprom virgen
  
  temper = DS18B20_read();
  
 lcd_init();

 while(true)
  {
 if(b==1)
  {
 temper = DS18B20_read();
    b=0;
     }
 
 if(temper<temp){
 output_high(pin_D2);
 output_low (pin_D3);
    }
    
 if(temper>=temp){
 output_high(pin_D3);
 output_low (pin_D2);
    } 
    
  lcd_gotoxy(2,2);
  printf(lcd_putc," Temperatura: %02.0dßC ",temper); // Indico el valor de la temperatura
  lcd_gotoxy(2,3);
  printf(lcd_putc," Valor de ßC: %02.0d   ",temp);  // Indico valor del Ajuste
    
 if(input(pin_A3))  // Para entrar en la funcion de ajuste de grados
     {      
    lcd_putc("\f");
    delay_ms(150);  // tiempo para el rebote
       ajustemp();
         }       
      }
   }
 
void ajustemp(void)
    {

  while(true)
    {
  
   lcd_gotoxy(2,2);
   printf(lcd_putc," Valor de ßC: %02.0d   ",temp);  // Indico valor del Ajuste
    
  if(input(pin_A1))   // GRABAR VALOR DE TEMP
      {   
  write_eeprom(0,temp); 
   lcd_gotoxy(1,3);
   lcd_putc("  GRABADO EL VALOR  ");

     delay_ms(1000); 
     lcd_putc("\f");
       break;
      }  
      
  if(input(pin_A2))  // BORRAR VALOR DE TEMP
     {
   delay_ms(200); 
    temp=0;
       }    
 
  if(input(pin_A3))  // SUBIR VALOR DE TEMP
     {  
      delay_ms(200); 
       temp++;       
         }  
         
   if(temp>50){temp=0;}             
  
  if(input(pin_A4))  // BAJAR VALOR DE TEMP
      { 
     delay_ms(200);
      temp--;       
       } 
       
  if(temp==-1){temp=0;}
 
    }
  }
 
Última edición:
Las advertencias al incorporar rutinas con retardos dentro del servicio de interrupción, no afectan la ejecución del programa.
El compilador te indica que serán deshabilitadas las interrupciones al ingresar al servicio, pero después serán nuevamente habilitadas.
De hecho, en ciertas ocasiones suelen desactivarse algunas durante el proceso de interrupción para que no afecten la rutina ejecutada.

Y me parece conveniente que las instrucciones de if(input(PIN_A1)) queden cuando "b" sea 1.
O sea que deben quedar dentro de la rutina de comprobación de "b".
Ya que no tiene caso usar una rutina de comprobación, si la temperatura se sigue guardando manualmente.
Y te repito, no importa que queden dentro del servicio de interrupción del Timer 1.
Si no quieres ver esa advertencia, usa: #ignore_warnings warnings
Donde warnings puede ser uno o varios valores de advertencia precedidos por una coma.
No recuerdo el valor de ese tipo advertencia, pero creo que es el 216.
(Los puedes ver en la ventana del log de compilación.)

Si incorporas esas rutinas, se evita guardar manualmente el valor y una escritura en pantalla.
 
He hecho lo que has indicado y perfecto, no lo habia visto como dices, sobretodo lo de evitar guardar el valor manualmente.

Una ultima pregunta si no te importa, la temperatura esta en un entero, pero si quiero que sea con un float para que tenga decimales, que insrtuccion devo usar si quisiera guardarla? es que leo y no lo tengo claro, gracias y ya no pregunto mas jejeje.
 
Usa la librería incluida con el IDE. "internal_eeprom.c"
Tiene las rutinas "write_float_eeprom" y "read_float_eeprom"
No recuerdo si se usan 3 o 4 bytes, así que debes tener cuidado con eso para no sobreescribir locaciones.
También tiene la librería "ds18b20.c" para la lectura del sensor de temperatura y la librería "lcd420.c" para pantallas de 4 líneas y 20 caracteres.
 
Saludos, mucha gente buena por aqui y con conocimientos. Alguno me podria indicar la forma correcta para escribir y leer un valor de 16 bit en una eeprom que tiene "EE bit depth 8bit" utilizando flowcode. Trabajo con la version de flowcode v6 gracias.
 
No sé cómo se use eso del Flowcode, pero supongo que debe tener ejemplos instalados.
La forma clásica en cualquier lenguaje, es escribir dos bytes. (MSB y LSB)
Entonces ocuparás 16 bits. (8 bits * 2 = 16 bits) O sea, dos locaciones de 8 bits.
 
ok gracias por responder, he visto sus propios post explicando el procedimiento para separar en dos 2 bits me ayudaria igual un codigo en c, algo simple solo escibir una variable y leerla. El flowcode es alto nivel, pones un icono y configuras las opciones y el solo pega el codigo c correspondiente, pero permite modificar el codigo tambien.
 
Básicamente para obtener el MSB y el LSB, sería así:
PHP:
unsigned char msb = (valor_16bits >> 8) & 0xFF;
unsigned char lsb = (valor_16bits & 0xFF);
Y para recuperar el valor de 16 bits, sería así:
PHP:
valor_16bits = (unsigned int) (msb << 8) | lsb;
 
Atrás
Arriba