# Control de temperatura por pic para servidores



## Insane (Nov 3, 2005)

Hola,

La idea era armar un sistema que con un par de sensores de temperatura pueda activar uno o mas ventiladores como para mantener una temperatura constante. El objetivo es usarlo para mantener el/los servidor en un lugar (mueble) cerrado con sus sistemas de ventilacion pero que se pongan en funcionamiento bajo ciertas condiciones, para que no esten constantemente funcionando y hagan mucho ruido.

Tambien que cense el cooler del micro y de la fuente para que corte la alimentacion del servidor si alguno deja de funcionar antes de que algo se cocine.

Es bastante, pero creo que con sentarse un buen rato se puede hacer, pero para que reinventar la polvora? si alguien tiene algo que haga esto o parecido estaria muy agradecido si lo comparte.

Saludos a todos y gracias por su tiempo

Insane


----------



## maunix (Nov 8, 2005)

Insane dijo:
			
		

> Hola,
> 
> El objetivo es usarlo para mantener el/los servidor en un lugar (mueble) cerrado con sus sistemas de ventilacion pero que se pongan en funcionamiento bajo ciertas condiciones, para que no esten constantemente funcionando y hagan mucho ruido.


Ok, suena razonable, aunque un A/C con control de temperatura hace esto 'solo' y es muy buen sistema de enfriamiento.  Si realmente hace calor, un ventilador no solucionará nada solo retrasará lo inevitable.  



> Tambien que cense el cooler del micro y de la fuente para que corte la alimentacion del servidor si alguno deja de funcionar antes de que algo se cocine.



Yo no haría esto.  Si hablamos de un servidor que tenga un sistema operativo que tenga power managment inteligente, yo activaría el botón de shutdown o de hibernación.  Luego de un par de minutos, sí apagaría la fuente (tienes que pensar como reencenderla).

Es muy peligroso para tus datos que apagues el servidor asi sin previo aviso al software corriendo en el mismo.  Muchos equipos nuevos lleva un software de monitoreo que hace esto automáticamente



> Es bastante, pero creo que con sentarse un buen rato se puede hacer, pero para que reinventar la polvora? si alguien tiene algo que haga esto o parecido estaria muy agradecido si lo comparte.
> 
> Insane



MM, no tengo nada hecho así pero creo que no es dificil.  Tienes que lidiar con electrónica de potencia para manejar a los ventiladores o simplificarte la vida utilizando reles de potencia manejados con algún transistor que active a los mismos desde un PIC.

Filtra muy bien tu fuente hacia el PIC, una vez que enciendas los ventiladores (que son inherentemente inductores) el chispazo que ocurra podría generar un ruido eléctrico importante que podría afectar a tu electrónica si no está bien filtrada la fuente.

Otro consejo es que sensores utilizar!  Es muy simple interfacear un sensor tipo NTC con un microcontrolador con un A/D.  Aunque debieras relevar con un termometro su temperatura.

Hay otros integrados que directamente te dan la temperatura en mV.  Si tienes 50 mV son 50 grados centígrados y así.  Con un operacional con ganancia de 30 o 50 por ejemplo podrías cubrir el rango de las temperaturas más comunes.


Mi consejo es que si tus servidores valen tanto utilices un Aire Acondicionado con control de temperatura, en una habitación cerrada y no húmeda.  El A/C puede bajar la temperatura ambiente, un ventilador solo hace circular el aire bajando algunos pocos grados por 'convección' pero no quita calor del ambiente (más pensando en un recinto de servidores cerrado).


----------



## Piries (Nov 8, 2005)

Hola! yo huze un proyecto muy parecido al tuyo hace tiempo, si quieres te puedo subir los esquemas y le haces las modificaciones que creas oportunas. Si te interesa solo dilo y los cuelgo.

El sistema tiene un pic 16f877 como maestro que maneja un lcd, una botonera, un zumbador y demas cosas. Este esta comunicado por I2C con un pic 16f876 esclavo que se encarga de medir temperaturas, calcular las RPM de cada ventilador y la intensidad que consumen. Para controlar los ventiladores uso un L293D. Todos los valores que recoje el esclavo son mandados al maestro y este los saca por el lcd.

