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



## ariel 37 (May 20, 2014)

Hola que tal gente !!! saludos a todos , queria consultar por lo siguiente, estoy haciendo un programa con CCS en el cual leo un canal analogico digital(AN0)  del pic 16f876a   , y guardo tres valores, en tres direcciones distintas de  la memoria eeprom, para despues leerlos y utilizarlos para hacer unas funciones. El tema es que en la simulacion de proteus me funciona perfecto pero cuando lo grabo en el pic y lo pruebo hace cualquier  cosa.Uno de los puntos es que uso un pulsador para grabar en la memoria y el error que me aparece es como si siempre estuviese pulsando  el boton , y otra  es que tal vez estoy utilizando posiciones de memoria que no se pueden escribir y leer  y queria saber si alguien me podria decir en que posiciones de memoria de este pic se puede hacer esto, por lo que lei en el datasheet a partir de la posicion 120h eran registros de proposito general por lo que estoy utilizando la posicion (0x120), (0x122) y (0x126) que tampoco estoy seguro si se escribe de esta manera.Y el ultimo punto es que tal vez el error este en otro lado y nunca me di cuenta ja ja  .Ojala me puedan ayudar, les agradezco de antemano Saludos !!!  .Esta es parte del codigo donde grabo uno de los parametros en la memoria 

```
if (input(pin_c1)==1) //  llave de seleccion
   {
  
   lcd_gotoxy(1,1);
   printf(lcd_putc," Grabar dato  \n       %lu       ",cursor );

  if (input(pin_c0)==1) // pulsador para grabar en la eeprom
   {
   printf(LCD_PUTC, "\f");
   write_int16_eeprom(0x120,(int16) cursor);// escribe en la memoria posicion (0x120)
   delay_ms(15);
   dato=read_int16_eeprom(0x120);
   lcd_gotoxy(1,1);
   printf(lcd_putc,"   Parametro    \n   Guardado     " );
   delay_ms(2000);
   lcd_gotoxy(1,1);
   printf(lcd_putc," Selecione otro \n Parametro      " );
   delay_ms(3000);
  
   }
```


----------



## D@rkbytes (May 20, 2014)

Parece que estás usando una librería para guardar y leer datos de 16 Bits.
Si esta es la librería que estás usando *(Lib_Int_EEProm.c)* a mi no me dio buenos resultados.

Sustituye y prueba con estas rutinas de lectura y escritura:

Rutina para leer 16 Bits.

```
long read_int16_eeprom(int8 address){
   int8 aadr_low, addr_high;
   long result;
   addr_high = read_eeprom(address);
   ++address;
   aadr_low = read_eeprom(address);
   result=(addr_high<<8);
   result+=aadr_low;
   return result;
}
```
Rutina para escribir 16 Bits.

```
void write_int16_eeprom(int address, long val){
   int8 addr_low, addr_high;
   addr_low = val;
   addr_high = val>>8;
   write_eeprom(address,addr_high);
   delay_ms(12);
   ++address;
   write_eeprom(address,addr_low);
   delay_ms(12);
}
```
La memoria EEPROM del PIC16F876A es de 256 Bytes.

Suerte.


----------



## ariel 37 (May 20, 2014)

