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 CCS Technical Support

LM34, A/d conversion and getting a 10 bit result.

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



Joined: 01 May 2004
Posts: 49

View user's profile Send private message

LM34, A/d conversion and getting a 10 bit result.
PostPosted: Thu May 20, 2004 1:11 am     Reply with quote

I'm using an LM34 for tempurature reading up tp 300' F (10 mV/degree farenheit), then printing the results on an LCD, Here's my code;

Code:
#include <16f877A.h>
#device ICD=TRUE
#fuses HS, NOWDT, NOPROTECT,PUT,BROWNOUT, NOLVP
#byte TRISA = 0x85
#byte PORTA = 0x05
#byte TRISB = 0x86
#byte PORTB = 0x06
#byte TRISD = 0x88
#byte PORTD = 0x08
#byte TRISE = 0x89
#byte PORTE = 0x09

#locate READ = 0x20
#locate HEAT = 0x21

#byte ADCON0 = 0x1F
#byte ADCON1 = 0x9F
#byte ADRESH = 0x1E
#byte OPTION = 0x81
#bit T0IF = 0x0B.2
#bit GO = 0x1F.2
#bit ADIF = 0x0C.6

/* Define Temp */
#bit TEMP = PORTE.0

/* Define Outputs*/
#bit Bake = PORTB.3
#bit Vent = PORTB.4



#bit Timed1 = READ.0
#bit Timed2 = READ.1

/* Define Inputs */
#bit PB_Preheat = PORTB.0
#bit PB_Plastic = PORTB.1
#bit PB_Metal = PORTB.2



#use delay(clock=20000000)
//#use rs232(DEBUGGER)
//#use rs232(baud=9600, xmit=PIN_c6,rcv=PIN_c7)
#include <lcd3.c>


   void main(void)

{

   lcd_init();

   ADCON0 = 0x69;      /* Fosc/8, A/D enabled */
   OPTION = 0x07;      /* TMR0 prescaller, 1:256, PORTB pullups */
   ADCON1 = 0x0E;      /* Left justify, 1 analog channel, VDD and Vss references */



   TRISB = 0x07;         /* PORTD Inputs and 0utputs */
   PORTB =0x07;        /*Sets up PORTD*/
   TRISE = 0x01;
   Timed1 =0;
   Timed2 = 0;
   HEAT = 0;         /* clears HEAT */


BACK:   do
   {;}


   while (T0IF == 0); /* Stay in loop until T0IF sets */

   
   /* Exit loop */

   T0IF = 0;   /* Clear the T0IF flag */
   GO = 1;   /* Start A/D conversion */


   do
   {;}
   while (ADIF == 0 );    /* Wait for conversion to complete */
    HEAT = ADRESH<<1;      /* Load HEAT with A/D value   */


   lcd_gotoxy(0,2);
   printf(lcd_putc, "TEMP %1u", HEAT);


      goto BACK;         /* Check again */


}


I know there is a lot of stuff before the MAIN, that is all from the rest of my code that this will be going with when it's working.


what I have here works fine up to 255 degrees, but then it roles over to zero again. I know this is because "HEAT" is only 8 bits, and so is ADRESH. Is there a way I can get this to work? Maybe combining ADRESH and ADRESL into a 16 bit adress.

I need to be able to multiplay the result by 2

Code:
 HEAT = ADRESH<<1;


In order to get the real tempurature.

Thank you again, you guys, you guys have been a big help to me.
valemike
Guest







Missing a #device ADC=10
PostPosted: Thu May 20, 2004 5:41 am     Reply with quote

This is what I do to get 10-bit A/D...

Code:

#include <16F876.h>
#device ADC=10
#fuses HS, NOWDT, NOPROTECT etc.


Don't forget the #device ADC=10
directive. You need that for 16F/16C/ family of PICs.
rwyoung



Joined: 12 Nov 2003
Posts: 563
Location: Lawrence, KS USA

View user's profile Send private message Send e-mail

PostPosted: Thu May 20, 2004 7:16 am     Reply with quote

You need a line
#device ADC=10
at the top to tell the compiler that results from the ADC are 10-bits long and not 8. Your code is just using the top 8 out of 10 bits.

And your variable "HEAT" is only 8 bits so it can never hold anything greater than 255 anyway.

I also suggest you use the library functions for manipulating the ADC so that your code is more portable to other PICs.
_________________
Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month!
RatFink



Joined: 01 May 2004
Posts: 49

View user's profile Send private message

PostPosted: Thu May 20, 2004 10:59 am     Reply with quote

Thanks valemike and rwyoung, I read through everything I could find here last night and found references to exactly what you guys are saying.


rwyoung wrote:
I also suggest you use the library functions for manipulating the ADC so that your code is more portable to other PICs.


When you say this, are you talking about these?