Pero esto ya es soft y depende de cada uno lo que quiere que haga. Si te interesa busco los esquemas y los cuelgo.

Salu2


----------



## Marcelo (Nov 8, 2005)

Hola Piries,

A mi si me interesaría tu proyecto pero para hacer otra cosa (controlar la temperatura en un sistema de convexión por medio de un disipador/ventilador). ¿Podrías subirlo como attachment?. Por favor incluye el firmware de los PICs.

Muchas Gracias,
Marcelo.


----------



## Piries (Nov 8, 2005)

Pues sintiendolo mucho, el codigo del maestro no se donde lo tengo y el del esclavo no esta terminado del todo, falta la parte de leer los lm35 y la intensidad pero bueno, lo subo igualmente. Me dejais un rato que busque los esquemas y el codigo.


----------



## Piries (Nov 8, 2005)

Este es el codigo para el esclavo, los comentarios estan en catalan sorry pero es que me da palo traducirlos todos . Al final del programa esta escrito lo que falta por hacer.


```
////////////////////////////////modul1.c////////////////////////////////////
//    Aquest programa s'encarrega de recollir l'informaciónrmacio enviada per dos//
// sensors de temperatura i pels tach de dos ventiladors, aquesta         //
// informaciónrmacio es enviada per I2C a un altre microcontrolador que          //
// s'encarrega de mostrarla per un LCD i calcular el nivell de PWM de cada//
// ventilador depenent de la temperatura llegida pels sensors.            //
//                                                                        //
//    Els programes dels diferents moduls son exactamens iguals, l'unica  //
// cosa  que canvia es la direccio de slave.                              //
//                                                                        //
//                                  //
////////////////////////////////////////////////////////////////////////////




//  #include <lcd.c>

// defineix el protocol de comunicacions I2C en mode slave
typedef enum {NOTHING,CONTROL_READ,ADDRESS_READ, READ_COMAND_READ} I2C_STATE;
I2C_STATE fState;
//determina l'estat de la comunicació I2C
byte address, buffer [0x10];
//array am els valors que l'esclau comprateix am el mestre

// defineix la paraula de configuració del pic




/*Aquesta directiva reserva les posicions de memoria 0x1F00 fins a  0x1FFF
per tal que el programa principal no es gravi damun del registre de carrega*/


////////////////////////////////////////////////////////////////////////////
//                     Definició de variables                             //
////////////////////////////////////////////////////////////////////////////
 static long int tach1,tach2,cont1,cont2,rpm1=200,rpm2=150;
// definim com a variables glovals de 16 bit
static unsigned  int temp1=70, temp2=60, i1=0, i2=0, duty1=0, duty2=0;
////////////////////////////////////////////////////////////////////////////
//                    Definició de les funcions                           //
////////////////////////////////////////////////////////////////////////////
void inter_I2C();      // interrupcio I2C
void inter_rb();       // interrupcio per canvi d'estat RB4:RB7
void inter_timer0();   // interrupcio pel desbordament del timer0
void inicial();        // configuracio inicial del PIC
//void temp_int();       // adquirim els valors dels sensors de temperatura
void buffer_i2c();     // donem els valors dels parametres al buffer I2C
void main();           // funció principal

///////////////////////////////////////////////////////////////////////////
//   Funció d'interrupció per rebre la senyal del tach dels ventiladors  //
///////////////////////////////////////////////////////////////////////////

void inter_rb()
{
short enc1,enc2;
static short ultim_enc1=1;
static short ultim_enc2=1;
enc1=input(pin_b5);
enc2=input(pin_b6);
if(ultim_enc1 && !enc1) tach1++;     //si pasa de 1 a 0 sumem puls
if(ultim_enc2 && !enc2) tach2++;
ultim_enc1=enc1;
ultim_enc2=enc2;
}
///////////////////////////////////////////////////////////////////////////
//           Funció d'interrupció per desbordament del timer0            //
///////////////////////////////////////////////////////////////////////////

void inter_timer0()
{
static byte timer_0_count=0;
if (timer_0_count<31)timer_0_count++;
else
   {
   timer_0_count=0;
   cont1=tach1;
   cont2=tach2;
   rpm1=(cont1/4)*60;
   rpm2=(cont2/4)*60;
  //                                                        printf(lcd_putc,"\fr1=%lu r2=%lu",rpm1,rpm2);
   tach1=0;
   tach2=0;
 //  temp_int();
   }
set_timer0 (8);
}
///////////////////////////////////////////////////////////////////////////
//       Funció d'interrupció per activitat en el modul SSP (I2C)        //
///////////////////////////////////////////////////////////////////////////

void inter_i2c()
{
   byte incoming;/////es donde recibo el byte que me manda
   if (i2c_poll() == FALSE) {
      if (fState == ADDRESS_READ) {  //i2c_poll() returns false on the
         i2c_write (buffer[address]);//interupt receiving the second
         fState = NOTHING;           //command byte for random read operation
      }
   }
   else {
      incoming = i2c_read();
      if (fState == NOTHING){

         fState = CONTROL_READ;
               }
      else if (fState == CONTROL_READ) {
         address = incoming;
         fState = ADDRESS_READ;
}
      else if (fState == ADDRESS_READ) {
         buffer[address] = incoming;
         fState = NOTHING;

      }
   }
}
////////////////////////////////////////////////////////////////////////////
//               Funció de configuració inicial del PIC                   //
////////////////////////////////////////////////////////////////////////////
void inicial()
{
int i=0;
set_tris_a(0x2F);                          //port_A com a entrades
set_tris_b(0x0F);                          //RB0:RB3 sortides RB4:RB7 entrades
//set_tris_c(0x00);                          //port_C com a sortides
setup_adc_ports(AN0_AN1_AN2_AN4_VSS_VREF); //configura CAD RA3=vref
setup_adc(ADC_CLOCK_DIV_32);               //Temps de lectura del CAD
setup_timer_2(T2_DIV_BY_1,9,1);            //100khz PWM
setup_ccp1(CCP_PWM);                       //Mode PWM
setup_ccp2(CCP_PWM);                       //Mode PWM
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256); //interrupció timer cada 2 segons
set_timer0 (8);
enable_interrupts(INT_TIMER0);             //activem interrupció timer0
enable_interrupts(INT_RB);                 //activem interrupció RB
enable_interrupts(INT_SSP);                //activem interrupcio I2C
enable_interrupts(GLOBAL);                 //activem permis d'interrupcions
fState = NOTHING;
address = 0x00;                            //primera posició del buffer
for(i=0;i<0x10;i++)buffer[i]=0;            //inicialitzem array a 0
}
////////////////////////////////////////////////////////////////////////////
//    Funció per llegir els sensors de temperatura i les intencitats      //
////////////////////////////////////////////////////////////////////////////
void temp_int()
{
disable_interrupts(global);                //no es pot interompre la conversió

set_adc_channel(0);                        //preparem el canal 0
delay_ms(16);
temp1=read_adc();                          //llegim temp 1
set_adc_channel(1);                        //preparem el canal 1
delay_ms(16);                              //per carregar el c intern del cad             /// se le el voltage y sabiendo la R se
temp2=read_adc();                          //llegim temp 2                                 /// calcula la intensidad 
set_adc_channel(2);
delay_ms(16);
i1=read_adc();                             // llegim intencitat 1
set_adc_channel(4);
delay_ms(16);
i2=read_adc();                             // llegim intenciata 2
enable_interrupts(global);                 //activem interrupcions

}
///////////////////////////////////////////////////////////////////////////
//          Dades que el slave comparteix amb el master                  //
///////////////////////////////////////////////////////////////////////////
void buffer_i2c()
{
buffer[0x00]=temp1;                      //guardem temp al buffer
buffer[0x01]=temp2;
buffer[0x02]=rpm1;                       //guardem rpm al buffer
buffer[0x03]=rpm2;
buffer[0x04]=i1;                         //guardem intencitat al buffer
buffer[0x05]=i2;
duty1=buffer[0x06];                      //llegim el duty enviat pel master
duty2=buffer[0x07];
}

void main()
{
            // delay_ms(10);
inicial();                                 //configuració inicial del PIC
//                                                 lcd_init();                         // NOMES X DEBUG
   while(1)
   {
   buffer_i2c();                             //cridem a la funcio
   set_pwm1_duty(duty1);                     //actualitzem pwm1
   set_pwm2_duty(duty2);                     //actualitzem pwm2
   }
}
// EL maestro debe multiplicar por 60 los pulsos del tach del ventilador para obtener las rpm
// se ha de tratar la señal que se recive del lm35
// la intensidad se calcula de la siguiente forma: hay una resistencia en paralelo con el ventilador, sabiendo la r,
// leemos el voltage con el CAD y sacamos la intensidad. Lo otro esta probado y funciona bien.
```

