Saturday, May 30, 2020

Interfacing LM35 temperature sensor to the ADC module of PIC16F887

LM35 is an analog temperature sensor built in an integrated circuit. It could work in voltage range of -55 to +150 degree Celsius. It could be supply by a DC voltage between 4 to 30 V. It analog output is the temperature data. It is a linear output, 10 mV per degree Celsius.

Using the MCU ADC, it's easy to access rather using a complex protocol like one-wire or I2C bus.



Interfacing LM35 temperature sensor to the ADC module of PIC16F887
LM35 IC in TO-92 package and its pin out. 

To find the analog temperature data, we can find the digital ADC result per 10 mV. Or we can find the total voltage reading, multiplied by 100 to get the equivalent temperature in degree Celsius.

In this example, I use the ADC module to read the temperature data between -55 to 150 degree Celsius. The internal ADC module of PIC16F887 use -2.5 V to +2.5 V reference voltage, to make the device be able to read both negative and positive voltage.

I use timer 0 overflow interrupt to schedule the ADC reading for every one second.

The SSD is multiplexed with seven digits. Each digit turn on for every 5 milli seconds.


Interfacing LM35 temperature sensor to the ADC module of PIC16F887
Schematic diagram. The LM35 connects to RB4/AN11 to convert the analog
temperature data. The display is multiplexed with seven digits SSD.

Source code's here:

#include<xc.h>
// PIC16F887 Configuration Bit Settings
// CONFIG1
#pragma config FOSC = XT
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = ON
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = ON
#pragma config IESO = ON
#pragma config FCMEN = ON
#pragma config LVP = ON
// CONFIG2
#pragma config BOR4V = BOR40V
#pragma config WRT = OFF
/*_XTAL_FREQ use for __delay*/
#define _XTAL_FREQ 4000000
#define ssdRate 5
void driveDisplays(  int analogRead){
 unsigned char ssd[16]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,
 0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
 float voltage;
 int _voltage;
 /*Voltage Calculation total reference is
  +5V with centered ground*/
 voltage=(5*((float)(analogRead)/1024))-2.5;
 voltage*=10;
 /*Now _voltage becomes temperature,
  multiply it by 100 to convert it
  to the SSD data*/
 _voltage=(voltage*100);
 /*Check negative voltage*/
 if(_voltage&0x8000){
     _voltage=-_voltage;
     PORTD=0x00;
     PORTC=0x40;
     if((_voltage<1000)|(_voltage>-1000))
         PORTD=0x02;
     else
         PORTD=0x01;
     __delay_ms(ssdRate);
 }
 /*Decimal Place*/
 if((_voltage>=1000)|(_voltage<=-1000)){
 PORTD=0x00;
 PORTC=ssd[_voltage/1000];
 PORTD=0x02;
 __delay_ms(ssdRate);
 }
 PORTD=0x00;
 PORTC=ssd[(_voltage%1000)/100];
 if(_voltage>=100)
     PORTD=0x04;
 __delay_ms(ssdRate);
 /*Floating point*/
 PORTD=0x00;
 PORTC=ssd[(_voltage%100)/10]|0x80;
 PORTD=0x08;
 __delay_ms(ssdRate);
 PORTD=0x00;
 PORTC=ssd[_voltage%10];
 PORTD=0x10;
 __delay_ms(ssdRate);
 PORTD=0x00;
 PORTC=0x63;
 PORTD=0x20;
 __delay_ms(ssdRate);
 PORTD=0x00;
 PORTC=0x39;
 PORTD=0x40;
 __delay_ms(ssdRate);
}
int readADC(void){
    GO=1;
    while(GO);
    /*Return a 10-bit result*/
    return (ADRESH<<8)+ADRESL;
}
void portSetup(void){
    /*Analog and digital Port
     Configuration*/
    PORTB=0x00;
    PORTC=0x00;
    PORTD=0x00;
    /*RB4 for analog input*/
    TRISB4=1;
    TRISC=0x00;
    TRISD=0x00;
}
void timer0Setup(void){
    /*Select FOSC*/
    T0CS=0;
    /*Select timer 0 Prescaler*/
    PSA=0;
    /*Enable Timer 0 Overflow
     interrupt*/
    T0IE=1;
    /*Turn on Global interrupt
     Control*/
    GIE=1;
    /*Clear interrupt flage*/
    T0IF=0;
    /*Clear timer 0 register*/
    TMR0=0;
}
void adcSetup(void){
    /*Analog and digital Port
     Configuration*/
    PORTB=0x00;
    PORTC=0x00;
    PORTD=0x00;
    /*RB4 for analog input*/
    TRISB4=1;
    TRISC=0x00;
    TRISD=0x00;
    /*Select external Voltage reference
     +2.5V to -2.5V*/
    VCFG1=1;
    VCFG0=1;
    /*Result is right justify*/
    ADFM=1;
    /*By default is analog,
     but again set it to analog*/
    ANS11=1;
    /*Select FRC Clock of ADC module*/
    ADCON0bits.ADCS=0x03;
    /*Turn on ADC Module*/
    ADON=1;
    /*Select AN11 RB4*/
    ADCON0bits.CHS=0x0B;
    /*initiate a conversion*/
    GO=1;
    /*Wait until GO=0 "done"*/
    while(GO);
}
int adcResult;
int cnt=10;
void main(void){
    
    portSetup();
    adcSetup();
    timer0Setup();
    
    while(1){
        //adcResult=readADC();
        driveDisplays(adcResult);
    }
}
void interrupt _ISR(void){
    if(T0IF){
        cnt+=1;
        T0IF=0;
    }
    if(cnt>=15){
        adcResult=readADC();
        cnt=0;
    }
}


Interfacing LM35 temperature sensor to the ADC module of PIC16F887
A sample of simulation


Back to main tutorials page.



No comments:

Post a Comment

Search This Blog

Labels

25AA010A (1) 8051 (7) 93AA46B (1) ADC (30) Analog Comparator (1) Arduino (15) ARM (6) AT89C52 (7) ATMega32 (54) AVR (57) CCS PICC (28) DAC (1) DHT11 (2) Display (105) Distance Sensor (3) DS18B20 (3) dsPIC (2) dsPIC30F1010 (2) EEPROM (5) Environment Sensor (4) esp8266 (1) I2C (29) Input/Output (67) Interrupt (19) Keil (5) Keypad (10) LCD (46) Master/Slave (1) MAX7221 (1) MCP23017 (5) MCP23S17 (4) Meter (3) MikroC (2) Motor (15) MPLABX (66) Nokia 5110 LCD (3) OLED (2) One-Wire (6) Oscillator (8) PCB (6) PCD8544 (3) PCF8574 (5) PIC (107) PIC12F (2) PIC16F628A (2) PIC16F630 (1) PIC16F716 (3) PIC16F818 (10) PIC16F818/819 (2) PIC16F84A (15) PIC16F876A (1) PIC16F877A (9) PIC16F88 (1) PIC16F887 (60) PIC18 (19) PIC18F1220 (4) PIC18F2550 (3) PIC18F4550 (12) PWM (11) RTC (8) Sensor (10) SH1106 (1) Shift Register (11) Shift Registers (2) SPI (24) STM32 (6) STM32 Blue Pill (6) STM32CubeIDE (6) STM32F103C8T6 (6) SysTick (3) temperature sensor (11) Thermometer (21) Timer/Counter (30) TM1637 (2) UART (7) Ultrasonic (4) Voltmeter (7) WDT (1) XC16 (2) XC8 (94)