Temperature monitoring with LM35 sensor

(instructions, reset, WDT, specifications...) PIC12F6xx, PIC16Fxxx, PIC16F6x, PIC16F7x

Temperature monitoring with LM35 sensor

Postby SamuelWong » Wed Jul 22, 2020 6:28 am

Hi, I am currently working on a temperature monitoring system using a PIC16f887, this is the code I've written but It takes too much space on my program space. The code is already taking 91.2% of my 2000H words.
Code: Select all
#pragma config CONFIG1 = 0x2CD2
#pragma config CONFIG2 = 0x0700
#include <stdio.h>
#include <stdlib.h>

//LCD module connections
#define LCD_RS       RD0
#define LCD_EN       RD1
#define LCD_D4       RD2
#define LCD_D5       RD3
#define LCD_D6       RD4
#define LCD_D7       RD5
#define LCD_RS_DIR   TRISD0
#define LCD_EN_DIR   TRISD1
#define LCD_D4_DIR   TRISD2
#define LCD_D5_DIR   TRISD3
#define LCD_D6_DIR   TRISD4
#define LCD_D7_DIR   TRISD5
//End LCD module connections

#include <xc.h>
#define _XTAL_FREQ 20000000
#include <stdint.h>        // include stdint header
#include "LCD_Lib.c"       // include LCD driver source file

uint16_t AN0RES=0;
float Temperature, Voltage;
char* TempSTR[16];
char* ADCN[16];

void InitADC(void);
uint16_t ADC_Read(uint8_t ANC);

void InitADC(void)
{
    ADCON0 = 0x91;
    ADCON1 = 0x80;
    PORTA  = 0x00;
    TRISA  = 0x20;
    ANSEL  = 0x10;
}

uint16_t ADC_Read(uint8_t ANC)
{
    /*if(ANC<0 || ANC>7) // Check Channel Number Validity
    { return 0;}*/
    ADCON0 = 0x91;
    __delay_us(30);
    GO_DONE = 1;               // Start A/D Conversion
    while(ADCON0bits.GO_DONE); // Polling GO_DONE Bit
    return ((ADRESH<<8)+ADRESL);
}

void main(void)
{
    LCD_Begin();
    InitADC();
 
    LCD_Cmd(LCD_CLEAR);
    LCD_Goto(1, 1);
    LCD_Print("Temperature");
 

    while(1)
    {
        AN0RES = ADC_Read(4);               // Read Analog Channel 4
        Voltage = AN0RES * 0.0048828;
        Temperature = Voltage / 0.01;   // Calculate The Temperature     
        sprintf(TempSTR, " %.2f", Temperature); // Convert The Temperature From Float To String
     
        LCD_Goto(1, 2);
        LCD_Print(TempSTR);
        __delay_ms(500);
    }
}


I checked that this part of the code here takes 84.9% of my Flash.
Code: Select all
while(1)
    {
        /*AN0RES = ADC_Read(4);               // Read Analog Channel 4
        Voltage = AN0RES * 0.0048828;
        Temperature = Voltage / 0.01;   // Calculate The Temperature     
        sprintf(TempSTR, " %.2f", Temperature); // Convert The Temperature From Float To String
     
        LCD_Goto(1, 2);
        LCD_Print(TempSTR);
        __delay_ms(500);*/
    }


I think the major problem is this line.
Code: Select all
sprintf(TempSTR, " %.2f", Temperature);


It takes 63.5% of my FLASH, how do I make it more efficient.
Thank you very much in advance!
SamuelWong
 
Posts: 11
Joined: Wed Jul 22, 2020 6:20 am

Re: Temperature monitoring with LM35 sensor

Postby ric » Wed Jul 22, 2020 6:47 am

Yes, floating point takes a lot of code space.
What temperature range do you need to support?
You could almost certainly make it faster, and less code space, just using a lookup table directly from the ADC readings.
Latest test project, an LED matrix display made from one reel of addressable LEDs. here
User avatar
ric
Verified identity
 
Posts: 659
Joined: Sat May 24, 2014 2:35 pm
Location: Melbourne, Australia
PIC experience: Professional 5+ years with MCHP products

Re: Temperature monitoring with LM35 sensor

Postby SamuelWong » Wed Jul 22, 2020 7:06 am

Temperature range is only from 25 - 50 degree celsius. I tried declaring Temperature and Voltage as Int but it doesn't help.

How do I use the lookup table you mention?
SamuelWong
 
Posts: 11
Joined: Wed Jul 22, 2020 6:20 am

Re: Temperature monitoring with LM35 sensor

Postby ric » Wed Jul 22, 2020 7:40 am

So Temperature = AN0RES * 0.0048828 / 0.01 = AN0RES * 0.48828
If Temperature ranges from 25 to 50, then you are only expecting AN0RES to range from 51 to 102, so you would only need a 52 element table, which could be an integer array with 52 items in it.

However I have changed my mind, you can just do this with integer math. First lets work in hundredths of a degree, assuming you want two decimal places.
So, Temperature * 100 = AN0RES * 48.828
A simple approximation would just be AN0RES * 49
(1023 * 49 = 50127, so won't overflow a uint16_t variable)
Or you could use 32 bit math, and multiply by 12500/256, as "/256" is just a right shift of 8 bits.
Code: Select all
uint16_t Temperature;
Temperature = (AN0RES * 12500UL)/256;

The "UL" suffix on the constant forces 32 bit math. 12500 is the nearest integer to 48.828 * 256
That gives you actual temperature * 100 in your variable. It's easy to insert a dot before the last two digits for display purposes.
Latest test project, an LED matrix display made from one reel of addressable LEDs. here
User avatar
ric
Verified identity
 
Posts: 659
Joined: Sat May 24, 2014 2:35 pm
Location: Melbourne, Australia
PIC experience: Professional 5+ years with MCHP products

Re: Temperature monitoring with LM35 sensor

Postby Roche » Wed Jul 22, 2020 10:06 am

If you use a 2.048V low voltage reference and a 4.096V high voltage reference you can get 0.2K resolution with virtually no maths. That probably exceeds the accuracy of the sensor and voltage references.
Roche
 
Posts: 72
Joined: Fri Jul 11, 2014 12:35 pm
PIC experience: Professional 5+ years with MCHP products

Re: Temperature monitoring with LM35 sensor

Postby upand_at_them » Mon Sep 28, 2020 9:44 pm

Roche wrote:If you use a 2.048V low voltage reference and a 4.096V high voltage reference you can get 0.2K resolution with virtually no maths. That probably exceeds the accuracy of the sensor and voltage references.


If you come back, I'd like to see an example of this, please.
upand_at_them
 
Posts: 4
Joined: Sun Apr 26, 2020 10:58 pm
PIC experience: Experienced Hobbyist

Re: Temperature monitoring with LM35 sensor

Postby Roche » Tue Sep 29, 2020 9:44 am

I was thinking of an LM135, but the general idea remains more or less the same. Use a 2.048V high reference. That gives each bit a weight of 0.2K, convert from binary to decimal if you need to for a display. All integer maths, no FP needed. Using the LM135 gives the advantage of direct Kelvin output, so a negative supply is not needed for low temperatures. The downside is that you need to shift the a2d window up to 2.048V to 4.096V, then subtract the Kelvin offset. Still all integer maths though.
Roche
 
Posts: 72
Joined: Fri Jul 11, 2014 12:35 pm
PIC experience: Professional 5+ years with MCHP products


Return to 14-Bit Core

Who is online

Users browsing this forum: No registered users and 15 guests

cron