Los esquemas son para el eagle.


----------



## Piries (Nov 8, 2005)

¿¿¿¿Porque no me adjunta los esquemas??? Una cosa, las variables temp 1 y temp 2 y rpm1 y rpm2 han de inicializarse a 0. Los valores que hay en em programa ahora, los puse para comprobar que se pudieran leer des del maestro sin problemas.


----------



## Insane (Nov 9, 2005)

> Tambien que cense el cooler del micro y de la fuente para que corte la alimentacion del servidor si alguno deja de funcionar antes de que algo se cocine.
> 
> 
> Yo no haría esto.  Si hablamos de un servidor que tenga un sistema operativo que tenga power managment inteligente, yo activaría el botón de shutdown o de hibernación.  Luego de un par de minutos, sí apagaría la fuente (tienes que pensar como reencenderla).



Ok la idea esta un poco mal expuesta por mi, perdon. Por supuesto que haria que la maquina se apage sola o hiberne.

El tema mas que nada es lograr una solucion economica, ya que tampoco son 20 serivdores en una habitacion, es solo una pc que queda quieta para servir a las demas maquinas.

Muchas gracias por la ayuda que es bastante mas de lo que esperaba

Saludos


----------



## Teotekaplan (Nov 20, 2005)

Buenas  Aquí me he dejado caer, aficionado y profesional de la electrónica desde hace años... algunos me conoceréis de una página muy conocida de modding.

