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

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 :D .Ojala me puedan ayudar, les agradezco de antemano Saludos !!! .Esta es parte del codigo donde grabo uno de los parametros en la memoria
Código:
     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);
  
   }
 
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.
Código:
   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.
Código:
   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.
 
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 !!!!!!!
 
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
 
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.
 
Última edición:
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 !!!
 
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 !!!
Código:
#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 );
   
   }
   }
  
  }
 
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.
 

Adjuntos

  • 16F876A Int16 EEPROM RW.rar
    47.6 KB · Visitas: 90
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
Código:
////////////////////////////////////////////////////////////////////////////////
////                          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 !!!!!
 
Última edición:
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
 
¿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.
¿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.
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.
 
Última edición:
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 !!!
 
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!!!!
 
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.
 
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.

Código:
# 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.
Código:
#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)
 

Adjuntos

  • archivos.rar
    38 KB · Visitas: 19
Última edición por un moderador:
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.
 
Última edición:
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
 
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.
 

Adjuntos

  • Esquema Control Incubadora.JPG
    Esquema Control Incubadora.JPG
    111.1 KB · Visitas: 39
  • 16F877A Control de incubadora.rar
    138.6 KB · Visitas: 49
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.

Entiendo que requieres de más precisión, pero modificando este programa tal vez lo puedas lograr.

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
 
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.
#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.
#define t_min_decr pin_b7 aquí define la entrada haber omitido y solo preguntar luego 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
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.
{
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????
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 :cool:
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.
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?

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

write_eeprom(0,temp_min); ¿Está bien esto?
Eso también será parte de las modificaciones que tendrás que realizar.
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.
--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

write_eeprom(0,temp_min); está bien esto
Eso también será parte de las modificaciones que tendrás que realizar.
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.
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.
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.
 
Atrás
Arriba