Code:
////////////////////////////////////////////////////////////////// ADC
// ADC Functions: SETUP_ADC(), SETUP_ADC_PORTS() (aka SETUP_PORT_A),
//                SET_ADC_CHANNEL(), READ_ADC()
// Constants used in SETUP_ADC_PORTS() are:
#define NO_ANALOGS             0x86         // None
#define ALL_ANALOG             0x80         // A0 A1 A2 A3 A5 E0 E1 E2 Ref=Vdd
#define ANALOG_RA3_REF         0x81         // A0 A1 A2 A5 E0 E1 E2 Ref=A3
#define A_ANALOG               0x82         // A0 A1 A2 A3 A5 Ref=Vdd
#define A_ANALOG_RA3_REF       0x83         // A0 A1 A2 A5 Ref=A3
#define RA0_RA1_RA3_ANALOG     0x84         // A0 A1 A3 Ref=Vdd
#define RA0_RA1_ANALOG_RA3_REF 0x85         // A0 A1 Ref=A3
#define ANALOG_RA3_RA2_REF              0x88   // A0 A1 A5 E0 E1 E2 Ref=A2,A3
#define ANALOG_NOT_RE1_RE2              0x89   // A0 A1 A2 A3 A5 E0 Ref=Vdd
#define ANALOG_NOT_RE1_RE2_REF_RA3      0x8A   // A0 A1 A2 A5 E0 Ref=A3
#define ANALOG_NOT_RE1_RE2_REF_RA3_RA2  0x8B   // A0 A1 A5 E0 Ref=A2,A3
#define A_ANALOG_RA3_RA2_REF            0x8C   // A0 A1 A5 Ref=A2,A3
#define RA0_RA1_ANALOG_RA3_RA2_REF      0x8D   // A0 A1 Ref=A2,A3
#define RA0_ANALOG                      0x8E   // A0
#define RA0_ANALOG_RA3_RA2_REF          0x8F   // A0 Ref=A2,A3
// Constants used for SETUP_ADC() are:
#define ADC_OFF                0              // ADC Off
#define ADC_CLOCK_DIV_2        1
#define ADC_CLOCK_DIV_8     0x41
#define ADC_CLOCK_DIV_32    0x81
#define ADC_CLOCK_INTERNAL  0xc1              // Internal 2-6us

// Constants used in READ_ADC() are:
#define ADC_START_AND_READ     7   // This is the default if nothing is specified
#define ADC_START_ONLY         1
#define ADC_READ_ONLY          6


I tried using these at first, but I'm actually using PORTE.0 as the A/D input because the driver for my LCD uses the first 3 bits of PORTA as the control lines, and using the above library funcions didn't seem to give me the option for setting only PORTE for the A/D conversion. Am I missing something here?

rwyoung wrote:
And your variable "HEAT" is only 8 bits so it can never hold anything greater than 255 anyway.


Yes, I understand that this is my problem with both "Heat" and "ADRESH"

Both of you wrote:
You need a line
#device ADC=10


I saw this in a few of the threads I read, but it was my understanding that the PIC16F877A always used 10 bit A/D, my problem is having those 10 bits to use. If I use the above library functions, and the "ADC_READ" in what location can I perform the math funtions I need to give me a reading to the LCD that I want?

Thank you
RatFink



Joined: 01 May 2004
Posts: 49

View user's profile Send private message

PostPosted: Thu May 20, 2004 2:19 pm     Reply with quote

OK, I spent a long time trying to change LCD drivers to get one that did have the control line on PORTA so I could use it for A/D and the standard libraries.... I can't get one to work.

So I'm trying to join ADRESH and ADRESL.

Code:
BACK:   do
   {;}


   while (T0IF == 0); /* Stay in loop until T0IF sets */


   /* Exit loop */

   T0IF = 0;   /* Clear the T0IF flag */
   GO = 1;   /* Start A/D conversion */


   do
   {;}
   while (ADIF == 0 );    /* Wait for conversion to complete */
   
   int16 HEAT;
   HEAT = make16(ADRESH, ADRESL);

    HEAT = HEAT<<1;      /* Load HEAT with A/D value   */


   lcd_gotoxy(0,2);
   printf(lcd_putc, "TEMP %1u", HEAT);


      goto BACK;         /* Check again */


}


but when I try to compile I get an error message

Quote:
A numeric expression must appear here


associated with

Code:
 int16 HEAT;


Why?
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

PostPosted: Thu May 20, 2004 3:01 pm     Reply with quote

I don't think that you can declare a variable just anywhere in code but I'm not really sure.
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Thu May 20, 2004 3:01 pm     Reply with quote

Try commenting out sections of your code until it goes away. int16 HEAT might not be what's causing the problem. It's usually something before the error that's causing the problem. I've had phantom errors before and had to enter the code from scratch because some kind of character was in there (control code?) that I couldn't see.

Ronald
prwatCCS



Joined: 10 Dec 2003
Posts: 70
Location: West Sussex, UK

View user's profile Send private message

PostPosted: Thu May 20, 2004 3:05 pm     Reply with quote

Here is a code snip from my AD implementations ..

u16 is typedefed elsewhere but is unsigned int16

All variables are globals - I dont understand why you force HEAT to be at 0x20 in your code ...

Code:

#device ADC=10

// current and voltage monitors

