No hace falta irse lejos para encontrarse con algún que otro automatismo, si buscamos en casa tenemos un montón de ellos. Entre ellos, tenemos uno que poco a poco ha ido cobrando importancia, hasta el punto en el que ya es necesario disponer de uno si se quiere controlar de manera precisa la calefacción; se trata del termostato.
En esta entrada voy a presentar un proyecto de termostato digital, basado en lógica programada (microcontroladores PIC). Constará a su vez de una pantalla LCD y una serie de botones para poder establecer comunicación con el usuario.
El funcionamiento básico de un termostato es el siguiente: Cuando la temperatura de la estancia es igual o superior a la temperatura a la que nosotros queremos que esté, entonces se mantendrá apagada la calefacción; en cambio, si la temperatura de la estancia está por debajo de la que nosotros especifiquemos, entonces se encenderá la calefacción con el objetivo de llegar hasta esa temperatura.
Por supuesto necesitaremos medir la temperatura de la estancia. Para ello vamos a utilizar un sensor de temperatura, el DS1820 (DataSheet). Se trata de un sensor de temperatura de alta precisión digital, es decir, dentro incorpora un sensor analógico de temperatura, un ADC y todo lo necesario para codificar los datos digitales. De esta manera vamos a poder comunicar el sensor directamente con el PIC. Vamos a necesitar también conmutar la calefacción desde el PIC, para ello se ha incorporado un relé de estado sólido, formado por un triac y un opto-acoplador con foto-triac que nos permitirán conmutar una electro-válvula a 230V, permitiendo o no el paso del agua caliente de la calefacción.
Este proyecto gira en torno al microcontrolador PIC16F628A (DataSheet). Veremos a continuación las diferentes partes de las que se compone éste termostato:
- El sensor:
El sensor de temperatura DS1820 de la empresa DALLAS Semiconductor, se comunica de manera digital a través de un protocolo de comunicación serial diseñado por la misma empresa. Este protocolo, conocido como 1-wire, consiste en enviar los datos a través de una única línea con resistencia Pullup (ya que se utilizan las salidas en colector abierto), en la cual pueden existir varios dispositivos esclavos y un único dispositivo maestro. Todos los dispositivos deberán compartir la referencia de tierra para poder establecer las comunicaciones. Existe en CCS una librería que nos permite usar este protocolo de comunicación; podemos descargarla en este enlace 1wire.c.
El sensor se conectará al microcontrolador de la siguiente manera:
Ahora veremos la sección de código que necesitamos para poder leer la temperatura del sensor:
#include <16f628a.h>
[...]
#define ONE_WIRE_PIN pin_b0
#include "1wire.c"
[...]
int8 tp1,tp2;
signed int16 temp;
[...]
onewire_reset();
onewire_write(0xCC);
onewire_write(0x44);
while(!busy) busy=onewire_read();
onewire_reset();
onewire_write(0xCC);
onewire_write(0xBE);
tp1=onewire_read();
tp2=onewire_read();
temp=make16(tp2,tp1)/2;
[...]
Este fragmento de código, hace uso de la librería 1wire.c para poder leer 2 bytes del sensor. Estos dos bytes se unen en un único número de 16 bits (con la función make16()), y se obtiene la temperatura sin punto decimal en la variable temp. Es decir, si hacen 21,5 ºC, en la variable temp se guardará el número 215. De esta manera, podemos obtener el valor de temperatura en una variable de 16 bits.
- La pantalla LCD:
Utilizaremos una pantalla LCD de 16 caracteres por 2 líneas y luz de fondo para poder representar los valores de temperatura medida y temperatura establecida. Con la ayuda de un potenciometro, podremos regular el contraste de la pantalla para obtener el mejor resultado de claridad.
Conectaremos la pantalla LCD al microcontrolador de la siguiente manera:
Utilizaremos una librería de CCS para poder controlar la pantalla LCD. Dicha librería se llama flex_lcd_2.c (disponible en este enlace flex_lcd_2.c). La sección de código que necesitamos para poder manejar el display LCD es el siguiente:
#include <16f628a.h>
[...]
#define LCD_DB4 PIN_B7
#define LCD_DB5 PIN_B6
#define LCD_DB6 PIN_B5
#define LCD_DB7 PIN_B4
#define LCD_RS PIN_A1
#define LCD_E PIN_A0
#define bklight pin_a2
#include "flex_lcd_2.c"
[...]
printf(lcd_putc," .... ");
[...]
output_high(bklight);
[...]
output_low(bklight);
[...]
output_high(bklight);
[...]
output_low(bklight);
[...]
Es muy importante definir los pines donde se conectará la LCD antes de incluir la librería para que dichas definiciones tengan efecto sobre la misma. Se podrá controlar el encendido de la luz de fondo (bklight) mediante el uso de funciones de salida output_high() y output_low().
- El relé de estado sólido:
Necesitaremos también un circuito que nos permita controlar el encendido y apagado de una carga a 230V AC desde el microcontrolador. Para ello, utilizaremos un relé de estado sólido formado por un opto-acoplador MOC3022 (DataSheet), un triac de potencia BT137 (DataSheet) y un par de resistencias de 470Ω ¼w:
A través de una resistencia limitadora de corriente, podremos controlar desde el microcontrolador el encendido y apagado del LED del opto-acoplador el cual activará o no el foto-triac de su interior, polarizando o no el terminal de puerta del triac BT137. El triac conmutará la carga de 230V AC:
#include <16f628a.h>
[...]
#define rele pin_a3
[...]
output_high(rele);
[...]
output_low(rele);
[...]
output_high(rele);
[...]
output_low(rele);
[...]
- Los botones:
Para poder establecer la temperatura del termostato, será necesario incorporar algún elemento de entrada (hombre → maquina). Para ello utilizaremos tres pulsadores. Estos tres pulsadores los conectaremos en Push-Down y no necesitaremos resistencias de Pull-Up, ya que los conectaremos al puerto B del microcontrolador, el cual dispone internamente de estas resistencias:
Los pulsadores marcados como + y - , se utilizarán para subir y bajar la temperatura respectivamente. El pulsador marcado como M , se ha añadido para tener un botón auxiliar; por ejemplo, para apagar la calefacción independientemente de la temperatura. Definiremos los pulsadores al principio del código:
#include <16f628a.h>
[...]
#define onoff pin_b1#define rmv pin_b2
#define add pin_b3
[...]
port_b_pullups(true);
[...]
int1 x=!input(add);
int1 y=!input(rmv);
int1 z=!input(onoff);
[...]
- Fuente de alimentación:
Para alimentar el termostato, añadiremos un conector para poder alimentarlo desde una fuente DC de hasta 24V (como por ejemplo un simple adaptador de enchufe). Un circuito integrado LM78L05 (DataSheet), se encargará de obtener los 5V que necesita el sistema para funcionar. Un condensador electrolítico de 470µF, filtrara los 5V de la salida del integrado:
Al unir todas las partes que hemos visto anteriormente, queda como resultado el siguiente circuito:
Procederemos a escribir el código para el termostato:
- Fuente de alimentación:
Para alimentar el termostato, añadiremos un conector para poder alimentarlo desde una fuente DC de hasta 24V (como por ejemplo un simple adaptador de enchufe). Un circuito integrado LM78L05 (DataSheet), se encargará de obtener los 5V que necesita el sistema para funcionar. Un condensador electrolítico de 470µF, filtrara los 5V de la salida del integrado:
Al unir todas las partes que hemos visto anteriormente, queda como resultado el siguiente circuito:
Procederemos a escribir el código para el termostato:
//
// TERMOSTATO DIGITAL
//
// Diseñado para controlar el
// sistema de calefacción de una
// vivienda. Utiliza un sensor
// de temperatura para determinar
// la temperatura del ambiente
// y controlar una electro-valvula
// a 230V AC que permita el paso
// de agua para la calefacción.
// Mediante unos pulsadores se
// puede establecer la temperatura
// del termostato, además de
// mostrar los datos en una pantalla
// LCD.
//
// PIC16F628A
//
// DS1820
// PANTALLA LCD
//
// Copyright © 2015 Aaron G.
// All rights reserved.
#include <16f628a.h>
#fuses intrc_io,nomclr,put,nobrownout,nolvp,noprotect,nocpd
#use delay(int=4000000)
#define ONE_WIRE_PIN pin_b0
#define LCD_DB4 pin_b7
#define LCD_DB5 pin_b6
#define LCD_DB6 pin_b5
#define LCD_DB7 pin_b4
#define LCD_RS pin_a1
#define LCD_E pin_a0
#define rele pin_a3
#define bklight pin_a2
#define onoff pin_b1
#define rmv pin_b2
#define add pin_b3
#include "1wire.c"
#include "flex_lcd_2.c"
int1 sleeptermo=false; // Flag para poner el termostato en modo sleep
int8 j=0,busy=0,tp1,tp2; // Variables globales de 8 bits
unsigned int16 temp,tset=200,pret; // Variables globales de 16 bits
void Print_lcd(void){ // Print_lcd(): función para imprimir los datos en la
lcd_putc("\f"); // pantalla LCD
lcd_gotoxy(1,1);
if(!((temp/100)%10)) printf(lcd_putc,"Temp %lu.%lu%cC",((temp/10)%10),(temp%10),223);
else printf(lcd_putc,"Temp %lu%lu.%lu%cC",((temp/100)%10),((temp/10)%10),(temp%10),223);
if(tset>temp&&!sleeptermo) printf(lcd_putc," ON");
else printf(lcd_putc," OFF");
lcd_putc("\n");
if(!sleeptermo){
printf(lcd_putc,"Set %lu%lu.%lu%cC",((tset/100)%10),((tset/10)%10),(tset%10),223);
if(tset==100) printf(lcd_putc," MIN");
if(tset==300) printf(lcd_putc," MAX");
}
else printf(lcd_putc," TERMO OFF ");
}
void Read_temp(void){ // Read_temp(): función para leer la temperatura
onewire_reset(); // del sensor. Se utilizan unos condicionales para
onewire_write(0xCC); // hacer que la resolución de la temperatura sea
onewire_write(0x44); // de 0.5 ºC. Se ejecuta la función Print_lcd()
while(busy==0) busy=onewire_read(); // cuando se produce un cambio en la temperatura
onewire_reset();
onewire_write(0xCC);
onewire_write(0xBE);
tp1=onewire_read();
tp2=onewire_read();
temp=make16(tp2,tp1)/2;
if(temp%10>=3&&temp%10<=7) temp=(((temp/100)%10)*100)+(((temp/10)%10)*10)+5;
if(temp%10<3) temp=(((temp/100)%10)*100)+(((temp/10)%10)*10);
if(temp%10>7) temp=(((temp/100)%10)*100)+((((temp/10)%10)+1)*10);
if(temp!=pret){
Print_lcd();
pret=temp;
}
delay_ms(146);
}
void Inicio(void){ // Inicio(): Muestra un mensaje en pantalla
output_high(bklight); // al inicio del programa
lcd_putc("\f");
printf(lcd_putc,"Termostato PIC16");
lcd_gotoxy(4,2);
printf(lcd_putc,"By Aaron G.");
delay_ms(4500);
Read_temp();
Print_lcd();
}
void Set_temp(void){ // Set_temp(): función destinada a leer el
if(!input(add)){ // estado de los pulsadores y aumentar la
j=0; // temperatura establecida. También pone
if(tset<300){ // a 0 la variable j para encender la luz de
tset=tset+5; // fondo de la LCD
Print_lcd();
}
}
if(!input(rmv)){
j=0;
if(tset>100){
tset=tset-5;
Print_lcd();
}
}
}
void Termo(void){ // Termo(): conmuta el rele de estado sólido
if(tset>temp) output_high(rele); // para encender o apagar la calefacción
else output_low(rele);
}
void Back_light(void){ // Back_light(): controla el encendido de la luz
if(j!=30){ // de fondo de la pantalla LCD
output_high(bklight);
j++;
if(j==30) output_low(bklight);
}
}
void main(void){ // Programa principal
delay_ms(10);
set_tris_a(0x00);
set_tris_b(0x0F);
lcd_init();
delay_ms(10);
port_b_pullups(true);
Inicio();
while(1){ // while(1): bucle infinito
while(!sleeptermo){
Read_temp();
delay_ms(1);
Set_temp();
delay_ms(1);
Termo();
delay_ms(1);
Back_light();
delay_ms(1);
if(!input(onoff)){
j=0;
output_high(bklight);
delay_ms(1700);
if(!input(onoff)){
sleeptermo=true;
output_low(rele);
Print_lcd();
while(!input(onoff));
}
}
}
Read_temp();
delay_ms(4);
Back_light();
if(!input(add)||!input(rmv)) j=0;
if(!input(onoff)){
sleeptermo=false;
j=0;
Print_lcd();
}
}
}
// TERMOSTATO DIGITAL
//
// Diseñado para controlar el
// sistema de calefacción de una
// vivienda. Utiliza un sensor
// de temperatura para determinar
// la temperatura del ambiente
// y controlar una electro-valvula
// a 230V AC que permita el paso
// de agua para la calefacción.
// Mediante unos pulsadores se
// puede establecer la temperatura
// del termostato, además de
// mostrar los datos en una pantalla
// LCD.
//
// PIC16F628A
//
// DS1820
// PANTALLA LCD
//
// Copyright © 2015 Aaron G.
// All rights reserved.
#include <16f628a.h>
#fuses intrc_io,nomclr,put,nobrownout,nolvp,noprotect,nocpd
#use delay(int=4000000)
#define ONE_WIRE_PIN pin_b0
#define LCD_DB4 pin_b7
#define LCD_DB5 pin_b6
#define LCD_DB6 pin_b5
#define LCD_DB7 pin_b4
#define LCD_RS pin_a1
#define LCD_E pin_a0
#define rele pin_a3
#define bklight pin_a2
#define onoff pin_b1
#define rmv pin_b2
#define add pin_b3
#include "1wire.c"
#include "flex_lcd_2.c"
int1 sleeptermo=false; // Flag para poner el termostato en modo sleep
int8 j=0,busy=0,tp1,tp2; // Variables globales de 8 bits
unsigned int16 temp,tset=200,pret; // Variables globales de 16 bits
void Print_lcd(void){ // Print_lcd(): función para imprimir los datos en la
lcd_putc("\f"); // pantalla LCD
lcd_gotoxy(1,1);
if(!((temp/100)%10)) printf(lcd_putc,"Temp %lu.%lu%cC",((temp/10)%10),(temp%10),223);
else printf(lcd_putc,"Temp %lu%lu.%lu%cC",((temp/100)%10),((temp/10)%10),(temp%10),223);
if(tset>temp&&!sleeptermo) printf(lcd_putc," ON");
else printf(lcd_putc," OFF");
lcd_putc("\n");
if(!sleeptermo){
printf(lcd_putc,"Set %lu%lu.%lu%cC",((tset/100)%10),((tset/10)%10),(tset%10),223);
if(tset==100) printf(lcd_putc," MIN");
if(tset==300) printf(lcd_putc," MAX");
}
else printf(lcd_putc," TERMO OFF ");
}
void Read_temp(void){ // Read_temp(): función para leer la temperatura
onewire_reset(); // del sensor. Se utilizan unos condicionales para
onewire_write(0xCC); // hacer que la resolución de la temperatura sea
onewire_write(0x44); // de 0.5 ºC. Se ejecuta la función Print_lcd()
while(busy==0) busy=onewire_read(); // cuando se produce un cambio en la temperatura
onewire_reset();
onewire_write(0xCC);
onewire_write(0xBE);
tp1=onewire_read();
tp2=onewire_read();
temp=make16(tp2,tp1)/2;
if(temp%10>=3&&temp%10<=7) temp=(((temp/100)%10)*100)+(((temp/10)%10)*10)+5;
if(temp%10<3) temp=(((temp/100)%10)*100)+(((temp/10)%10)*10);
if(temp%10>7) temp=(((temp/100)%10)*100)+((((temp/10)%10)+1)*10);
if(temp!=pret){
Print_lcd();
pret=temp;
}
delay_ms(146);
}
void Inicio(void){ // Inicio(): Muestra un mensaje en pantalla
output_high(bklight); // al inicio del programa
lcd_putc("\f");
printf(lcd_putc,"Termostato PIC16");
lcd_gotoxy(4,2);
printf(lcd_putc,"By Aaron G.");
delay_ms(4500);
Read_temp();
Print_lcd();
}
void Set_temp(void){ // Set_temp(): función destinada a leer el
if(!input(add)){ // estado de los pulsadores y aumentar la
j=0; // temperatura establecida. También pone
if(tset<300){ // a 0 la variable j para encender la luz de
tset=tset+5; // fondo de la LCD
Print_lcd();
}
}
if(!input(rmv)){
j=0;
if(tset>100){
tset=tset-5;
Print_lcd();
}
}
}
void Termo(void){ // Termo(): conmuta el rele de estado sólido
if(tset>temp) output_high(rele); // para encender o apagar la calefacción
else output_low(rele);
}
void Back_light(void){ // Back_light(): controla el encendido de la luz
if(j!=30){ // de fondo de la pantalla LCD
output_high(bklight);
j++;
if(j==30) output_low(bklight);
}
}
void main(void){ // Programa principal
delay_ms(10);
set_tris_a(0x00);
set_tris_b(0x0F);
lcd_init();
delay_ms(10);
port_b_pullups(true);
Inicio();
while(1){ // while(1): bucle infinito
while(!sleeptermo){
Read_temp();
delay_ms(1);
Set_temp();
delay_ms(1);
Termo();
delay_ms(1);
Back_light();
delay_ms(1);
if(!input(onoff)){
j=0;
output_high(bklight);
delay_ms(1700);
if(!input(onoff)){
sleeptermo=true;
output_low(rele);
Print_lcd();
while(!input(onoff));
}
}
}
Read_temp();
delay_ms(4);
Back_light();
if(!input(add)||!input(rmv)) j=0;
if(!input(onoff)){
sleeptermo=false;
j=0;
Print_lcd();
}
}
}
Hola me llamo duniesky espero no molestar pues quiero hacer este proyecto pero no tengo la pantalla lcd lo que tengo es display 7 segmentos soy cubano y los componentes electrónicos se dificultan bastante y el poder conectarme a internet también es un tanto difícil, por lo que si pudiera y quisiera ayudarme se lo agradecería necesito este mismo proyecto para display 7 segmentos y el .hex y si no es mucho pedir una explicación de como programar el ds1820 como calcular el valor de temperatura desde ya muchas gracias y mil disculpa si molesto. Mi correo electrónico es dunieskydj@gmail.com
ResponderEliminarGracias por publicar, buen aporte para los que necesitamos conocer programación
ResponderEliminarhola me pudiera mandar las librerías pues no las puedo descargar me dice q no existe gracias mi correo
ResponderEliminardunieskydj@gmail.com