Weno, al grano... echando un ojo por estos foros encontré este post... y me llamó muchísimo la atención el código que ha posteado Piries para el control de velocidad y temperaturas con el 16F876... weno... me ha llamado tanto la atención porque ese código lo conozco... se trata de código modificado de un proyecto realizado hace un año de un sistema de control de temperaturas para servidores que hemos desarrollado un grupo de personas y que tiene como nombre HM-Baybus.

Al margen de que me parece MUY MAL que Piries (que ya hablaré contigo en la web de modding, ejem) se te olvide citar la procedencia original de ese código e insinúes que forma parte de un proyecto tuyo, sólo entro para comentar que el proyecto completo para el sistema de control de temperaturas con pic llamado HM-Baybus puede ser descargado gratuítamente utilizando las redes P2P o enviándome un correo electrónico (o un MP) pidiéndome la memoria completa del proyecto.

Por otro lado, aprovecho para postear el código completo del módulo esclavo.


```
/***********************************************

Slave module HM-Baybus system
Manuel Díaz García
Computer Systems
European University of Madrid
September 2004

More informaciónrmation than comments in:
[url]http://www.microchip.com[/url] (for 16F876 información)
[url]http://www.ccsinformación.com[/url] (for CCS compiler información)

***********************************************/





/*Define the I2C operation mode: SLAVE=I2C slave mode,
SCL=specifies de SCL pin, SDA=specifies de SDA pin,
FAST=fast I2C especification,
FORCE_HW=Use hardware I2C functions (only if micro support)*/

/*Define the RS232 operation mode:
BAUD=Set baud rate, XMIT=Set transmit pin, RCV=Set receive pin*/


/*The fast method of doing I/O will cause the compiler to perform I/O
without programming of the direction register*/

/*Directive to reserve memory in compilation from 0x1F00 to 0x1FFF to
the bootloader code (more informaciónrmation in [url]http://www.microchipc.com[/url])*/

//Include the library with specific functions to project and 16F876


typedef enum {NOTHING,CONTROL_READ,ADDRESS_READ,READ_COMMAND_READ} I2C_STATE;
byte slaveinformacións[0x8];

short update = 1;
unsigned int16 tach1=0, tach2=0;



void ssp_interupt (){
   static i2c_state fstate=NOTHING;
   static byte address=0x00;
   static byte incoming=0;

   if (i2c_poll() == FALSE) {
      if (fState == ADDRESS_READ) {
         i2c_write (slaveinformacións[address]);
         fState = NOTHING;
      }
   }
   else {
      incoming = i2c_read();
         if (fState == NOTHING){
            fState = CONTROL_READ;
         }else if (fState == CONTROL_READ) {
                  address = incoming;
                  fState = ADDRESS_READ;
               }else if (fState == ADDRESS_READ) {
                        slaveinformacións[address] = incoming;
                        fState = NOTHING;
                     }
        }
}



void detect_rb_change() {
   short enc1;
   short enc2;
   static short last_enc1=1;
   static short last_enc2=1;
   enc1 = input(PIN_B5);
   enc2 = input(PIN_B6);
   if (last_enc1 && !enc1) {tach1++;}
   if (last_enc2 && !enc2) {tach2++;}
   last_enc1=enc1;
   last_enc2=enc2;
}


void initmodule(){
   int i;
   for (i=0;i<0x08;i++)
      slaveinformacións[i] = 0;                            //Init values array
   setup_timer_2(T2_DIV_BY_1,9,1);              //4Mhz, 100 Khz PWM module
   output_high(PIN_C1);                         //Init Pin C1 as output
   output_high(PIN_C2);                         //Init Pin C2 as output
   setup_ccp1(CCP_PWM);                         //Mode PWM CPP1
   setup_ccp2(CCP_PWM);                         //Mode PWM CPP2
   slaveinformacións[0]=10;                                //Init PWM Channel 1 value
   slaveinformacións[1]=10;                                //Init PWM Channel 2 value

   set_tris_A(0x2F);
   setup_adc_ports(A_ANALOG_RA3_REF);
   setup_adc(ADC_CLOCK_DIV_32);

   setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256); //Setup Timer0 to interrupt (1/(4 Mhz/256))=0,064 sec.
   set_timer0 (8);
   enable_interrupts(int_timer0);
   set_tris_b(0xF0);
   enable_interrupts(INT_RB);
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
}


void timer_0_isr (void) {
    static byte timer_0_count = 0;
    if (timer_0_count < 31) {
        timer_0_count++;
    } else {
        update = 1;
        timer_0_count = 0;
        slaveinformacións[2]=tach1;
        slaveinformacións[3]=tach2;
        tach1=0;
        tach2=0;
    }
    set_timer0 (8);
}

void updateinformacións(){
   int temp;
   static byte duty1=10,duty2=10,channel=0;   //Static variables
   if (duty1!=slaveinformacións[0]){           //Verify if the duty1 has been changed
      duty1=slaveinformacións[0];              //Save the new value
      set_pwm1_duty(duty1);         //Init PWM1 (10=100%..0=0%)
   }
   if (duty2!=slaveinformacións[1]){           //Verify if the duty1 has been changed
      duty2=slaveinformacións[1];              //Save the new value
      set_pwm2_duty(duty2);         //Init PWM2 (10=100%..0=0%)
   }
   if (channel==0){                 //Verify the channel that has to update
      slaveinformacións[4]=(int8) ((getadc(1)*500)/1024);         //Read Temperature channel 0
      temp = getadc(0);
      printf("Canal 6 I1=%i PWM1=%i\r",temp,slaveinformacións[0]);
      if (slaveinformacións[0]>1 && slaveinformacións[2]==0){
         if (slaveinformacións[6]==0){
            slaveinformacións[6]=1;
         } else {
            if (slaveinformacións[6]==2){
               slaveinformacións[6]=3;
            }
         }
      }
      channel=1;
   } else {
      slaveinformacións[5]=(int8) ((getadc(4)*500)/1024);         //Read Temperature channel 1
      temp = getadc(2);
      printf("Canal 6 I2=%i PWM2=%i\r",temp,slaveinformacións[1]);
      if (slaveinformacións[1]>1 && slaveinformacións[3]==0){
         if (slaveinformacións[6]==0){
            slaveinformacións[6]=2;
         } else {
            if (slaveinformacións[6]==1){
               slaveinformacións[6]=3;
            }
         }
      }
      channel=0;
   }
   if (slaveinformacións[7]==1){
      delay_ms(500);
      resetcpu();
   }
}

void main (){
   loader16F876();
   initmodule();
   delay_ms(2000);
   while (TRUE) {
      if (update) {
         updateinformacións();
         update = 0;
      }
   }
}
```

