đź”§ PIC Microcontroller Project: Digital Temperature Monitor with LM35 and LCD

đź”§ PIC Microcontroller Project: Digital Temperature Monitor with LM35 and LCD file 1AF28TvEfjUp41udCwG5nk 1

đź”§ PIC Microcontroller Project: Digital Temperature Monitor with LM35 and LCD


1. Introduction

In this project, we’ll build a simple digital thermometer using a PIC16F877A microcontroller. It will read temperature from an LM35 sensor and display the value in Celsius on a 16×2 LCD. This kind of setup is commonly used in temperature monitoring systems like weather stations, greenhouses, or home automation systems.


2. Learning Objectives

By completing this project, you will:

  • Learn how to connect and use an analog temperature sensor with a PIC microcontroller.
  • Understand how the Analog-to-Digital Converter (ADC) works on the PIC16F877A.
  • Interface a 16×2 character LCD using 4-bit mode.
  • Write and structure embedded C code using MPLAB X and the XC8 compiler.
  • Test, troubleshoot, and modify your embedded system for real-world use.

3. Components and Tools Needed

You’ll need the following components and tools:

  • One PIC16F877A microcontroller
  • One LM35 analog temperature sensor
  • One 16×2 character LCD (HD44780 compatible)
  • One 10k potentiometer (for adjusting LCD contrast)
  • One 20MHz crystal oscillator
  • Two 22pF ceramic capacitors (for the crystal)
  • Breadboard and jumper wires
  • Regulated 5V power supply
  • MPLAB X IDE and XC8 compiler
  • PIC programmer (such as PICkit3)

4. Concept Overview

The LM35 outputs a voltage that increases linearly with temperature. For example, 250 millivolts means 25 degrees Celsius. The microcontroller reads this analog signal through its ADC module and converts it into a digital number. We then convert that number into a readable temperature and show it on the LCD screen.

The LCD is operated in 4-bit mode to save microcontroller pins. This means we send data in two parts (high nibble and low nibble) using only four data lines instead of eight.


5. Step-by-Step Instructions

Hardware Setup

Connecting the LCD:

  • Connect the LCD’s VSS pin to ground and VDD pin to 5V.
  • The VO pin (for contrast) should connect to the middle pin of a 10k potentiometer, with the outer pins connected to 5V and ground.
  • RS (Register Select) connects to RC0 on the PIC.
  • RW (Read/Write) connects to ground (since we only write to the display).
  • E (Enable) connects to RC1.
  • Data pins D4 to D7 on the LCD connect to RC2 to RC5 on the PIC.
  • Connect the LCD’s backlight (if available) through a current-limiting resistor to 5V.

Connecting the LM35:

  • Pin 1 of the LM35 connects to 5V.
  • Pin 2 (the output) connects to RA0 on the PIC (analog channel 0).
  • Pin 3 connects to ground.

Connecting the crystal:

  • Place the 20MHz crystal between the OSC1 and OSC2 pins (pins 13 and 14).
  • Add a 22pF capacitor from each of these pins to ground.

Powering the system:

  • Make sure your PIC microcontroller receives a stable 5V regulated power supply.
  • Ensure all grounds are connected together.

Code (XC8 for MPLAB X)

Below is the full C code with comments:

#define _XTAL_FREQ 20000000

#include <xc.h>
#include <stdio.h>

// Configuration bits
#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config BOREN = ON
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF

// Function declarations
void ADC_Init(void);
unsigned int ADC_Read(unsigned char);
void LCD_Init(void);
void LCD_Command(unsigned char);
void LCD_Char(unsigned char);
void LCD_String(const char*);

void main(void) {
    char buffer[16];
    unsigned int adc_value;
    float temperature;

    TRISA = 0x01; // RA0 as input
    TRISC = 0x00; // PORTC as output for LCD

    ADC_Init();
    LCD_Init();

    while (1) {
        adc_value = ADC_Read(0); // Read from analog channel 0
        temperature = (adc_value * 5.0 / 1023.0) * 100.0;

        LCD_Command(0x80); // Move to first line
        sprintf(buffer, "Temp: %.2f C", temperature);
        LCD_String(buffer);
        __delay_ms(1000);
    }
}

void ADC_Init() {
    ADCON0 = 0x41; // Turn on ADC, select channel 0
    ADCON1 = 0x80; // Right-justified result, Vref = VDD
}

unsigned int ADC_Read(unsigned char channel) {
    if (channel > 7) return 0;

    ADCON0 &= 0xC7; // Clear current channel
    ADCON0 |= (channel << 3); // Select desired channel
    __delay_ms(2); // Wait for acquisition
    GO_nDONE = 1; // Start conversion
    while (GO_nDONE); // Wait until done
    return ((ADRESH << 8) + ADRESL); // Combine 10-bit result
}

void LCD_Command(unsigned char cmd) {
    PORTC &= 0xF8; // Clear control bits
    PORTC |= (cmd >> 4); // Send high nibble
    PORTC |= 0x04; __delay_ms(2); PORTC &= ~0x04;

    PORTC &= 0xF8;
    PORTC |= (cmd & 0x0F); // Send low nibble
    PORTC |= 0x04; __delay_ms(2); PORTC &= ~0x04;
}

void LCD_Char(unsigned char data) {
    PORTC |= 0x01; // RS = 1 for data
    PORTC &= ~0x02; // RW = 0 to write
    PORTC |= (data >> 4); PORTC |= 0x04; __delay_ms(2); PORTC &= ~0x04;
    PORTC &= 0xF8;
    PORTC |= (data & 0x0F); PORTC |= 0x04; __delay_ms(2); PORTC &= ~0x04;
}

void LCD_String(const char *str) {
    while (*str) {
        LCD_Char(*str++);
    }
}

void LCD_Init() {
    __delay_ms(20);
    LCD_Command(0x02); // 4-bit mode
    LCD_Command(0x28); // 2-line display, 5x7 font
    LCD_Command(0x0C); // Display ON
    LCD_Command(0x06); // Entry mode set
    LCD_Command(0x01); // Clear display
}

6. Testing and Debugging Tips

  • If the LCD only shows blocks, check the contrast by adjusting the potentiometer and confirm the Enable and RS pins are correctly connected.
  • If no temperature reading appears or the value is always zero, check the LM35 sensor’s output with a multimeter and ensure the RA0 pin is set as an input.
  • If temperature readings flicker, try placing a small capacitor (like 100nF) between the LM35 output and ground to reduce noise.
  • Confirm the microcontroller’s oscillator is working by measuring the OSC pins with an oscilloscope if available.
  • Double-check ADC configuration and that the ADCON0 and ADCON1 settings match the hardware.

7. Project Extensions

Once the basic version is working, you can add more features:

  • Add a push button to switch between Celsius and Fahrenheit.
  • Trigger a buzzer or LED when the temperature exceeds a limit.
  • Log temperature values to EEPROM or an SD card.
  • Send temperature data wirelessly using an ESP8266 Wi-Fi module.
  • Optimize for low power by putting the microcontroller to sleep between readings.