CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Temperature reading

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
mcataldo



Joined: 04 Jul 2010
Posts: 11
Location: Santiago, Chile

View user's profile Send private message

Temperature reading
PostPosted: Thu Jul 08, 2010 1:38 am     Reply with quote

Hi everybody, recently I've found a trouble with my system. I'm using PIC 16F877A and 2 LM35DZ. Problem is when I run Proteus to simulate, when it's an even value, LCD shows exactly half this and when is an odd value, LCD shows half (value - 1). For example, when real temperature is 10, LCD shows 5, when is 11 shows 5, and for 12 it shows 6.

I attach a code part.

Thank you.
Code:

#include <16F877A.h>
#device ADC=8
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT
#use delay(clock=4000000)

#include <LCD.c>

#priority rb,timer2

// Declaración de variables
int temp_sp;
int temp_sp_ee;
long temp_analogo_c;
long temp_analogo_f;
int temp_f;
int temp_f1;
int temp_f2;
int temp_f3;
int temp_f4;
int temp_c;
int temp_c1;
int temp_c2;
int temp_c3;
int temp_c4;
int temp_min;
int temp_max;
short temp_read = 0;

void main()
{

  set_tris_a(0xFF); // interesa que los puertos A0 y A1 sean salidas (0)
  set_tris_b(0xFF); // Señal Pulsadores
  set_tris_c(0x00); // Señal PWM para los servos
  set_tris_d(0x00); // Puertos que van al LED

  setup_adc(ADC_CLOCK_DIV_32);
  setup_adc_ports(ALL_ANALOG);

  setup_psp(PSP_DISABLED);
  setup_spi(FALSE);
  setup_comparator(NC_NC_NC_NC);
  setup_timer_0(RTCC_INTERNAL);
  setup_timer_1(T1_DISABLED);
  setup_timer_2(T2_DIV_BY_16,255,1); //el postscale es para determinar

switch (counter)
    {
       case 0:set_adc_channel(0);
              temp_analogo_f=read_adc(); //10 bits
              temp_f1=(int)temp_analogo_f; //conversion a °C (LM335) se 
              set_adc_channel(1);
              temp_analogo_c=read_adc(); //10 bits
              temp_c1=(int)temp_analogo_c; //conversion a °C (LM335) se
              counter = 1;
              break;

       case 1:set_adc_channel(0);
              temp_analogo_f=read_adc(); //10 bits
              temp_f2=(int)temp_analogo_f; //conversion a °C (LM335) se
              set_adc_channel(1);
              temp_analogo_c=read_adc(); //10 bits
              temp_c2=(int)temp_analogo_c; //conversion a °C (LM335) se
              counter = 2;
              break;

       case 2:set_adc_channel(0);
              temp_analogo_f=read_adc(); //10 bits
              temp_f3=(int)temp_analogo_f; //conversion a °C (LM335) se mejora con Vref A/D
              set_adc_channel(1);
              temp_analogo_c=read_adc(); //10 bits
              temp_c3=(int)temp_analogo_c; //conversion a °C (LM335) se
              counter = 3;
              break;

       default:set_adc_channel(0);
               temp_analogo_f=read_adc(); //10 bits
               temp_f4=(int)temp_analogo_f; //conversion a °C (LM335) se 
               set_adc_channel(1);
               temp_analogo_c=read_adc(); //10 bits
               temp_c4=(int)temp_analogo_c; //conversion a °C (LM335) se
               temp_f=(temp_f1+temp_f2+temp_f3+temp_f4)/4;
               temp_c=(temp_c1+temp_c2+temp_c3+temp_c4)/4;
               temp_min=temp_f+1;
               temp_max=temp_f+4;

    lcd_putc("\f");
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Tref:%2u\xDF",temp_sp);
    lcd_gotoxy(9,1);
    printf(lcd_putc,"Tcal:%2u\xDF",temp_c);
    lcd_putc(223);
    lcd_gotoxy(1,2);
    printf(lcd_putc,"Tmin:%2u\xDF",temp_min);
    lcd_gotoxy(9,2);
    printf(lcd_putc,"Tmax:%2u\xDF",temp_max);
    lcd_putc(223);
    delay_ms(800);


Last edited by mcataldo on Thu Jul 08, 2010 11:58 am; edited 1 time in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19383

View user's profile Send private message

PostPosted: Thu Jul 08, 2010 2:14 am     Reply with quote

Some comments:
Alongside your 'read_adc' lines, you have the comment '10 bits'. However you have the ADC setup to return 8 bits, in the second line of your program...
You are selecting an ADC channel, and immediately reading it. This will give incorrect result. The ADC acquisition time, is just under 20uSec for this chip.
Why are you moving the value from the ADC into a value, then into another. Seems just a waste of time?. Why not just put the read value directly into the variable you want.
You then have a remark on each of these tranfers about 'conversion to degrees C', or 'conversions to degrees F', but no such conversion is taking place. The sum of four readings, and then division by four, could be done much easier with an array.
You are then adding up four integers (remember 8 bit), will the sum be less than 255?.

Best Wishes
mcataldo



Joined: 04 Jul 2010
Posts: 11
Location: Santiago, Chile

View user's profile Send private message

PostPosted: Thu Jul 08, 2010 11:57 am     Reply with quote

Ok, I made changes you told me, but LCD still shows the same values. Regarding temperatures addition, their values are small (no more than 20ºC), therefore this sum is always lower than 255.

I attach changes

Code:

#device ADC=10

long temp_f1;
long temp_c1;
int temp_f;
int temp_c;

switch (counter)
    {
       case 0:set_adc_channel(0);
              delay_us(20);
              temp_f1=read_adc(); //10 bits
              set_adc_channel(1);
              delay_us(20);
              temp_c1=read_adc(); //10 bits

             

PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jul 08, 2010 12:41 pm     Reply with quote

Strip the program down to just a few lines. Use only one A/D channel.
Make that channel work.

If you have problems then post your complete short test program.
By complete I mean, post the #include for the PIC, #device statement,
#fuses statement, #use delay(), main(), closing braces, etc. In other
words, a compilable program. But it must be short (10 lines in main, max).

Also post your compiler version.
mcataldo



Joined: 04 Jul 2010
Posts: 11
Location: Santiago, Chile

View user's profile Send private message

PostPosted: Thu Jul 08, 2010 1:21 pm     Reply with quote

Here is full code. I don't know how shrink it. Regarding ADC channels, I'm using two sensor, then I need two channels (or not?).

Code:

#include <16F877A.h>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT
#use delay(clock=4000000)

#include <LCD.c>

#priority rb,timer2

// Declaración de variables
int temp_sp;
int temp_sp_ee;
int temp_f;
long temp_f1;
long temp_f2;
long temp_f3;
long temp_f4;
int temp_c;
long temp_c1;
long temp_c2;
long temp_c3;
long temp_c4;
int temp_min;
int temp_max;
short temp_read = 0;

// Variables relacionadas a los Servos
signed int d_temp;
signed int d_temp_c;
signed int d_temp_f;
int r_temp;
int contador_c;
int contador_f;
int contador_p;
int N;
int counter = 0;
//short t_default = 1;

// Variables relacionadas a los pulsadores
short msg_max = 0;
short msg_min = 0;
short sp=0;
//short rebote = 0;

// Interrupción para señal PWM de Servomotores
#INT_TIMER2
void servos()
{
  N++;
// El timer 2 está contando permanentemente, cuando llega al overflow se detiene
// el main y entra a la rutina de interrupción. Ejecuta los pasos que vienen a
// continuación y regresa a la línea de comandos del main.
  switch (N)
  {
     case 1:output_low(PIN_C2);
            set_timer2(contador_f);
            break;
     case 2:output_low(PIN_C1);
            set_timer2(contador_p);
            break;
     case 7:output_high(PIN_C1);
            output_high(PIN_C2);
            set_timer2(contador_c);
            N = 0;
            break;
     default:output_low(PIN_C1);
             output_low(PIN_C2);
             set_timer2(0);
             break;
  }
}

// Interrupción de cambio de temperatura de Setpoint por pulsadores
#INT_RB
void pulsadores()
{
  disable_interrupts(INT_RB);
  disable_interrupts(INT_TIMER2);
  if(!input(PIN_B4))
  {
    if(temp_sp < temp_max)
    {
      temp_sp = temp_sp+1;
      sp = 1;
    }
    else
      msg_max = 1;
  }
  if(!input(PIN_B5))
  {
    if(temp_sp > temp_min)
    {
      temp_sp = temp_sp-1;
      sp = 1;
    }
    else
      msg_min = 1;
  }   
  enable_interrupts(INT_TIMER2);
  enable_interrupts(INT_RB);
}

void main()
{

  set_tris_a(0xFF); // interesa que los puertos A0 y A1 sean salidas (0)
  set_tris_b(0xFF); // Señal Pulsadores
  set_tris_c(0x00); // Señal PWM para los servos
  set_tris_d(0x00); // Puertos que van al LED

  setup_adc(ADC_CLOCK_DIV_32);
  setup_adc_ports(ALL_ANALOG);

  setup_psp(PSP_DISABLED);
  setup_spi(FALSE);
  setup_comparator(NC_NC_NC_NC);
  setup_timer_0(RTCC_INTERNAL);
  setup_timer_1(T1_DISABLED);
  setup_timer_2(T2_DIV_BY_16,255,1); //el postscale es para determinar cuantos
                                     //overflows para gatillar una interrupción
 
// se acostumbra a poner aca el enable interrupts ...

   lcd_init();
   
   // Mensaje de Bienvenida
   lcd_putc("\f");
   lcd_gotoxy(1,1);
   printf(lcd_putc,"Ducha  Electrica");
   lcd_gotoxy(1,2);
   printf(lcd_putc,"Automatizada V.6");
   delay_ms(500);
   lcd_putc("\f");
   lcd_gotoxy(1,1);
   printf(lcd_putc," G.14 : Cataldo");
   lcd_gotoxy(1,2);
   printf(lcd_putc,"        Cortes");
   delay_ms(500);
   
   // Temperatura de Setpoint
   temp_sp_ee = read_eeprom(0);
   if(temp_sp_ee != 255)
   {
   temp_sp = temp_sp_ee;
   }
   else
   {
   temp_sp = 15;
   }

//***** Setup del número al que debe contar timer 2 por defecto

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER2);
   enable_interrupts(INT_RB);
   
   //se debe crear el primer pulso que posiciona las válvulas en reposo
   
   output_high(PIN_C1);
   output_high(PIN_C2);
   contador_c = 94;
   contador_f = 0;
   contador_p = 156;
   set_timer2(162);
   N = 0;
   
   while(TRUE)
   {

//      enable_interrupts(INT_RB);
   
    // LECTURA DE TEMPERATURA ANÁLOGA
   
   
    // Definición de los anchos de pulso para las señales PWM

// Los casos son los siguientes:

// Primero, para elevar la temperatura, no necesito hacer nada con las válvulas.

// Segundo, si la T° del agua caliente está por sobre la T° de setpoint, debo
// abrir la válvula de agua fría
     // Agua fría
    switch (counter)
    {
       case 0:set_adc_channel(0);
              delay_us(20);
              temp_f1=read_adc(); //10 bits
              set_adc_channel(1);
              delay_us(20);
              temp_c1=read_adc(); //10 bits
              counter = 1;
              break;
       case 1:set_adc_channel(0);
              delay_us(20);
              temp_f2=read_adc(); //10 bits
              set_adc_channel(1);
              delay_us(20);
              temp_c2=read_adc(); //10 bits
              counter = 2;
              break;
       case 2:set_adc_channel(0);
              delay_us(20);
              temp_f3=read_adc(); //10 bits
              set_adc_channel(1);
              delay_us(20);
              temp_c3=read_adc(); //10 bits
              counter = 3;
              break;
       default:set_adc_channel(0);
               delay_us(20);
               temp_f4=read_adc(); //10 bits
               set_adc_channel(1);
               delay_us(20);
               temp_c4=read_adc(); //10 bits
               temp_f=(temp_f1+temp_f2+temp_f3+temp_f4)/4;
               temp_c=(temp_c1+temp_c2+temp_c3+temp_c4)/4;
               temp_read = 1;
               counter = 0;
               break;
    }
    if (temp_read == 1)
    {
      temp_read = 0;
      temp_min = temp_f+1;
      temp_max = temp_f+4;

      d_temp_c = (int)temp_c - temp_sp;
      d_temp_f = temp_sp - (int)temp_f;
      d_temp = (int)temp_c - (int)temp_f;
      r_temp = 300*d_temp_f/d_temp;

      if (d_temp_c >= 0 && d_temp > 0)
      {
      // Al contar hasta 31 se tienen 0,5 ms o -90°
      // Al contar hasta 94 se tienen 1,5 ms o 0°
      // Al contar hasta 156 se tienen 2,5 ms o +90°

      // Al igualar el resultado a una variable del tipo int, ésta tomará el valor
      // entero y para que quede redondeada se usa el truco de sumar 0.5
         switch (r_temp)
         {
            case 75:contador_c = 210; // 256-46
                    contador_f = 162; // 256-(140-46)
                    contador_p = 116; // 256-140
                    break;
            case 100:contador_c = 204; // 256-52
                     contador_f = 173; // 256-(135-52)
                     contador_p = 121; // 256-135
                     break;
            case 150:contador_c = 194; // 256-62
                     contador_f = 193; // 256-(125-62)
                     contador_p = 131; // 256-125
                     break;
            case 200:contador_c = 183; // 256-73
                     contador_f = 215; // 256-(114-73)
                     contador_p = 142; // 256-114
                     break;
            case 225:contador_c = 177; // 256-79
                     contador_f = 225; // 256-(110-79)
                     contador_p = 146; // 256-110
                     break;
            default:contador_c = 162; // 256-94
                    contador_f = 255;
                    contador_p = 162; // 256-94
                    break;
         }
    }
    else
    {
      contador_c = 162;
      contador_f = 255;
      contador_p = 162;
    }
    set_timer2(contador_c);
   
    //en caso de que se alcance la temperatura, entonces:
   
    // Mostrar la temperatura leida en el Display
    lcd_putc("\f");
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Tref:%2u\xDF",temp_sp);
    lcd_gotoxy(9,1);
    printf(lcd_putc,"Tcal:%2u\xDF",temp_c);
    lcd_putc(223);
    lcd_gotoxy(1,2);
    printf(lcd_putc,"Tmin:%2u\xDF",temp_min);
    lcd_gotoxy(9,2);
    printf(lcd_putc,"Tmax:%2u\xDF",temp_max);
    lcd_putc(223);
    delay_ms(800);

    // Guardar temperatura de setpoint
    if(sp == 1)
    {
      sp = 0;
      write_eeprom(0,temp_sp);
    }
    // Mostrar mensaje que se ha alcanzado temperatura máxima o mínima
    if(msg_max == 1)
    {
      msg_max = 0;
      lcd_putc("\f");
      lcd_gotoxy(1,1);
      printf(lcd_putc,"Ha alcanzado la");
      lcd_gotoxy(1,2);
      printf(lcd_putc,"  temp. maxima ");
      delay_ms(500);
    }
    if(msg_min == 1)
    {
      msg_min = 0;
      lcd_putc("\f");
      lcd_gotoxy(1,1);
      printf(lcd_putc,"Ha alcanzado la");
      lcd_gotoxy(1,2);
      printf(lcd_putc,"  temp. minima ");
      delay_ms(500);
    }
//    if(rebote == 1);
//    {
//      rebote = 0;
//      delay_ms(20);
//    }
   
      delay_ms(1000);
   }
  }
}
 
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jul 08, 2010 1:30 pm     Reply with quote

Someone else will have to help.
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Thu Jul 08, 2010 2:06 pm     Reply with quote

Get one channel to work properly before trying to use two channels. Write a test program that reads ONE channel and prints the raw result. Then add C or F conversion. Then add a second channel. Take many small steps. No one here is going to read your big program searching for errors. We don't have the time.
_________________
The search for better is endless. Instead simply find very good and get the job done.
pmuldoon



Joined: 26 Sep 2003
Posts: 218
Location: Northern Indiana

View user's profile Send private message

PostPosted: Thu Jul 08, 2010 2:33 pm     Reply with quote

Check your setup_adc()
you might want to be at DIV_8 instead of DIV_32.

If that doesn't help, rewrite an LCD routine to display all values and averages and call it in the DEFAULT of your CASE statement. That should show you exactly what is going right and what is going wrong.
mcataldo



Joined: 04 Jul 2010
Posts: 11
Location: Santiago, Chile

View user's profile Send private message

PostPosted: Thu Jul 08, 2010 4:27 pm     Reply with quote

Thanks for your replies. I changed ADC clock value to 8 and I did a modification (I wrote the formula temp = 0.5*(read_adc()-1) and simulation shows correct values, but right now I've found another trouble: in real system, LCD shows value 160.

Thank you
pmuldoon



Joined: 26 Sep 2003
Posts: 218
Location: Northern Indiana

View user's profile Send private message

PostPosted: Fri Jul 09, 2010 5:47 am     Reply with quote

Are you sure your voltages make sense?
What is the supply voltage to the PIC? +5V?
What is the voltage at the AD pin?
Since you are not using the reference inputs of the AD, the PIC will see 1023 * Vin/Vcc as the result of the AD conversion.

At 5V Vcc you should get a 10 on the LCD with about 49mV input.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group