Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

help with pic16f877a and lm34 accuracy reading

Status
Not open for further replies.

Ernest Clyde Chua

Newbie level 6
Newbie level 6
Joined
Jul 29, 2014
Messages
13
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Visit site
Activity points
69
hi im making a digital thermometer using lm34 and pic16f877a,
heres the code

Code:
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;


 //-----------------------------------------------------
void staticprint(){

LCD_Out(2,1,"TIME");
LCD_Out(2,14,":");
LCD_Out(2,11,":");
LCD_Out(2,8,":");
LCD_Out(1,1,"TEMP");
LCD_Chr(1,15, 223);
LCD_Out(1,16,"F");
 }
//--------------------------------------tahmids code for lm35----------------
  void readtemp()
 {
unsigned long ADRead;
unsigned int vDisp[3];
unsigned char Display[7];
ADRead = (ADC_Get_Sample(0) * 500) >> 10;
           vDisp[0] = ADRead / 100;
           vDisp[1] = (ADRead / 10) % 10;
           vDisp[2] = ADRead % 10;
           Display[1] = vDisp[0] + 48;
           Display[2] = vDisp[1] + 48;
           Display[3] = vDisp[2] + 48;
           LCD_Chr(1, 8, Display[0]);
           LCD_Chr(1, 9, Display[1]);
           LCD_Chr(1, 10, Display[2]);
           LCD_Chr(1, 11, Display[3]);

 }
//------------------------------------------------------
void mydelay()
 {
 readtemp();
 staticprint();

               Delay_ms(250);

 readtemp();
 staticprint();

               Delay_ms(250);
 readtemp();
 staticprint();

               Delay_ms(250);
 readtemp();
 staticprint();
               Delay_ms(250);
  }
 //------------------------------------------------------



//-----------------------------------------------------------------------------

void main() 
{
    //-----------------------------
     PORTA = 0;
     TRISA = 0X01;
     PORTB = 0;
     TRISB = 0;
     LCD_Init();
     LCD_Cmd(_LCD_CURSOR_OFF);
     LCD_Cmd(_LCD_CLEAR);
     ADCON1 = 0x0E;
     ADC_Init();
     //----------------------------





//////////////////////////////////////////////////////////////////////////
     while (1)
     {

          //------------variables-----------------------
           char secs[7];
           char mins[7];
           char hours[7];
           char days[7];
           unsigned int s;
           unsigned int m;
           unsigned int h;
           unsigned int d;
          //-------------------------------------------

for(d = 0;d<40;d++)
 {
IntToStr(d,days);
if(d<10)
{
LCD_Out(2,7,Ltrim(days));
LCD_Out(2,6, "0");
}
if (d>9)
{
LCD_Out(2,6,Ltrim(days));
}


                for(h = 0;h<24;h++)
                {
                IntToStr(h,hours);
                        if(h==24)
                        {
                        d++;
                        }
                        if(h<10)
                          {
                          LCD_Out(2,10,Ltrim(hours));
                          LCD_Out(2,9,"0");
                         }
                          if (h>9)
                          {
                           LCD_Out(2,9,Ltrim(hours));
                           }
                                for(m = 0;m<60;m++)
                                {
                                IntToStr(m,mins);
                                        if(m==60)
                                        {
                                        h++;
                                        }
                                        if(m<10)
                                          {
                                          LCD_Out(2,13,Ltrim(mins));
                                          LCD_Out(2,12, "0");
                                         }
                                          if (m>9)
                                          {
                                           LCD_Out(2,12,Ltrim(mins));
                                           }

                                                for(s = 0;s<60;s++)
                                                {
                                                IntToStr(s,secs);

                                                        if(s==60)
                                                        {
                                                        m++;

                                                        }
                                                        if(s<10)
                                                          {
                                                          LCD_Out(2,16,Ltrim(secs));
                                                          LCD_Out(2,15, "0");
                                                         }
                                                          if (s>9)
                                                          {
                                                           LCD_Out(2,15,Ltrim(secs));
                                                           }
                                                           mydelay();

                                                }

                                }

                }
















 }

     }
}
when the reading is greater than 64 it reverts back to zero and increments as the reading rise.
what is wrong with the code and also how can i get decimal reading?
 

