Autor Tema: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)  (Leído 15468 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5398
    • Picmania by Redraven
En este nuevo ejemplito vamos a utilizar el circuito integrado LM35A que es capaz de servirnos una tensión de 10 mV por cada grado centígrado de temperatura a partir de 0º que nos dá correspondientemente 0V a la salida.

Datasheet del LM35A

En este caso particular hago uso del siguiente circuito conectado al PORTA del 16F628:



Como puede verse la LDR esta conectada como divisor de tensión a RA0. El LM35A está conectado a RA1. Y a RA2 y RA3 estan conectados los cursores de dos potenciómetros entre VCC y GND. Éste último, el que se conecta a RA3, lo uso para ajustar la tensión de referencia VREF para realizar la converisón Analógico-Digital de la salida del LM35A.

Como en mi habitación hay a proximadamente 23 o 24 grados centígrados por lo que el LM35A va a darme unos 230 ó 240 mV, así que he ajustado el potenciómetro R18 hasta conseguir exactamente 1V (1000 mV) en RA3, si mi Fluke no me engaña (marca exactamente 1,000 V).

Realizo una conversión AD cada vez que envío mediante la RS232 el comando "t", entonces realiza un muestreo de RA0, la LDR, y de RA1, el LM35A. A continuación  envío el resultado de nuevo al RS232.

En mi hardaware tengo también una resistencia conectada electricamente a RB5 (no aparece en el esquemático anterior) y que fisicamente esta junto al LM35A. Esto hace que al activar RB5 se caliente esta resistencia y podamos así testear cómo sube la temperatura en el mismo.

Vía RS232 puedo tambíen mandar los comandos "1" y "0" que conectan o desconectan respectivamente el calefactor al LM25A.

El programa CCS C (v.2.150) queda así:

Codigo:


#include <16f876a.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=4000000)
#use standard_io(b)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

int  adc_luminosidad=0x00;
int  adc_temperatura=0x00;
int  grados_temperatura=0;
char Keypress=" ";

#int_rda
void rda_isr() {
   Keypress=0x00;
   if(kbhit()){
      Keypress=getc();
   }
}

void toma_adc_y_transmite(void){

   // Lectura del canal 0 -> AN0 LDR
   set_adc_channel(0);
   delay_ms(1);
   adc_luminosidad=read_adc();
   delay_ms(1);
   
   // Lectura del canal 1 -> AN1 LM35a
   set_adc_channel(1);
   delay_ms(1);
   adc_temperatura=read_adc();
   delay_ms(1);

   grados_temperatura = (int) ((adc_temperatura * 391) / 1000);

   printf(" L = %u T = %u (adc= %u)
",adc_luminosidad,grados_temperatura,adc_temperatura );
}

void main() {

   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(RA0_RA1_ANALOG_RA3_REF);
   output_low(PIN_B5);

   enable_interrupts(int_rda);
   enable_interrupts(global);

   printf("
 AD - LM35a - Monitor

" );

   do {

      if(Keypress!=0x00){

         switch(Keypress){
            case "t": toma_adc_y_transmite();
                      break;
            case "0": output_low(PIN_B5);
                      printf(" 0 - Calentador OFF
" );
                      break;
            case "1": output_high(PIN_B5);
                      printf(" 1 - Calentador ON
" );
                      break;
         }
         Keypress=0x00;
      }
   } while (TRUE);

}




Y por fín los resultados de la correspondiente prueba en mi terminal serie sobre el PC:



T=24 significa que tengo 24ºC en el LM35A,
lo que corresponde a un valor AD adc=62.
Lo que es compatible con VREF - > 1000 mv / 256 = 3,90625 mV por cada Ud AD.
Luego 62 * 3,90625 mV = 242,1875 mV en RA1 y como tenemos 10 mv por grado
Entonces 242,1875 mV / 10 mVº = 24,21875. CSQD (Como Se Quería Demostrar)

Y eso es todo (por ahora).  Rebotado



Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5398
    • Picmania by Redraven
RE: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #1 en: 28 de Diciembre de 2005, 15:41:00 »
FlashFlashFlashFlashFlash

Una perfecta aplicación de esta técnica la podéis encontrar en el bonito e interesante proyecto  Termómetro Digital realizado por nuestro amigo Radon y aplicado al control de Temperatura de un Acuario (el de su hermana).

FlashFlashFlashFlashFlash



Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado RaDoN

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 1498
RE: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #2 en: 28 de Diciembre de 2005, 15:48:00 »
Sonrisa GiganteSonrisa GiganteSonrisa GiganteGiño

Por cierto, te aconsejo que te pidas algún DS1624, que es un termómetro digital por i2c, con una precisión impresionante (0.013º o cosa asíGiño. Yo subiria la resistencia del divisor de tensión con la LDR a la de 10k.

Bonito terminal Giño
Si juegas contra el mejor, pierdes como los demás.

Desconectado kain589

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 324
RE: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #3 en: 23 de Marzo de 2006, 10:12:00 »
Estan muy bien los ejemplos para C, ayer consegui hacer mi primera comunicacion rs232, asi que ahora es hora de comenzar a realizar mas pruebas. Me preguntaba si en la siguiente linea (int) lo que hace es covertir el dato a entero, creo que sera lo que hace pero no estoy seguro

Escrito originalmente por RedPic


   grados_temperatura = (int) ((adc_temperatura * 391) / 1000);


Saludos desde Córdoba, españa

Desconectado gONzAO

  • PIC10
  • *
  • Mensajes: 38
RE: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #4 en: 23 de Marzo de 2006, 11:53:00 »
Pues si, tiene toda la pinta de ser un casting.

La cosa es que la variable que entra en juego en esa operación, y los números son de tipo int, entonces creo que debería ir todo correctamente.

De todas formas, todo esto de los tipos depende del compilador y de cómo esté configurado, así puede que en unos casos salte un warning, en otros un error y en otra ocasión que compile y los tres ser correctos.

Un saludo

gONzAO

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5398
    • Picmania by Redraven
RE: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #5 en: 23 de Marzo de 2006, 14:20:00 »
Exacto kain589. estoy forzando al acompilador a guardar el resultado en una
variable de tipo int (8 bits). Así evito el tener que dejar al compilador haciendo
conversiones implicitas, me gusta declarar exactamente lo que estoy haciendo.

La variables son todas de tipo int pero el operador / puede darme un resultado
int (8 bits) long (16 bits) o float (32 bits) y yo quiero que sea exactamente int (8 bits).



Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado naho

  • PIC12
  • **
  • Mensajes: 62
Re: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. A
« Respuesta #6 en: 07 de Abril de 2007, 13:37:37 »
Hola RedPic:

Estaba mirando tu código, y hay algo que no entiendo.
¿Porque haces esto?

Código: [Seleccionar]
((adc_temperatura * 391) / 1000)
¿De dónde salen el 391 y 1000?


Como siempre Muchas gracias.



Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5398
    • Picmania by Redraven
Re: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #7 en: 07 de Abril de 2007, 18:58:28 »
Hola naho.

Esto viene directamente de las condiciones físicas que rodean al ejemplito en cuestión, y al que el fuente de mi programa debe adaptarse para poder dar un resultado fiable. Todo está en el texto que acompaña a dicho fuente.

Me explico:

He ajustado VREF para poder realizar una conversión AD de sólo 1000 milivoltios (1 voltio) en 256 (8 bits) partes.

Luego 1000 / 256 = 3,90625 milivoltios por cada unidad en la conversión.

Así si leo, como pone mi ejemplo, una conversión de 62 significa que 62 * 3,90625 = 242,1875 milivoltios en el LM35A.

Y como éste me entrega 10 milivoltios por Grado Centígrado puedo concluir que tengo una temperatura de 24,21875 grados centígrados.

El fuente pone grados_temperatura = (int) ((adc_temperatura * 391) / 1000);   porque hace todos estos cálculos de una sola tacada.

Podría haber escrito:

grados_temperatura = (int) ((adc_temperatura * 3,90625) / 10); y todo sería igual ya que 62 * 3,90625 / 10 es 24,21875

Pero al PIC no le sientan bien los flotantes así que si multiplicaba por 100 tanto el numerador como el denominador daría el mismo cociente:

grados_temperatura = (int) ((adc_temperatura * 3,90625 * 100) / 10 * 100);

Y esto es lo mismo que escribir:

grados_temperatura = (int) ((adc_temperatura * 390,625) / 1000);

Redondeando a la unidad superior ese extraño 390,625 queda:

grados_temperatura = (int) ((adc_temperatura * 391) / 1000);

O sea que todo es un asunto de manejar los mismos datos pero escritos de otra forma.

Matemáticas de primero.

Un saludo.
« Última modificación: 07 de Abril de 2007, 19:00:40 por RedPic »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado naho

  • PIC12
  • **
  • Mensajes: 62
Re: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. A
« Respuesta #8 en: 09 de Abril de 2007, 13:46:07 »

Claro como el agua!   :mrgreen:

Muchísimas gracias. 


Desconectado DarkVect

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 302
Re: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #9 en: 13 de Abril de 2007, 10:29:42 »
RedPic tengo una duda/problema con la parte: grados_temperatura = (int) ((adc_temperatura * 391) / 1000);

Tengo un programa que lee la frecuencia con que se cierra un contacto y hago: speed=(int) ((contact_close*100)/120));

En un LCD muestro ambas variables y mientras contact_close da el valor correcto, en speed veo o un 1 o un 0. Ambas variables están declaradas coo int y se muestran en el lcd con %u. Los valores que puede tomar close_contact van de 0 a unos 250.

Cuándo dices que la instrucción se ejecuta de una tacada, significa que no guarda valores intermedios en grados_temperatura, no? Por lo que aunque haya algún instante en que el valor intermedio sea superior a 255 no debería pasar nada, no?

Gracias y un saludo!!

Desconectado DarkVect

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 302
Re: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #10 en: 16 de Abril de 2007, 07:26:56 »
Tengo mi fórmula funcionando pero a costa de declarar contact_close como int16. Speed es un int, como tiene que ser, ya que el resultado global de la fórmula cabe en un entero y la función (int) obliga a que sea entero. Pero el paso intermedio no funciona bien. Si declaro contact_close como int el resultado de la multiplicación es lo que me paso de 256, por ejemplo:

Si contact_close vale 3, al multiplicar por 100 son 300, pués es como si el resultado fuese 44 (300-256) y al dividirlo por 120 y hacer (int) da 0. Todo esto lo he probado paso a paso mirando los valores intermedios. En cambio si declaro la varibale como int16 todo funciona ok.

No lo entiendo.

Desconectado Oscarinv

  • PIC10
  • *
  • Mensajes: 8
Re: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #11 en: 14 de Abril de 2009, 20:35:21 »
Bueno, primero que nada estoy comenzando en esto de los microcontroladores y tengo varias dudas.
1.- ¿Qué es eso del 0x00 y 0? valores o espacios de memoria.
int  adc_luminosidad=0x00;
int  adc_temperatura=0x00;
int  grados_temperatura=0;

2.- ¿El voltaje de referencia para que me sirve?, es muy necesario.

3.- ¿De donde sale el 256?

"Lo que es compatible con VREF - > 1000 mv / 256 = 3,90625 mV por cada Ud AD."

3.- Finalmente mi programa en C,

#include <16F877A.H>
#fuses XT, NOWDT, NOPUT, NOLVP, NOBROWNOUT, NOWRT, NOPROTECT
#use delay (clock = 4000000)
#include <lcd.c>

void main(){
set_tris_a(0xff);
setup_adc(adc_clock_internal);
setup_adc_ports(AN0);
set_adc_channel(0);
lcd_init();
printf(lcd_putc, "Temperatura: %d",read_adc()*2);
}

Funciona, pero a partir de temperaturas de 60° C tiene un error de unos 2°C, y de la lectura del LM35 me sale un valor de la mitad del valor real, es por
eso que multiplico x 2 (read_adc()*2), no se por que sale así.

Se que son muchas preguntas, espero que me respondan, mientras tanto seguire investigando.

Desconectado Cryn

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4169
Re: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #12 en: 15 de Abril de 2009, 12:01:05 »
Citar
1.- ¿Qué es eso del 0x00 y 0? valores o espacios de memoria.
int  adc_luminosidad=0x00;
int  adc_temperatura=0x00;
int  grados_temperatura=0;
el 0x00 esta escrito en hexadecimal y el 0 en decimal, simplemente es la notación que utiliza el compilador para las distintas bases, tenemos también binario 0b11100010 y octal que si no me equivoco es 0176, un "0" por delante


Citar
2.- ¿El voltaje de referencia para que me sirve?, es muy necesario.
normalmente el micro puede reconocer valores analógicos de 0 a 5 Vdc, y en este caso el sensor de temperatura no llega a dar tensiones por arriba de 1000mv al parecer, por tanto si no se usa una tensión de referencia se esta desperdiciando la resolución y tendiendo a cometer un error más grande en la conversión. Colocando una tensión de referencia por ejm a 1V quiere decir que cuando se lee 1V en el canal el resultado de la conversión a 8 bits por ejemplo será 255. En el caso de no tener tensión de referencia el valor de 255 será leído cuando se tenga 5V en el canal analógico. En resumen la tensión de referencia sirve para ampliar nuestra resolución del conversor A/D cuando medimos tensiones más bajas de 5V. En si creo que el mínimo valor de referencia son 2V, para eso hay qeu ver la hoja de datos del micro


Citar
3.- ¿De donde sale el 256?

"Lo que es compatible con VREF - > 1000 mv / 256 = 3,90625 mV por cada Ud AD."
256 son las combinaciones posibles de los bits de un número de 8bits o 1byte, viene de hacer
2^8=256
donde 2 es la base del numero y 8 los bits que tiene. Los registros de los micros de la familia 16f 18f son de 8bits o 1byte cada uno.
Estas combinaciones son 00000000, 00000001, 00000010...... 11111110, 11111111 en total son 256 combinaciones posibles de 8 1's y/o 0's


Citar
3.- Finalmente mi programa en C,
#include <16F877A.H>
#fuses XT, NOWDT, NOPUT, NOLVP, NOBROWNOUT, NOWRT, NOPROTECT
#use delay (clock = 4000000)
#include <lcd.c>

void main(){
set_tris_a(0xff);
setup_adc(adc_clock_internal);
setup_adc_ports(AN0);
set_adc_channel(0);
lcd_init();
printf(lcd_putc, "Temperatura: %d",read_adc()*2);
}

Funciona, pero a partir de temperaturas de 60° C tiene un error de unos 2°C, y de la lectura del LM35 me sale un valor de la mitad del valor real, es por
eso que multiplico x 2 (read_adc()*2), no se por que sale así.

Se que son muchas preguntas, espero que me respondan, mientras tanto seguire investigando.
quizá pueda haber un problema en los conceptos que desconocías, ahora sabiendo quizá puedas corregirlo, inténtalo.

Un saludo
« Última modificación: 15 de Abril de 2009, 12:05:54 por Cryn »
.

Desconectado Oscarinv

  • PIC10
  • *
  • Mensajes: 8
Re: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #13 en: 15 de Abril de 2009, 20:51:02 »
Muchas gracias Cryn, solo una cosa, creo que no me dí a entender bien en la primera pregunta:

1.- ¿Qué es eso del 0x00 y 0? valores o espacios de memoria.
int  adc_luminosidad=0x00;
int  adc_temperatura=0x00;
int  grados_temperatura=0;

Se que son valores en hexadecimal y decimal, pero estos valores de 0 se le asignan a las variables int adc_luminosidad, int adc_temperatura, ... ó son espacios de memoria donde se guardan estas variables.

y  la 3, si alguien la sabe espero que me respondan.

Una cosa más, intente esta formula:

Código: [Seleccionar]
  grados_temperatura = (int) ((adc_temperatura * 391) / 1000);
pero no me sale el valor correcto.

Desconectado kcire

  • Colaborador
  • PIC12
  • *****
  • Mensajes: 84
Re: Ejemplito 16F876A: Temperatura y Luminosidad con un LM35a y una LDR (Conv. AD)
« Respuesta #14 en: 16 de Abril de 2009, 02:52:57 »
1.- ¿Qué es eso del 0x00 y 0? valores o espacios de memoria.
int  adc_luminosidad=0x00;
int  adc_temperatura=0x00;
int  grados_temperatura=0;

Se que son valores en hexadecimal y decimal, pero estos valores de 0 se le asignan a las variables int adc_luminosidad, int adc_temperatura, ... ó son espacios de memoria donde se guardan estas variables.

Pues estas variables (adc_luminosidad,adc_temperatura, grados_temperatura) globales de tipo enteras les asigna un 0 al inicio o comienzo del programa, sopongo que preveyendo valores ideseados.

Saludos..... Erick
"La imaginación es más rica que el lenguaje... sugiere con palabras, la imaginación podrá hacer el resto."


 

anything