El programa que ha de instalarse en el chip maestro, que es el elemento más importante, ya que incorpora el algoritmo PID de control de velocidad no lo posteo porque es enorme, muy enorme (culpa de los menús del LCD, jejeje) pero lo mismo, disponible de forma gratuíta para quien quiera realizar este montaje o derivados, pero SIEMPRE CITANDO LA FUENTE, PROCEDENCIA ORIGINAL DEL CÓDIGO Y EL PROYECTO.

Siento hacer estas cosas, pero concretamente en este HM-Baybus hemos trabajado un grupo de personas durante casi DOS AÑOS para tenerlo listo... y no nos gustaría que alguien se apropiara de este esfuerzo.

Mi email información(at)d-zins(dot)com para quien necesite la memoria y los ficheros.

Un saludo


----------



## Paul Stryker (Dic 27, 2005)

Hola Teotekaplan!

Primero que todo, te alabo por haber realizado con éxito un proyecto de ese tamaño, eso no lo hace cualquiera   

Segundo, te explico mi situación: Con algunos estudiantes egresados de Ingeniería Biomédica estamos realizando un proyecto un poco menos ambicioso pero muy similar, en el cual debemos programar en C un PIC 16F877 para medir la lectura de 5 sensores y controlar su temperatura por medio de unas resistencias, alimentándolas cuando la T° descienda de un margen inferior, y cortando la alimentación cuando éste supere el margen superior.