typedef unsigned int16 u16;

   u16   V_Out1;
   u16   V_Out2;

   u16   I_Out1;
   u16   I_Out1Max;
   u16   I_Out1Min;

   u16   I_Out2;
   u16   I_Out2Max;
   u16   I_Out2Min;


   u8    analog_channel;


// the above is from my header file



#int_AD
void ADC_irq(void)
{

       disable_interrupts( INT_AD );

       switch (analog_channel++)
       {
       case AN0:
         V_Out1 = read_adc(ADC_READ_ONLY);
         break;

       case AN1:
         I_Out1 = (I_Out1 + read_adc(ADC_READ_ONLY))/2;
         if (I_Out1 > I_Out1Max)
            I_Out1Max = I_Out1;
         else if (I_Out1 < I_Out1Min)
            I_Out1Min = I_Out1;
          break;

       case AN2:
         V_Out2 = read_adc(ADC_READ_ONLY);
         break;

       case AN3:
         I_Out2 = (I_Out2 + read_adc(ADC_READ_ONLY))/2;
         if (I_Out2 > I_Out2Max)
            I_Out2Max = I_Out2;
         else if (I_Out2 < I_Out2Min)
            I_Out2Min = I_Out2;
         break;

       case AN4:
         analog_channel = AN0;
         break;

       default:
         analog_channel = AN0;

       }
       set_adc_channel(analog_channel);      // next port to sample

}


This code has been used on 16F877 and 18F252 projects without any problems - albeit that I have irq's running and collect data from multiple ADC ports.


in your case I would use

u16 HEAT;

HEAT = read_adc(ADC_READ_ONLY);

HEAT = HEAT << 1; //multiply heat * 2 as required

Also I think Neutine is right about placement of int16 HEAT; - move it to the top of main()
_________________
Peter Willis
Development Director
Howard Eaton Lighting Ltd UK
RatFink



Joined: 01 May 2004
Posts: 49

View user's profile Send private message

PostPosted: Thu May 20, 2004 3:08 pm     Reply with quote

Neutone, Thanx

now I'm having trouble with the printf format.
languer



Joined: 09 Jan 2004
Posts: 144
Location: USA

View user's profile Send private message

PostPosted: Thu May 20, 2004 3:22 pm     Reply with quote

Try,
Code:
printf(lcd_putc, "TEMP %l", HEAT);


And if you keep the #locate statement in,
Code:
#locate READ = 0x20
#locate HEAT = 0x21
I think the READ may overflow into the HEAT memory location if it is more than a byte-long.

And you should still be able to use,
Code:
heat = read_adc( ADC_READ_ONLY );
instead of,
Code:
HEAT = make16(ADRESH, ADRESL); 
Just a thought.
RatFink



Joined: 01 May 2004
Posts: 49

View user's profile Send private message

PostPosted: Thu May 20, 2004 3:30 pm     Reply with quote

languer wrote:
Try,
Code:
printf(lcd_putc, "TEMP %l", HEAT);


Thwnx I'll try that (**edit**, nope, I still get a wrong format message)

languer wrote:
And if you keep the #locate statement in,
Code:
#locate READ = 0x20
#locate HEAT = 0x21
I think the READ may overflow into the HEAT memory location if it is more than a byte-long.


I actually have that commented out now, (Read actually just holds values in 2 bits)

languer wrote:
And you should still be able to use,
Code:
heat = read_adc( ADC_READ_ONLY );
instead of,
Code:
HEAT = make16(ADRESH, ADRESL); 
Just a thought.


Even though I'm not using the other A/D library functions? Which I would if I could define porte.o as my input.
RatFink



Joined: 01 May 2004
Posts: 49

View user's profile Send private message

PostPosted: Thu May 20, 2004 4:01 pm     Reply with quote

WOOOT! I got it to work, it may be ugly, but it does what it should.

Code:
   void main(void)

{
   int16 HEAT;
   lcd_init();

   ADCON0 = 0x69;      /* Fosc/8, A/D enabled */
   OPTION = 0x07;      /* TMR0 prescaller, 1:256, PORTB pullups */
   ADCON1 = 0x0E;      /* Left justify, 1 analog channel, VDD and Vss references */



   TRISB = 0x07;         /* PORTD Inputs and 0utputs */
   PORTB =0x07;        /*Sets up PORTD*/
   TRISE = 0x01;
   Timed1 =0;
   Timed2 = 0;
   //HEAT = 0;         /* clears HEAT */
   


BACK:   do
   {;}


   while (T0IF == 0); /* Stay in loop until T0IF sets */


   /* Exit loop */

   T0IF = 0;   /* Clear the T0IF flag */
   GO = 1;   /* Start A/D conversion */


   do
   {;}
   while (ADIF == 0 );    /* Wait for conversion to complete */

   
   HEAT = make16(ADRESH, ADRESL);

    HEAT = HEAT*(5.0/65535)*100;      /* Load HEAT with A/D value, convert to correct temp*/


   lcd_gotoxy(0,2);
   printf(lcd_putc, "TEMP %lu", HEAT);


      goto BACK;         /* Check again */



Thanx to all that helped, now I just have to learn TIMER0 interupts then the code for my project will be done.
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