in
Code:
ADRead = (ADC_Get_Sample(0) * 500) >> 10;
although ADRead is unsigned long if ADC_Get_Sample() returns an int the calculation will be carried out as an int and then cast to unsigned long when assigned to ADRead - hence you get overflow
try
Code:
ADRead = (ADC_Get_Sample(0) * 500UL) >> 10;
should do the calculation as unsigned long
 
thanks horace1

how can i change this to add accuracy of .1 because it increase as soon it hits .5 any idea?
Code:
ADRead = (ADC_Get_Sample(0) * 500UL) >> 10;
           vDisp[0] = ADRead / 100;
           vDisp[1] = (ADRead / 10) % 10;
           vDisp[2] = ADRead % 10;
 

if you require a decimal value with afractional component why not make ADRead a float and use sprintf() to convert the value to text with a decimal point
 

i dont see sprintf in the library files for pic16f877a im using mikroc is there another way to get the float value of ADRead?
 

i dont see sprintf in the library files for pic16f877a im using mikroc is there another way to get the float value of ADRead?

I would suggest reexamining the mikroC Pro Compiler documentation, specifically the ANSI C and Standard Libraries section.

The mikroC Pro compiler clearly provides the following:

sprintf()
sprintl()
sprinti()

mikroC Pro for PIC Libraries

Of course, you could always write your own routine for the conversion of float types to string.


BigDog
 

i read a thread in mikroc, sadly pic16 doesn't support sprintf

One of many reasons why I no longer use the MikroC line of compilers, even though I actually purchased a license some years back.

Sadly the latest compiler documentation neglects to mention this fact:

Sprint Library

The following thread offers an example routine to perform the conversion from float type to string:

No sprintf for PIC16F88?


BigDog
 

i tried the code given in the links, it doesn't print anything i didn't alter the code and just assigned the lcd direction.
why it does't print the "X11.223 Y4.567 " in the display?

- - - Updated - - -

i see float to string in the mikroc library
can i turn an adc in to float and print it by this?

Code:
float ADRead;
char txt[16];

ADRead = ADC_Get_Sample(0);
FloatToStr(ADRead, txt);
 

Possibly, I'm not familiar with that routine as it is non-standard C.

I would suggest reading the documentation and trying out the example code.

It is not difficult to write your own float to string conversion routine.

Search this forum or Google it.

BigDog
 

Yes, FloatToStr() can be used to convert float value to string for LCD printing. I always use that in my ADC projects. Remember txt[] has to be txt[23] to use FloatToStr(). mikroC Help documentation recommends minimum elements required.
 

i tried it but how can i read the voltage in mV heres what ive done
Code:
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;



float voltage;


char voltagestr[23];