El problema es que no conocemos nada de C y estamos muy complicados con este tema. No sé si pudieras ayudarnos en algo, ya que sabemos que el problema en sí no es tan complicado, pero tenemos muchas dudas al intentar hacer un programa... Si por casualidad tienes algún código que pueda ayudarnos como ejemplo, te lo agradeceríamos mucho...

Saludos, Pablo


----------



## kain589 (Dic 28, 2005)

Te recomiendo esta pagina

http://www.frino.com.ar/

Aqui encontraras un manual de C en CCs, ademas si buscas por la red encontraras manuales y foros sobre Pic's y C

Yo todavia no domino mucho,pero tu proyecto parece mucho mas sencillo que el PID, ya que tu lo que haras sera trabajar en un rango si llega al minimo actuas y cuando llegues al maximo dejas de actuar

Por cierto Teotekaplan, cual es tu correo, es que estoy interesado en ver ese proyecto y por la red p2p he buscado pero no he encontrado nada


----------



## Paul Stryker (Dic 28, 2005)

Muchas gracias kain589, esa página nos será de buena ayuda. Sin embargo, el problema que nosotros tenemos es que no disponemos actualmente de ningún dispositivo para probar el PIC (se encuentra en un laboratorio del cual no disponemos de libre acceso)... es por eso que no podemos probar los programas que podamos generar, por último para ir haciendo arreglos hasta llegar al programa final. Por ello es que preguntaba si es que acaso alguien nos podría guiar un poco hacia el código que necesitamos, no necesariamente el programa en sí, aunque si así lo fuera nos encargaríamos de incluirlos en los agradecimientos del proyecto =)

Muchas gracias


----------



## cricad (Ene 25, 2006)

Teotekaplan, me intereza conocer mas acerca de las comunicaciones I2c; en el momento estoy trabajando en un proyecto, en el cual nesecito que el 16f877 trabaje como esclavo; debe ser igual al codigo que publicaste, pero realmente poco me he adentrado en el lenguaje C; a si que seria de gran ayuda, publiques algunos ejemplos, si los tienes, de como configurar los PICs (16f877) pero  como esclavos ( .asm).
cricad@hotmail.com


----------



## cricad (Ene 25, 2006)

Teotekaplan, me intereza conocer mas acerca de las comunicaciones I2c; en el momento estoy trabajando en un proyecto, en el cual nesecito que el 16f877 trabaje como esclavo; debe ser igual al codigo que publicaste, pero realmente poco me he adentrado en el lenguaje C; a si que seria de gran ayuda, publiques algunos ejemplos, si los tienes, de como configurar los PICs (16f877) pero  como esclavos ( .asm).
cricad@hotmail.com


----------