Hola D@rkbytes , gracias por responder!!! . Estoy usando la libreria (#include <internal_eeprom.c>) y en la simulacion funciona pero en la realidad no. Voy a probar lo que me decis , ahora disculpa mi ignorancia pero me marea un poco esto de las direcciones  , que direccion tengo que usar? las que ya use estan bien?(0x120),(0x122),(0x126).y asi estan bien escritas ? Muchas gracias por tu ayuda !!!!!!!


----------



## TRILO-BYTE (May 20, 2014)

la eprom no guarda 16 bits solo 8

aveces el CCS genera uno que otro bug

usa MAKE8 para despedazar 16bits en 8 y viceversa para convertir 2 registros de 8 bits en un dato de 16 bits

eso esta en la misma ayuda del CCS


----------



## D@rkbytes (May 20, 2014)

ariel 37 dijo:


> Hola D@rkbytes , gracias por responder!!! . Estoy usando la librería (#include <internal_eeprom.c>) y en la simulación funciona pero en la realidad no. Voy a probar lo que me decis , ahora disculpa mi ignorancia pero me marea un poco esto de las direcciones  , que dirección tengo que usar? las que ya use están bien?(0x120),(0x122),(0x126).y así están bien escritas ? Muchas gracias por tu ayuda !!!!!!!


OK. Esa librería no la conozco, pero las rutinas que puse funcionan bien para escribir y leer datos de 16 bits.

Para que no te confundas con las direcciones, escribe la dirección en decimal.
Así, para el PIC16F876A puedes empezar a escribir desde la dirección 0 hasta la 255
Y no 0x120 que en decimal es 288 por lo tanto la escritura dará vuelta y se escribirá en otra dirección.

Recuerda que si escribes datos de 16 bits, estarás ocupando dos direcciones de memoria,
y si por ejemplo, quieres escribir en la última dirección, debes escribir en la dirección 254.
Así la dirección 254 tendrá el MSB y la dirección 255 el LSB.

Suerte.


----------



## ariel 37 (May 21, 2014)

Ok muchas gracias por sus respuestas !!! recien hoy a la noche lo voy a poder  probar, asi que  despues les cuento los resultados. Saludos y muchas gracias !!!


----------



## ariel 37 (May 21, 2014)

Bueno muchachos les comento : estuve probando  las funciones que me paso d@rkbytes pero no las entiendo ,veo muchas variables de distintos tipos y eso me confunde ,no me di cuenta bien como reemplazarlas, supuse que debia reemplazar todo lo que decia address, por la posicion de memoria osea el numero de 0 a 255 donde queria grabar el dato  . Y donde decia (val) supuse que era el nombre de mi variable, pero seguramente que lo debo estar haciendo mal ,obiamente ya que mi nivel es muy muy basico, asi que decidi hacer un programita muy sencillo como para empezar de cero y de la misma manera que antes funciona en la simulacion pero no en la realidad .Me gustaria si me pueden aconsejar mas especificamente sobre como hacerlo, ya que soy muy novato y esto me ayudaria a entederlo bien.Disculpen mi ignorancia, pero tengo muchas ganas de aprender y a veces me pongo a leer lo que encuentro por internet ,pero llega un punto que me mareo y se me mezcla todo  asi que termino preguntando en el foro con algun ejemplo que es la manera como mejor lo entiendo  . Les adjunto el codigo del programa que hice a modo de prueba .Les estare muy agradecido por su ayuda .Saludos !!!

```
#include <16f876a.h>
#device adc =10
#use delay (clock=4M)
#fuses XT,NOWDT,NOPROTECT,NOLVP
#include <lcd.c>
#include <internal_eeprom.c>
#use fast_io(B)
#use fast_io(c)
#use fast_io(a)

int16 cursor=0,dato=0;

   void main ()
  {
//****************ADC**************************
   setup_adc_ports(AN0_AN1_AN3);//* entradas analogicas*//
   setup_adc (ADC_CLOCK_INTERNAL);
   setup_COUNTERS(RTCC_internal.rtcc_div_8);
//********************************************************
   lcd_init ();
   
   WHILE (1) {
  
      set_adc_channel (0); 
      delay_us (20);
      cursor = read_adc (); 
 //************************************************************
 
    if (input(pin_c1)==1)
   {    
    lcd_gotoxy(1,1);
   printf(lcd_putc,"Cursor    %lu \n                 " ,cursor);
   }
      
    if (input(pin_c0)==1)
   {
   write_int16_eeprom(0x10,(int16) cursor);// escribe en la memoria
   delay_ms(15);
   }
     if (input(pin_c2)==1)
   {
   dato=read_int16_eeprom(0x10);
   delay_ms(15);
   lcd_gotoxy(1,1);
   printf(lcd_putc,"Dato guardado\n       %lu  ",dato );
   
   }
   }
  
  }
```


----------



## D@rkbytes (May 21, 2014)

ariel 37 dijo:


> Bueno muchachos les comento: estuve probando  las funciones que me paso d@rkbytes pero no las entiendo, veo muchas variables de distintos tipos y eso me confunde, no me di cuenta bien como reemplazarlas, supuse que debía reemplazar todo lo que decía address, por la posición de memoria osea el numero de 0 a 255 donde quería grabar el dato y donde decía (val) supuse que era el nombre de mi variable, pero seguramente que lo debo estar haciendo mal, obviamente ya que mi nivel es muy muy básico, así que decidí hacer un programita muy sencillo como para empezar de cero y de la misma manera que antes funciona en la simulación pero no en la realidad.
> Me gustaría si me pueden aconsejar mas, específicamente sobre como hacerlo, ya que soy muy novato y esto me ayudaría a entenderlo bien.
> Disculpen mi ignorancia, pero tengo muchas ganas de aprender y a veces me pongo a leer lo que encuentro por Internet, pero llega un punto que me mareo y se me mezcla todo así que termino preguntando en el foro con algún ejemplo que es la manera como mejor lo entiendo.


Como no adjuntas la librería que estás usando no podemos saber si funciona.
Encontré una con ese nombre y es similar a la que te comenté que no funcionaba.

Lo mejor es que mires este ejemplo usando las funciones que te mencioné anteriormente.

Saludos.


----------



## ariel 37 (May 22, 2014)

Ok muchas gracias por la ayuda, hoy a la noche me voy a poner con lo que me pasaste y despues te cuento .De todos modos te paso la libreria que estoy usando 

```
////////////////////////////////////////////////////////////////////////////////
////                          internal_eeprom.c                             ////
////                                                                        ////
////       Utilities to write various data types to internal eeprom         ////
////////////////////////////////////////////////////////////////////////////////
////                                                                        ////
////   void write_int1_eeprom(address, int8 bitPosition, int1 data)         ////
////     Call to write one bit of data                                      ////
////                                                                        ////
////   int1 read_int1_eeprom(address, int8 bitPosition)                     ////
////     Call to read one bit of data                                       ////
////                                                                        ////
////                                                                        ////
////   void write_int16_eeprom(address, int16 data)                         ////
////     Call to write a 16 bit integer                                     ////
////                                                                        ////
////   void read_int16_eeprom(address, int16 data)                         ////
////     Call to read a 16 bit integer                                      ////
////                                                                        ////
////                                                                        ////
////   void write_int32_eeprom(address, int32 data)                         ////
////     Call to write a 32 bit integer                                     ////
////                                                                        ////
////   int16 read_int32_eeprom(address)                                     ////
////     Call to read a 32 bit integer                                      ////
////                                                                        ////
////                                                                        ////
////   void write_float_eeprom(address, float data)                         ////
////     Call to write a floating point number                              ////
////                                                                        ////
////   float read_float_eeprom(address)                                     ////
////     Call to read a floating point number                               ////
////                                                                        ////
////////////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996, 2004 Custom Computer Services               ////
//// This source code may only be used by licensed users of the CCS C       ////
//// compiler.  This source code may only be distributed to other licensed  ////
//// users of the CCS C compiler.  No other use, reproduction or            ////
//// distribution is permitted without written permission. Derivative       ////
//// programs created using this software in object code form are not       ////
//// restricted in any way.                                                 ////
////////////////////////////////////////////////////////////////////////////////


#ifndef INTERNAL_EEPROM_UTILITIES
#define INTERNAL_EEPROM_UTILITIES

// Used to adjust the address range
#ifndef INT_EEPROM_ADDRESS
#define INT_EEPROM_ADDRESS  int8
#endif

////////////////////////////////////////////////////////////////////////////////
//// Internal EEPROM Functions
////////////////////////////////////////////////////////////////////////////////

// Purpose:    Write one bit to internal eeprom
// Inputs:     1) An eeprom address
//             2) The bit position (LSB == 0)
//             3) The bit to write
// Outputs:    None
void write_int1_eeprom(INT_EEPROM_ADDRESS address, int8 bitPosition, int1 data)
{
   int8 stored_data;

   stored_data = read_eeprom(address);

   if(data)
   {
      bit_set(stored_data, bitPosition);
   }
   else
   {
      bit_clear(stored_data, bitPosition);
   }

   write_eeprom(address, stored_data);
}


// Purpose:    Read one bit from internal eeprom
// Inputs:     1) An eeprom address
//             2) The bit position (LSB == 0)
// Outputs:    The bit read from internal eeprom
int1 read_int1_eeprom(INT_EEPROM_ADDRESS address, int8 bitPosition)
{
   return bit_test(read_eeprom(address), bitPosition);
}


// Purpose:    Write a 16 bit number to internal eeprom
// Inputs:     1) An eeprom address
//             2) The 16 bit number to write to internal eeprom
// Outputs:    None
void write_int16_eeprom(INT_EEPROM_ADDRESS address, int16 data)
{
   int8 i;

   for(i = 0; i < 2; ++i)
   {
     write_eeprom(address + i, *((int8 *)(&data) + i));
   }
}


// Purpose:    Read a 16 bit number from internal eeprom
// Inputs:     An eeprom address
// Outputs:    The 16 bit number read from internal eeprom
int16 read_int16_eeprom(INT_EEPROM_ADDRESS address)
{
   int8  i;
   int16 data;

   for(i = 0; i < 2; ++i)
   {
     *((int8 *)(&data) + i) = read_eeprom(address + i);
   }

   return(data);
}


// Purpose:    Write a 32 bit integer to internal eeprom
// Inputs:     1) An eeprom address
//             2) The 32 bit number to write to internal eeprom
// Outputs:    None
void write_int32_eeprom(INT_EEPROM_ADDRESS address, int32 data)
{
   int8 i;

   for(i = 0; i < 4; ++i)
   {
     write_eeprom(address + i, *((int8 *)(&data) + i));
   }
}


// Purpose:    Read a 32 bit integer from internal eeprom
// Inputs:     An eeprom address
// Outputs:    The 32 bit integer read from internal eeprom
int32 read_int32_eeprom(INT_EEPROM_ADDRESS address)
{
   int8  i;
   int32 data;

   for(i = 0; i < 4; ++i)
   {
     *((int8 *)(&data) + i) = read_eeprom(address + i);
   }

   return data;
}


// Purpose:    Write a floating point number to internal eeprom
// Inputs:     1) An eeprom address. Four eeprom locations will be used.
//             2) The floating point number to write to internal eeprom
// Outputs:    None
void write_float_eeprom(INT_EEPROM_ADDRESS address, float data)
{
   int8 i;

   for(i = 0; i < 4; ++i)
   {
     write_eeprom(address + i, *((int8 *)(&data) + i));
   }
}


// Purpose:    Read a floating point number from internal eeprom
// Inputs:     An eeprom address
// Outputs:    The floating point number read from the internal eeprom
float read_float_eeprom(INT_EEPROM_ADDRESS address)
{
   int8 i;
   float data;

   for(i = 0; i < 4; ++i)
   {
     *((int8 *)(&data) + i) = read_eeprom(address + i);
   }

   return data;
}

#endif
```



Bueno llego tarde al trabajo pero no aguante ja ja !!! lo estuve viendo , parece perfecto y sencillo creo que lo veo  claro . Te  agradezco muchisimo a la noche te cuento como me fue Saludos , Mil gracias !!!!!


----------



## ariel 37 (May 22, 2014)

Hola D@rkbytes, te queria agradecer nuevamente por la ayuda que me diste,acabo de probar el programa que me pasaste , leyendo el canal adc y guardando en la memoria ,y hasta ahora en la simulacion funciona perfecto asi que mañana lo probare fisicamente haber que tal me va . Pero como mi idea no es solo copiar y pegar, sino aprender ,te queria hacer unas preguntas asi afirmo conceptos .
El tema de que no usas librerias es por que las funciones que hiciste lo hacen todo y no la necesitan ?
Como sabe esta funcion : while(input(pin_c0))     que el pin c0 esta en cero  y cuando cambia a 1 se ejecuta la instruccion ? pense que siempre habia que aclararlo por ejemplo if( input (pin_c0))==1
Y esta otra : while(input(pin_c0));  con que tiempo y como  Esperar hasta que RC0 sea 0 nuevamente.
Disculpa mi ignorancia ,tal vez las preguntas sean demasiado basicas,pero si quiero aprender las tengo que hacer y me has generado la confianza para hacerlas . Te mando un cordial saludo y muchas gracias por tu disposicion para enseñar


----------



## D@rkbytes (May 22, 2014)

ariel 37 dijo:


> ¿El tema de que no usas librerías es por que las funciones que hiciste lo hacen todo y no la necesitan?


Una librería es un archivo con varias funciones que pueden ser usadas en otros programas.
En sí, debe contener todas las funciones, variables y constantes necesarias para que funcione cada rutina.
Si te fijas bien, las rutinas que utilicé contienen sus propias variables y son independientes.
Pueden colocarse dentro de alguna librería para ser parte de ella, o simplemente usarlas dentro del programa.
Como únicamente necesitas las rutinas para leer y escribir datos de 16 bits, no necesitas una librería con rutinas que no vas a utilizar.


ariel 37 dijo:


> ¿El tema de que no usas librerías es por que las funciones que hiciste lo hacen todo y no la necesitan?
> Como sabe esta función : while(input(pin_c0))     que el pin c0 esta en  cero  y cuando cambia a 1 se ejecuta la instrucción ? pensé que siempre  había que aclararlo por ejemplo if( input (pin_c0))==1
> Y esta otra : while(input(pin_c0));  con que tiempo y como  Esperar hasta que RC0 sea 0 nuevamente.


La instrucción INPUT funciona en modo verdadero por defecto.
Es decir, no se necesita especificar el valor 1 para que lo interprete como expresión, a menos que se indique lo contrario.
Por ejemplo, de la forma negada:

While (Input (PIN_C0) == 0)
{
// Código
}

O de la siguiente forma:

While (!Input (PIN_C0))
{
// Código
}
// ******************************************
Así que, si no se declara el estado lógico, la instrucción lo tomará siempre como un 1.
Por lo tanto será lo mismo escribir While (Input (PIN_C0)) que While (Input (PIN_C0) == 1)
En el segundo ejemplo se está usando el operador ! que sirve para indicar una negación lógica.


ariel 37 dijo:


> Y esta otra : while(input(pin_c0));  con que tiempo y como  Esperar hasta que RC0 sea 0 nuevamente.


Toma la instrucción While como la traducción "Mientras"
Así que, en resumen se podrá entender de esta manera:

Mientras (RC0 sea 1) // Realiza lo siguiente secuencialmente...
{
// Código
// Más código
Mientras (RC0 sea 1); // Se queda aquí esperando hasta que RC0 sea 0 nuevamente.
} // Cuando RC0 ya esté en 0 sale de los bucles.

Se asume que RC0 tiene resistencia pull-down, (estará en 0 lógico)  o estado de reposo, por lo tanto no se entrará al bucle anidado hasta que RC0 sea 1.

Cuando RC0 sea 1, se ejecutarán las instrucciones internas y cuando se termine de ejecutar la última instrucción, se entrará al segundo bucle.
Este segundo bucle genera un bucle infinito en sí mismo mientras RC0 sea 1.
Por lo tanto no se podrá salir del primer bucle hasta que RC0 sea 0 nuevamente porque el segundo bucle lo está impidiendo.

Espero haberme explicado y que hayas logrado entender lo que preguntaste.

Saludos.


----------



## ariel 37 (May 23, 2014)

Wow un genio !!!! te mando un bucle infinito de gracias !!!! la explicacion perfecta ,como se dice aca en  argentina " entendi todo al pelo " Te agradezco un monton por tu voluntad .Este fin de semana espero terminar todo y despues te cuento como me fue .Saludos !!!


----------



## ariel 37 (May 25, 2014)

Hola D@rkbytes, te queria agradecer una vez mas por tu ayuda , y contarte que probe el programa en la plaqueta con un lcd de 2 x 16 y funciona !!!! asi que estoy re contento por haber aprendido una pequeña cosa mas de este interesantisimo mundo de los pics . Ahora con mas ganas de seguir adelante , te mando un gran saludo desde Mar del Plata Argentina!!!!


----------



## D@rkbytes (May 25, 2014)

Me da mucho gusto que haya funcionado tu programa y que estés contento con los resultados.
Gracias por los comentarios y que bueno que te guste el mundo de los microcontroladores PIC.

Te deseo mucha suerte en tus proyectos y esperamos seguirte viendo por aquí.

Saludos.


----------



## jucaceledon (Jul 15, 2014)

Hola D@rkbytes. Escribo acá para hacerle mi consulta, tengo una duda.
Estoy haciendo un programa ccs donde en RA0 ingreso un dato (lm35) que es float, de aquí lo llevo a un lcd y comparo con un seteo de temperatura máxima y mínima, si este dato es mayor que temp max, detiene un calefactor y si es menor a temp mínima, enciende este calefactor.
Estos seteos temp máxima y mínima debo guardarlos en la eeprom interna y que ante un corte de energia y/o reinicio del sistema estos valores permanecieran y fueran utilzados nuevamente (debe incluir el punto decimal, no necesario el valor ya que considera solo valor positivo) así como la activación y desactivación de un motor pap.

Todo bien hasta cuando quiero guardarlo, usted me sugiere que trabaje con int16 todo, pero la verdad es que no entiendo mucho.
Aquí está lo realizado hasta hoy.


```
# include <16f877a.h>
# device *=16
# device adc=10
# use delay(clock=4M)
# include <lcd420.c>

float temperatura;
float tempmin;
float tempmax;

void main()
{

//*******************************
setup_adc_ports(RA0_ANALOG);//entrada del LM35
setup_adc(ADC_CLOCK_INTERNAL);
setup_COUNTERS(RTCC_internal.rtcc_div_1);//marca de división
set_adc_channel(0);
//*******************************

lcd_init();// inicia lcd
lcd_gotoxy(5,1);//posiciona el puntero del renglón
printf(lcd_putc,"Temperatura");//imprime temperatura
delay_ms(350);//retardo para lectura
lcd_init();//resetea lcd

SET_TRIS_c (0b11111111);// 
SET_TRIS_d (0b11111111);
while (true) 
{
//delay_ms(200);
if (input(pin_c0)==1)
{
  tempmin=tempmin+0.1;
}
if (input(pin_c1)==1)
{
  tempmin=tempmin-0.1;
}

if (input(pin_c2)==1)
{
  tempmax=tempmax+0.1;
}
if (input(pin_c3)==1)
{
  tempmax=tempmax-0.1;
}
[COLOR=Red]// aqui se debe guardar este valor de tempmax y tempmin en la eeprom inclido los decimales[/COLOR]
temperatura=(float)read_adc()/2;
//********grados centigrados
lcd_gotoxy(8,2);
printf(lcd_putc,"%f",temperatura);//imprime bajo lectura temperatura, el valor de temperatura
lcd_gotoxy(1,1);
printf(lcd_putc,"T. min");// [COLOR=Red]imprime temp min  [/COLOR]
lcd_gotoxy(8,1);
printf(lcd_putc,"T. Act");//imprime tem actual
lcd_gotoxy(15,1);
printf(lcd_putc,"T. max");//[COLOR=Red]imprime temp max idem para temp min[/COLOR]
lcd_gotoxy(1,2);
printf(lcd_putc,"%f",tempmin);// [COLOR=Red]imprime el valor de tempminy que es el mismo valor que se seteo o si es reinicio el ultimo valor guardado [/COLOR]
//delay_ms(200);
lcd_gotoxy(15,2);
printf(lcd_putc,"%f",tempmax);// [COLOR=Red]imprime el valor de tempmax IDEM PARA TEMPMIN[/COLOR]
lcd_gotoxy(5,3);
printf(lcd_putc,"estamos probando");
//delay_ms(200);
lcd_gotoxy(5,4);
printf(lcd_putc,"vamos hbien");
//delay_ms(200);
//***********si la temperatura es mayor que temmax
if(temperatura<=500&&temperatura>=tempmax)
{
output_low(pin_d2);
output_low(pin_d4);
}
//**********si la temperatuta es menor a la tem min
if(temperatura<=tempmin&&temperatura>=0)
{
output_high(pin_d2);
output_high(pin_d4);
}
//aca va la secuencia de motor, esta solo la parte manual, debo incorporar la etapa automatica que la adjunto mas adelante
//***************inicioetapa manual
//pin c5 y 6 ent, c7 y d0 salida

//*******derecha

if (input(pin_d1)==1)
{
output_high (pin_d5);
output_high (pin_c5) ;
output_low (pin_c6) ;
output_high (pin_c7) ;
output_low (pin_d0) ;
delay_ms(1);

output_low (pin_c5) ;
output_high (pin_c6) ;
output_high (pin_c7) ;
output_low (pin_d0) ;
delay_ms(1);

output_low (pin_c5) ;
output_low (pin_c6) ;
output_low (pin_c7) ;
output_low (pin_d0) ;
delay_ms(1);

output_low (pin_c5) ;
output_low (pin_c6) ;
output_low (pin_c7) ;
output_low (pin_d0) ;
delay_ms(1);
}
//*******izquierda

if (input(pin_d3)==1)
{
output_high (pin_d5);
output_low (pin_c5) ;
output_high (pin_c6) ;
output_high (pin_c7) ;
output_low (pin_d0) ;
delay_ms(1);

output_low (pin_c5) ;
output_high (pin_c6) ;
output_low (pin_c7) ;
output_high (pin_d0) ;
delay_ms(1);

output_low (pin_c5) ;
output_low (pin_c6) ;
output_low (pin_c7) ;
output_low (pin_d0) ;
delay_ms(1);
output_low (pin_c5) ;
output_low (pin_c6) ;
output_low (pin_c7) ;
output_low (pin_d0) ;
delay_ms(1);

output_low (pin_d5);

output_low (pin_d5);

//fin movimiento motor
}
}
}
```
Acá va la etapa del motor.

```
#include <16F877A.h>         //Libreria del Pic Implementado.
#fuses HS, NOWDT, PUT, NOLVP   //Deshbilita el Doggy, Oscilador Externo.
#use delay( clock = 4000000 )      //Frecuencia de Reloj.
#byte port_D = 0x06            //Direccion del Puerto B.

 int32 Cont = 0;               //Variable que Cuenta.
 int32 Cont1 = 0;
#int_Timer1                  //Interrupcion del Timer0.

void TIMER0_isr( void )
   {
      Cont++;               //Incrementa el Contador.
      Cont1++;
      set_timer0(3036 );     //Carga el Timer0.
   }
   
void main( void )
   {  
      set_tris_B( 0x00 );   //Puerto B como Salida que debe ser cambiado despues
      setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);;   //Preescaler de 64.
      enable_interrupts( INT_TIMER1 );      //Habilita la Interrupcion del Timer0.
      enable_interrupts( GLOBAL );         //Habilita la Interrupcion Global.
      set_timer1( 3036 );               //Carga el Timer0.
      output_low( PIN_B1 );//para mantenerlo en cero
      output_low( PIN_B2 );//para mantenerlo en cero
      while( 1 )
      {
    //***********************************aqui falta indicar que si un pin esta en 1 haga este conteo***********

         if( Cont ==3600 )            
            {
               output_high ( PIN_B1 );// aqui espera una 1/2 aprox y que parta por 5 minutos (la secuencia del motor es la misma que en el anterior programa)
            }
         else if( Cont >4200 )        //aqui le digo que si funcionó 5 minutos espero 1/2 hora por .
            {
               output_low( PIN_B1 );
               
            }        
         if( Cont1 ==7800 )            //le digo que si funciono  5 min espere 1/2 hora y asi sucesivamente 
            {
               output_high ( PIN_B2 );
            }
         else if( Cont1 >8400 )        //Si llega 4 RB0 = 0.
            {
               output_low( PIN_B2 );
               Cont = 0;
               Cont1 = 0;
           }
      }
}
```
Adjunto el dns y los programas van así.

Temperatura con incubadora  e interrupciones con solo motor.

Nota: este programa yo lo hice en flow code (éste hacia el tratamiento en forma interna) pero migre a ccs por motivación personal y para ampliar mis conocimientos, me ha costado un mundo pero se logrará, de eso estoy seguro.

Usé la librería lc420, pero ésta no se salta RB3
¿Cómo lo puedo hacer para hacer que sean de corrido?
(La placa está hecha, así que debo acomodar el programa a la placa)


----------



## D@rkbytes (Jul 15, 2014)

No se me hace coherente la forma como lo estás haciendo.
Tampoco sé si lo que quieres tomar como referencia es la parte decimal (resto)
Si es así, eso no te servirá, pues el valor de la parte decimal podrá estar en varias lecturas.

Puedes hacerlo de forma sencilla trabajando con el ADC a 8 bits.
Así puedes usar 2 variables de 8 bits y una float para mostrar el resultado con decimales.
Una  de ellas será una variable espejo de 8 bits que contendrá el valor entero de la temperatura.
Ese valor de 8 bits ya lo puedes guardar sin problemas en la memoria.

Por ejemplo:
int8 valor_adc, ee_temp;
float temperatura;

Realizas la lectura con conversión a float:
float valor_adc = read_adc();
Haces la conversión:
temperatura = (mis cálculos usando valor_adc);
Muestras el resultado con punto flotante:
printf(lcd_putc,"%f ",temperatura);

Ahora usas la otra variable de 8 bits para tomar el entero de temperatura:
ee_temp = temperatura;
Y ya puedes usar ese valor para guardarlo en la memoria.
write_eeprom(X, ee_temp);

Si lo quieres hacer con 10 bits de resolución y usando variables de 16 bits, es lo mismo pero ya tendrás que usar el procedimiento del post #2.

Como te menciono, ya puedes tener dos referencias para realizar las comparaciones.
Puedes usar la variable temperatura o la variable valor_adc, pero tal vez necesites otras variables espejo que contengan el valor entero para que los resultados coincidan.

Suerte.


----------



## jucaceledon (Jul 15, 2014)

Ok, empezare todo de nuevo 

de lo que entendi lo explicare.

1.- Usted me dice que el valor de temp max y temp min lo haga cada uno de dos partes; 1 la parte entera y la otra la perta decimal, luego las uno y eso lo envio al lcd, esta bien asi o entendi mal.

2.- No se si estoy equivocado pero no entendi esto de 

int8 valor_adc, ee_temp;aqui crea variable de 8 bit en valor_adc y otra ee_temp, pero para que ee_temp

float valor_adc = read_adc(ra0);aqui lee la entrada analoga y la deja como flotante

temperatura = (mis cálculos usando valor_adc);que calculos ??????, o se refiere para comparar temp min y temp max con temperatura

printf(lcd_putc,"%f ",temperatura);esto esta claro


Ahora usas la otra variable de 8 bits para tomar el entero de temperatura:
ee_temp = temperatura;para que esto si ya se tomo temperatura y se llevo a flotante
Y ya puedes usar ese valor para guardarlo en la memoria.
write_eeprom(X, ee_temp);esta sentencia la tengo claro pero no lo de las variables

ahora no entendi o no esta lo de crear una variable para temp min y otra para temp maxima que se incrementen o decremente en 0.1 y se escriba en la lcd, como tampoco compararla

Espero no se moleste pero la verdad es que quede mas confundido que ants

juka


----------



## D@rkbytes (Jul 16, 2014)

jucaceledon dijo:


> Espero no se moleste pero la verdad es que quedé más confundido que antes.


Claro que no me molesto y es normal que no hayas comprendido algunas cosas.

Para que entiendas mejor que fue lo que traté de explicar, adjunto un proyecto completo de control de incubadora.
No es nada profesional pero te puede servir como base para realizar el programa como tú lo deseas.

Este proyecto cuenta con las siguientes características:
Detección de corte eléctrico. (Guarda las temperaturas establecidas en la EEPROM interna.)
Selección de temperatura máxima y mínima.
Activación de un calefactor por decremento de la temperatura mínima establecida.
Activación de un ventilador por incremento de la temperatura máxima establecida.
Muestra el valor de la temperatura en °C usando el sensor LM35 y también los valores establecidos.
Se utilizó una pantalla LCD 16x2 para visualizar los datos.

No realiza los incrementos/decrementos por fracciones, sino por valores enteros.
Entiendo que requieres de más precisión, pero modificando este programa tal vez lo puedas lograr.

Suerte.


----------



## jucaceledon (Jul 16, 2014)

D@rkbytes dijo:


> Claro que no me molesto y es normal que no hayas comprendido algunas cosas.
> 
> Para que entiendas mejor que fue lo que traté de explicar, adjunto un proyecto completo de control de incubadora.
> No es nada profesional pero te puede servir como base para realizar el programa como tú lo deseas.
> ...



Primero agradecer su amabilidad, voluntad y tiempo entregado a sus respuestas, pedir disculpas por tomar su ejemplo y cortarlo para hacer las consultas, solo dejo las interrogantes (obviamnete esperando su respuestas)


#device  adc = 10  // ADC a 10 bits aqui tenia un error

#define t_min_decr pin_b7 aqui define la entrada haber omitido y solo preguntar leugo si es verdadera esta entrada
while (true)
   {

     if(input(pin_b7))
     {
        --temp_min;             // Decrementa temperatura mínima.
         if(temp_min > temp_sens){temp_min = 0;}

#define t_min_incr pin_b6 idem a anterior
#define t_max_decr pin_b5 idem a anterior
#define t_max_incr pin_b4 idem a anterior

#define calefactor pin_c1 aqui solo activala salida como pin
if(round_temp8 < temp_min)
      {
  output_high(pin_c1); es lo mismo???
         delay_ms(100);
#define ventilador pin_c0 iedm anterior 

#define temp_sens 149 por que 149, es por la cuenta max 150????


void main (void)
{
int16 adc_corte;esto es corte electrico y es por ausencia de voltaje, pero como hace para que el pic siga energizado,* buena muy buena idea* 
int8 round_temp8,temp_min,temp_max;esto es para trabajar las variables
float valor_adc,temperatura;

 port_b_pullups(true); a que se refiere esto, no lo habia visto antes????

   temp_min = read_eeprom(0);ok, este es el valor que debe aparecer en lcd, despues del corte
   temp_max = read_eeprom(1);ok idem anterior


   if(temp_min > temp_sens){temp_min = 36;} aqui pre fija la temp inicial despues del corte yo pretendo    hacerlo que ante un reinicio o corte tome el valor de memoria
   if(temp_max > temp_sens){temp_max = 38;} idem a anterior


   while (true)
   {

     if(!input(t_min_decr))
     {
        --temp_min;  este valor debe ser guardado en memoria  
         if(temp_min > temp_sens){temp_min = 0;} para que es esto, si segun mi programa deberia aparecer la ultima seteo de temp guardado

 es decir 

 write_eeprom(0,temp_min); esta bien esto

     }

     if(!input(t_min_incr))
     {
         ++temp_min; idem a anterior.
         if(temp_min > temp_sens){temp_min = 150;} idem a anterior
     }

      set_adc_channel(0);           // Activar el canal 0
      delay_us(50);

      valor_adc = read_adc();

      temperatura = ((valor_adc *150)/308);por que estos valores, no lo hace directamente el lm35

      round_temp8 = temperatura; aqui convierte la variable int8 a flotante ???



      adc_corte = read_adc();       // Leer el canal 3 para sensar corte eléctrico.

      if(adc_corte <= 850)     por que este valor
      {


Espero pueda comprender mis dudas, quiero interpretar primero su programa para luego hacer el mio, ya que empezare todo de nuevo pero ordenado y bien definido

Juka


----------



## D@rkbytes (Jul 16, 2014)

jucaceledon dijo:


> Primero agradecer su amabilidad, voluntad y tiempo entregado a sus respuestas, pedir disculpas por tomar su ejemplo y cortarlo para hacer las consultas, solo dejo las interrogantes (obviamente esperando su respuestas)


Pues según veo, casi no comprendiste nada sobre lo que hace el programa.
Trataré de explicar las dudas que tienes respecto a las funciones del programa.


jucaceledon dijo:


> #device  adc = 10  // ADC a 10 bits aquí tenía un error


Esta sentencia es la que le dice al compilador que se va a usar el conversor ADC a 10 Bits.
Si te arroja un error, lo más seguro es que tengas que actualizar la versión que estás usando.


jucaceledon dijo:


> #define t_min_decr pin_b7 aquí define la entrada haber omitido y solo preguntar luego si es verdadera esta entrada
> while (true)
> {
> 
> ...


Son definiciones (En este caso para darle nombres a los pines)
Si no te gusta trabajar de esa manera, los puedes omitir y usar directamente el nombre de los pines.


jucaceledon dijo:


> {
> output_high(pin_c1); es lo mismo???
> delay_ms(100);
> #define ventilador pin_c0 iedm anterior
> ...


Como te mencioné anteriormente, es resultado será el mismo si usas la definición o el nombre del pin.
Se pone un número menos (149) porque en la comparación se usa el operador >
Así que, si se pone como referencia 150 entonces un número mayor que 150 será 151 


jucaceledon dijo:


> int16 adc_corte;esto es corte eléctrico y es por ausencia de voltaje, ¿pero cómo hace para que el pic siga energizado?* buena muy buena idea*


El microcontrolador se mantiene con energía debido a que se está usando un capacitor de 4700uF (Mirar esquema)
Este capacitor de alto valor mantendrá energizado al PIC el tiempo suficiente para realizar la operación de escritura en la EEPROM interna.
La referencia por corte eléctrico se deberá tomar por medio de un diodo antes del filtraje de la fuente de poder.
Esto es para que la falta de energía sea detectada cuando ocurre, y como el PIC aún tendrá energía, podrá realizar la detección por corte eléctrico.


jucaceledon dijo:


> int8 round_temp8,temp_min,temp_max;esto es para trabajar las variables
> float valor_adc,temperatura;
> 
> port_b_pullups(true); ¿A qué se refiere esto, no lo había visto antes?
> ...


Así es, esas variables son las que determinan el rango de temperatura establecida por el usuario.
*port_b_pullups(true);* Sirve para activar las resistencias pull-up internas del puerto B
Esto es con la finalidad de no colocar resistencias externas y usar las que tiene el PIC internamente.

Por este motivo, en las sentencias* IF *se usó el operador* !* que sirve para establecer una negación lógica.
Osea; en vez de escribir *if(input(pin_xx ==0))* tan sólo se escribe *if(!input(pin_xx))*
En ambas sentencias se realiza la misma operación pero sintetiza la escritura.


jucaceledon dijo:


> temp_min = read_eeprom(0);ok, este es el valor que debe aparecer en lcd, después del corte
> temp_max = read_eeprom(1);ok idem anterior


Eso ya será una modificación que tengas que hacer a tu programa.


jucaceledon dijo:


> if(temp_min > temp_sens){temp_min = 36;} aquí pre fija la temp inicial después del corte yo pretendo    hacerlo que ante un reinicio o corte tome el valor de memoria
> if(temp_max > temp_sens){temp_max = 38;} idem a anterior


Y eso es lo que aquí se está realizando.
Pero aquí el programa está verificando también algo importante.
Cuando una memoria está sin grabar (Virgen) sus locaciones tienen el valor 0xFF (255 en decimal)
Si se realiza la primer lectura y se toma el 255 como valor, éste será mostrado en pantalla, y como la lectura máxima es de 150°C no tendrá lógica mostrar un valor de 255.

Así que, aquí se está comprobando que la lectura nunca supere 149 (Una incubadora nunca llegará a ese valor)


jucaceledon dijo:


> --temp_min;  este valor debe ser guardado en memoria
> if(temp_min > temp_sens){temp_min = 0;} ¿Para qué es esto, si según mi programa debería aparecer el último seteo de temp guardado?
> 
> Es decir
> ...


Eso también será parte de las modificaciones que tendrás que realizar.


jucaceledon dijo:


> temperatura = ((valor_adc *150)/308); ¿Por qué estos valores? ¿No lo hace directamente el lm35?


Esa es la fórmula que yo usé, tú puedes utilizar la que creas más conveniente.
150 es la temperatura máxima del LM35 y 308 es la lectura del ADC a 10 bits cuando el LM35 está a 150°C
El LM35 entrega 10mV por cada grado centígrado y se tiene obviamente que usar una formula para obtener una lectura correcta.

Aquí te recomiendo que estudies sobre el *funcionamiento del ADC* para comprender porqué no podrás hacer comparaciones de 0.1 en 0.1 a 10 bits.


jucaceledon dijo:


> --temp_min;  este valor debe ser guardado en memoria
> if(temp_min > temp_sens){temp_min = 0;} para que es esto, si según mi programa debería aparecer la última seteo de temp guardado
> 
> es decir
> ...


Eso también será parte de las modificaciones que tendrás que realizar.


jucaceledon dijo:


> round_temp8 = temperatura; ¿Aquí convierte la variable int8 a flotante ?


Nop, aquí se toma el valor entero de un resultado con punto flotante.
*round_temp8* (8 bits) Sirve para realizar las comparaciones y obtener el valor que será guardado en la memoria.


jucaceledon dijo:


> adc_corte = read_adc();       // Leer el canal 3 para sensar corte eléctrico.
> 
> if(adc_corte <= 850)     por que este valor
> {


Es el valor de referencia de lectura del ADC cuando el voltaje de corte sea aproximadamente 4.1V.
Este valor es el que debes determinar para establecer a que voltaje ocurrirá el evento de corte eléctrico.
Mira bien el esquema y la simulación para que tengas una idea sobre esto.
Ahí se incluye un voltímetro sobre este voltaje para que puedas darte una idea.


jucaceledon dijo:


> Espero pueda comprender mis dudas, quiero interpretar primero su  programa para luego hacer el mio, ya que empezaré todo de nuevo pero  ordenado y bien definido
> 
> Juka


Claro que entiendo pues apenas estás empezando con este lenguaje después de haber pasado por FlowCode.
Es mejor que te hayas decidido por dejar eso y en verdad aprender un lenguaje de programación.

Ahora espero que yo me haya dado a entender y puedas comprender que es lo que está realizando ese programa.

Suerte.


----------



## talquino2012 (Jul 17, 2014)

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




```
#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.


----------



## D@rkbytes (Jul 17, 2014)

talquino2012 dijo:


> 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.


----------



## jucaceledon (Jul 22, 2014)

D@rkbytes dijo:


> 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:
> 
> ...



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


----------



## miglo (Feb 1, 2018)

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.


----------



## Gudino Roberto duberlin (Feb 1, 2018)

Hola, imposible abrir ese formato de archivo, súbelo en .txt o similar.


----------



## D@rkbytes (Feb 1, 2018)

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.



Gudino Roberto duberlin dijo:


> 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.


----------



## miglo (Feb 1, 2018)

```
#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.





D@rkbytes dijo:


> 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.
> 
> ...



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.


----------



## D@rkbytes (Feb 1, 2018)

miglo dijo:


> 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.


miglo dijo:


> 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:

```
printf(lcd_putc,"  GRABADO EL VALOR  ");
```
No estás presentando ningún valor para darle formato.
Así que puede quedar así simplemente:

```
lcd_putc("  GRABADO EL VALOR  ");
```
Y ahorras memoria RAM.


----------



## miglo (Feb 1, 2018)

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.


----------



## D@rkbytes (Feb 1, 2018)

Usa una interrupción externa y utiliza algún timer en lugar de usar retardos.


----------



## miglo (Feb 2, 2018)

Siguiendo tu consejo lo hecho de la siguiente forma, espero que sea correcta.



> #int_timer1
> void timer1_isr(void)
> {
> a++;
> ...



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?.


----------



## D@rkbytes (Feb 2, 2018)

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.


----------



## miglo (Feb 3, 2018)

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.


```
#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;}
 
    }
  }
```


----------



## D@rkbytes (Feb 3, 2018)

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.


----------



## miglo (Feb 3, 2018)

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.


----------



## D@rkbytes (Feb 3, 2018)

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.


----------



## Alejandro84 (Feb 6, 2018)

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.


----------



## D@rkbytes (Feb 6, 2018)

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.


----------



## Alejandro84 (Feb 6, 2018)

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.


----------



## D@rkbytes (Feb 6, 2018)

Básicamente para obtener el MSB y el LSB, sería así:

```
unsigned char msb = (valor_16bits >> 8) & 0xFF;
unsigned char lsb = (valor_16bits & 0xFF);
```
Y para recuperar el valor de 16 bits, sería así:

```
valor_16bits = (unsigned int) (msb << 8) | lsb;
```


----------



## Dr. Zoidberg (Feb 6, 2018)

Yo usaria algo mas simple:

```
typedef union {
   int16 dato;
   unsigned char b[2];
} int2bytes;
```
Con esa union es muy simple la transformacion:

```
...
int2bytes x;

x.dato = dato_de_16_bits;
dato_bajo_de_8_bits = x.b[0];
dato_alto_de_8_bits = x.b[1];
```

La conversion inversa es simple de imaginar...


----------



## Alejandro84 (Feb 7, 2018)

Muchas gracias a ambos por sus respuestas, la verdad un foro genial, al igual que la coordialidad de sus miembros, en c nunca habia programado, en delphi que utiliza pascal si tengo años de experiencia y me ayuda a comprender el codigo c proque tiene sus similitudes y bueno la logica de programacion es mas menos  la misma en todos los lenguajes. Automatizaba procesos con software sobre windows, controlando por puertos usb o lpt1 o com. ahora estoy en el mundo de los pic y mas recientemente en con las placas arduino que me ahoran todo el lio de ensamblar el circuito. Gracias de nuevo y de seguro estare por aca con mas dudas y espero que alguna que otra vez tambien yo pueda aportar algo a  quien lo necesite.


----------



## miglo (Feb 24, 2018)

D@rkbytes dijo:


> 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.



Hola D@rbytes, estado probando lo que dices y va de lujo, al principio me creò problemas por que no me di cuenta de poner la libreria "internal_eeprom.c", una vez puesta todo perfecto.

Una pregunta, quiero probar para contar las vueltas de un tacometroy guardarlas por si hay corte de tension, en float usa 4 direcciones, voy a usar un int16 que es mas que suficiente, he leido por algun sitio que no hay que abusar de la eeprom a la hora de estar guardando datos, como solo va ser en momentos puntuales, es correcto que ponga "write_int16_eeprom(direccion,variable);" dentro le la interrupcion?


```
#int_timer1
   void timer1_isr(void){
     vueltas=get_timer0();
      rpm=vueltas*2;
       write_int16_eeprom(6,rpm);
       set_timer0(0);
        set_timer1(3036); 
        }
```

o no es un problema de mayor importancia?.


----------



## Gudino Roberto duberlin (Feb 24, 2018)

Hola, las celdas EEPROMs, tienen una limitada cantidad de ciclos de escritura. Entonces en tú caso, a la hora de almacenar el valor, tienes que detectar el momento en que se produce la falta de alimentación. Y ahí, en esos pocos milisegundos que haya de tiempo, hasta que la tensión de fuente decae, almacenar en los registros EEPROM.


----------



## D@rkbytes (Feb 24, 2018)

miglo dijo:


> Una pregunta, quiero probar para contar las vueltas de un tacómetro y guardarlas por si hay corte de tensión.
> En float se usan 4 direcciones, voy a usar un int16 que es más que suficiente.
> He leido por algun sitio que no hay que abusar de la eeprom a la hora de estar guardando datos.
> Como solo va ser en momentos puntuales, ¿es correcto que ponga "write_int16_eeprom(direccion,variable);" dentro le la interrupción?
> ¿O no es un problema de mayor importancia?


Es preferible usar banderas y posteriormente las verifiques.
En algunos casos no pasa nada si se introducen rutinas de ese tipo en el servicio de interrupción, pero en otros casos sí pueden afectar.
Como quiera, el compilador se da cuenta de ello y deshabilita la interrupción hasta que se ejecute el código interno.
Cuando eso sucede lo podrás ver en el log de compilación como una advertencia.

Ahora, la mayoría de las EEPROMS internas de los PIC's, si no es que todos, soportan alrededor de un millón de lecturas o escrituras.


			
				Alguna hoja de datos dijo:
			
		

> • 1,000,000 erase/write cycle Data EEPROM memory typical
> • Data EEPROM Retention > 40 years


Así que con ese dato puedes saber cuánto podría tener de vida la EEPROM.
Que escribiéndola constantemente como en el código que expones, no sería por mucho tiempo.

Es mejor realizar lo que menciona Gudino, si no quieres que la EEPROM se deteriore pronto.
Por aquí en alguno de los foros subí un ejemplo de cómo hacerlo.
No recuerdo en cual, ni tampoco en qué lenguaje escribí el programa.
Pero dale una leída al registro PCON y te podrás dar una idea de la implementación.


----------



## miglo (Feb 24, 2018)

Hare lo que dice gudino, para ello me basare en el ejemplo que pusiste D@rbytes en un post, para ello tambien cambiare algunos condesadores, sobretodo el de filtrado que alimenta el micro, hay pondre uno de 4700uf. 

Gracias a los dos.


----------



## Gudino Roberto duberlin (Feb 24, 2018)

Recomendación, es preferible detectar el shut down, antes del regulador que alimenta al microcontrolador.
Pues si lo haces a la salida del mismo, sólo podrás detectarlo cuando dicho regulador deje de hacer lo que mejor hace, y puede ser tarde... y el micro puede entrar en mal funcionamiento, dependiendo de cómo esté configurado el fuse BOR. Sin ir más lejos, al detectar en la entrada del regulador cómo mencioné, recuerda que esa tensión de muestra, no supere a la de alimentación del controlador, yo suelo utilizar una simple resistencia, asociado a un zener de 5V1.(o la tensión de VDD) y un pequeño condensador de 100nF cómo filtro de algún ruido que pueda colarse a la entrada.


----------



## miglo (Feb 25, 2018)

```
set_adc_channel(3);           // Activar el canal 3
      delay_us(50);
      
      adc_corte = read_adc();       // Leer el canal 3 para sensar corte eléctrico.
      
      if(adc_corte <= 850)          // Si la lectura del canal 3 es menor a 850...
              {
         // Se escriben las temperaturas seleccionadas en la eeprom interna.
         write_eeprom(0,temp_min);
         delay_ms(10);
         write_eeprom(1,temp_max);
         // Se avisa sobre el suceso.
         lcd_putc("\f     !AVISO!");
         lcd_putc("\n CORTE ELECTRICO ");
         delay_ms(5000);
            }
```

Esto esta sacado de D@rbytes, pero en su ejemplo la alimentacion la toma despues del 7805, que es donde tiene puesto un electrolitico de 4700uf, tu hablas de cojerla antes del regulador y con una resistencia limitadora mas el zener de 5.1 mandarlo a la entrada analogica.

Por lo que veo, creo que las dos opciones son validas, no crees?

Una pregunta, uso el 16F877A y todas las entradas del puertoA analogico las tengo ocupadas, que otra solucion podria usar para tener la referencia de la entrada analogica?, es por no restructurar las entradas.


----------



## Gudino Roberto duberlin (Feb 26, 2018)

Hola, bueno, añadiendo un op-amp, puedes detectar el umbral e inyectarlo a una entrada digital.


----------



## D@rkbytes (Feb 27, 2018)

miglo dijo:


> Esto esta sacado de D@rbytes, pero en su ejemplo la alimentación la toma después del 7805, que es donde tiene puesto un electrolítico de 4700 uF.
> Tú hablas de cojerla antes del regulador y con una resistencia limitadora mas el zener de 5.1 mandarlo a la entrada analógica.


Me parece que no leíste sobre las consideraciones a tomar sobre ese circuito.


D@rkbytes dijo:


> Para lograr que el circuito funcione correctamente se deben tomar algunas consideraciones.
> 1.- *Separar la alimentación del PIC* y colocar un capacitor de 4700uF en VDD para mantener constante por algún tiempo la alimentación del mismo y así poder ejecutar las tareas de detección.
> También se puede colocar un sistema con batería recargable para mantener siempre alimentado al PIC.
> 2.- *De preferencia tomar la muestra de tensión a través de un diodo antes del filtraje del voltaje.*
> 3.- Espero que funcione.


----------

