
Project: Temperature-Controlled Fan using PIC16F877A
🧠 1. Introduction
In this project, we’ll design a Temperature-Controlled Fan using a PIC16F877A microcontroller. The system monitors temperature via an LM35 temperature sensor and automatically adjusts the fan speed based on the detected temperature using PWM (Pulse Width Modulation).
Real-world applications:
- Smart cooling systems
- Greenhouses
- Computer cooling
- Industrial equipment cooling
🎯 2. Learning Objectives
By completing this project, you will:
- Understand ADC (Analog-to-Digital Conversion) in PIC microcontrollers.
- Implement PWM to control motor speed.
- Read data from a temperature sensor.
- Integrate sensors and actuators.
- Develop structured, well-commented code.
🛠️ 3. Tools and Components
Hardware:
- PIC16F877A microcontroller
- LM35 Temperature Sensor
- 12V DC Fan
- MOSFET (e.g., IRF540) for switching
- 16×2 LCD Display (optional)
- Resistors (1kΩ, 10kΩ)
- Potentiometer (for LCD contrast)
- Breadboard and connecting wires
- 5V Regulated Power Supply
Software:
- MPLAB X IDE
- XC8 Compiler
- PICKit3 or another PIC programmer
📚 4. Background/Definitions
- ADC (Analog-to-Digital Converter): Converts analog signals like temperature into a digital form.
- PWM (Pulse Width Modulation): Simulates analog output using digital pulses to control devices like motors.
- LM35: A linear temperature sensor providing 10mV per °C.
🛠️ 5. Step-by-Step Guide
Circuit Wiring Overview
LM35 Temperature Sensor Connections:
- Vcc pin connects to +5V.
- GND pin connects to GND.
- Output pin connects to RA0 (AN0) of PIC16F877A.
Fan and MOSFET Connections:
- Fan positive terminal connects to 12V supply.
- Fan negative terminal connects to Drain of MOSFET.
- MOSFET Source connects to ground.
- MOSFET Gate connects to CCP1 PWM output (RC2).
LCD Connections (optional for displaying temperature):
- LCD RS pin connects to RC0.
- LCD RW pin connects to RC1.
- LCD E pin connects to RC2.
- LCD Data pins (D4 to D7) connect to RD4 to RD7.
- Potentiometer connects for LCD contrast control.
PIC Configuration Notes:
- Use a 4MHz crystal oscillator.
- Enable ADC module for analog input.
- Configure CCP1 module for PWM output.
Source Code (With Full Comments)
// Configuration bits
#pragma config FOSC = HS // High-Speed Oscillator
#pragma config WDTE = OFF // Watchdog Timer Disable
#pragma config PWRTE = ON // Power-up Timer Enable
#pragma config BOREN = ON // Brown-out Reset Enable
#pragma config LVP = OFF // Low-Voltage Programming Disable
#pragma config CPD = OFF // Data EEPROM Memory Code Protection
#pragma config WRT = OFF // Flash Program Memory Write Protection
#pragma config CP = OFF // Flash Program Memory Code Protection
#include <xc.h>
#define _XTAL_FREQ 4000000 // Define crystal frequency
void ADC_Init();
unsigned int ADC_Read(unsigned char channel);
void PWM_Init();
void LCD_Init();
void LCD_Command(char cmd);
void LCD_Char(char data);
void LCD_String(const char *str);
void LCD_Clear();
void main() {
unsigned int temp_raw;
float temperature;
int duty_cycle;
ADC_Init();
PWM_Init();
LCD_Init();
while(1) {
temp_raw = ADC_Read(0);
temperature = (temp_raw * 5.0 / 1023.0) * 100; // Convert ADC to Celsius
LCD_Command(0x80);
LCD_String("Temp: ");
char buffer[5];
sprintf(buffer, "%2.1f", temperature);
LCD_String(buffer);
LCD_String("C");
// Set fan speed based on temperature
if (temperature < 30)
duty_cycle = 0;
else if (temperature >= 30 && temperature < 40)
duty_cycle = 30;
else if (temperature >= 40 && temperature < 50)
duty_cycle = 60;
else
duty_cycle = 90;
CCPR1L = (duty_cycle * 4) / 100;
__delay_ms(500);
LCD_Clear();
}
}
void ADC_Init() {
ADCON0 = 0x41;
ADCON1 = 0x80;
}
unsigned int ADC_Read(unsigned char channel) {
if(channel > 7) return 0;
ADCON0 &= 0x11000101;
ADCON0 |= channel<<3;
__delay_us(30);
GO_nDONE = 1;
while(GO_nDONE);
return ((ADRESH<<8)+ADRESL);
}
void PWM_Init() {
PR2 = 0xFF;
CCP1CON = 0x0C;
T2CON = 0x04;
}
void LCD_Init() {
TRISD = 0x00;
TRISC = 0x00;
LCD_Command(0x02);
LCD_Command(0x28);
LCD_Command(0x0C);
LCD_Command(0x06);
LCD_Command(0x01);
}
void LCD_Command(char cmd) {
PORTD = (cmd & 0xF0);
RC0 = 0; RC1 = 0; RC2 = 1;
__delay_ms(1);
RC2 = 0;
PORTD = ((cmd<<4) & 0xF0);
RC0 = 0; RC1 = 0; RC2 = 1;
__delay_ms(1);
RC2 = 0;
}
void LCD_Char(char data) {
PORTD = (data & 0xF0);
RC0 = 1; RC1 = 0; RC2 = 1;
__delay_ms(1);
RC2 = 0;
PORTD = ((data<<4) & 0xF0);
RC0 = 1; RC1 = 0; RC2 = 1;
__delay_ms(1);
RC2 = 0;
}
void LCD_String(const char *str) {
while(*str) {
LCD_Char(*str++);
}
}
void LCD_Clear() {
LCD_Command(0x01);
__delay_ms(2);
}
🔍 6. Testing and Debugging Tips
If Fan is Not Moving:
- Verify PWM signal using an oscilloscope or LED blinking technique.
- Check MOSFET gate-source voltage.
- Confirm correct motor voltage supply.
If LCD Displays Garbage:
- Recheck LCD wiring.
- Confirm timing delays are sufficient.
- Double-check contrast settings via potentiometer.
Incorrect Temperature Readings:
- Ensure proper LM35 wiring (especially Vout to RA0).
- Verify correct ADC reference voltage (should be stable 5V).
Fan Speed Irregularity:
- Check if Timer2 is correctly configured.
- Validate duty cycle calculations.
🌟 7. Extensions
- Implement a PID Controller for more accurate fan speed control.
- Store temperature history into EEPROM for later analysis.
- Add Bluetooth (HC-05 module) to monitor via mobile phone.
- Manage multiple fans in different zones based on sensor inputs.
- Replace LCD with an OLED display for better readability and compact design.
Would you also like me to create a schematic drawing or simulate this project step-by-step next? 🚀