void main(){
PORTA = 0;
     PORTA = 0;
     TRISA = 0X01;
     PORTB = 0;
     TRISB = 0;
     LCD_Init();
     LCD_Cmd(_LCD_CURSOR_OFF);
     LCD_Cmd(_LCD_CLEAR);
     ADCON1 = 0x0E;
     ADC_Init();






Delay_ms(2500);
Lcd_Cmd(_LCD_CLEAR);





while (1)
{
      voltage = ADC_Read(0);


  //Convert ADC readings to strings for LCD)
      floatToStr(voltage, VoltageStr);


  //Write Strings to LCD
      LCD_Out(1,9,VoltageStr);


   //Wait a while
   delay_ms(2000);
}
}
how can i make the adc reading same as the value of voltage like this:
v=99.33 and ouput LCD_out(1,1,"99.33) ?
 

Please Zip and attach complete mikroC Project files. It will be easier to edit the code.
 

hello,

unfortunatly, mikroC is poor with PIC16F serie compare to PIC18F serie...that is !

Nota:
it is a very bad habit to put variables declaration inside an infinite loop !
Put them outside the main as global variables..

FloatToStr() mikroC is ugly to use
ADRead is not a float .. so use cast for using it inside FloatToStr
it is also a good habit to do that, even it can works without...

your result
Temp= 65 pts soit 65
Temp= 66 pts soit 65.99999
Temp= 27 pts soit 26.99999
Temp= 17 pts soit 16.99999
Temp= 269 pts soit 268.9999
Temp= 519 pts soit 518.9999
Temp= 605 pts soit 604.9999
Temp= 691 pts soit 690.9999
Temp= 840 pts soit 839.9999
Temp= 1021 pts soit 1020.999

test with this other function for best result , in particular, to fixe the number
of decimal into the result conversion.

Code:
// Globales variables
int ARRead;
float f1;
unsignec char TEXTE[60];
char * txt;
unsigned char CRam1[30];
.. other ....



void Float2Ascii (float x, unsigned char *str,char precision)
{
 /* converts a floating point number to an ascii string */
 /* x is stored into str, which should be at least 30 chars long */

 int ie, i, k, ndig;
 double y;
 ndig = ( precision<=0) ? 7 : (precision > 22 ? 23 : precision+1);
 ie = 0;
 /* if x negative, write minus and reverse */
 if ( x < 0)
 {
   *str++ = '-';
   x = -x;
 }
 /* put x in range 1 <= x < 10 */
 if (x > 0.0) while (x < 1.0)
 {
   x *= 10.0;                // a la place de =*
   ie--;
 }
 while (x >= 10.0)
 {
   x = x/10.0;
   ie++;
 }
 // in f format, number of digits is related to size
 ndig += ie;                                // a la place de =+
 //round. x is between 1 and 10 and ndig will be printed to
 // right of decimal point so rounding is ...
 for (y = i = 1; i < ndig; i++)
 y = y/10.;
 x += y/2.;
 if (x >= 10.0) {x = 1.0; ie++;}
 if (ie<0)
 {
   *str++ = '0'; *str++ = '.';
   if (ndig < 0) ie = ie-ndig;
   for (i = -1; i > ie; i--)  *str++ = '0';
 }
 for (i=0; i < ndig; i++)
 {
   k = x;
   *str++ = k + '0';
   if (i ==  ie ) *str++ = '.';
   x -= (y=k);
   x *= 10.0;
  }
 *str = '\0';
}





void main()
{
....
init Hardware();
init UART();
init LCD():
.....


  ADCON1 = 0x0E;
  ADC_Init();
  do
  {
  
  UART1_Write_CText("Temp= " );
  ADRead=ADC_Read(0);
  //readtemp();
  f1=   (float) ADRead * 0.004896;      // result 0 to 5.00 volt
  WordToStr(ADRead,CRam1);
  UART1_Write_Text(CRam1);
  UART1_Write_CText(" pts  soit " );
  UART1_Write(TAB);
  Float2Ascii (f1,txt,3);   // 3 = 3 digits after decimal point
  txt=TEXTE; // init pointeur txt
  UART1_Write_Text(txt);
  UART1_Write_CText(" Volts\r\n " );
  Delay_ms(1500);
  }
  while(1);

and result:
result on terminal
Temp= 1023 pts soit 5.009 Volts
Temp= 772 pts soit 3.780 Volts
Temp= 555 pts soit 2.717 Volts
Temp= 464 pts soit 2.272 Volts
Temp= 346 pts soit 1.694 Volts
Temp= 280 pts soit 1.371 Volts
Temp= 205 pts soit 1.004 Volts
Temp= 93 pts soit 0.455 Volts
Temp= 28 pts soit 0.137 Volts
Temp= 70 pts soit 0.343 Volts
Temp= 69 pts soit 0.338 Volts */

you can adjust the coef (floatting constant value 0.048) to your scale factor...
other than 5.000 volts and also use 2 decimal instead of 3 in
FloatToAscii(f1,txt,2);
 
Hello and thanks paulfjujo for the float2ascii. It works perfect. I'm calling it twice in my main function to convert two floats but it results in "There's not enough rom space" -error. My code is not that long that that's not the problem. I'm also using PIC16, so sprintf is not an option. Any idea why micro C pro is giving this kind of error?

Edit: forgot to mention that it's not the float2ascii function which causes this. It's the combination of this and other functions which work as by themselves ok, but not combined.
 
Last edited:

@Ernest Clyde Chua

Here is the fixed code. I have termiated the string variable txt 2 digits after decimal point.
 

Attachments

  • thermo.rar
    49.3 KB · Views: 129

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top