
Automatic Temperature-Controlled Fan using PIC Microcontroller
Introduction
This project uses a PIC16F877A microcontroller to control a fan based on temperature readings. The temperature is monitored using a LM35 temperature sensor, and the fan speed is adjusted automatically. This type of system is commonly used in home automation, industrial temperature control, and smart cooling solutions.
Learning Objectives
By completing this project, you will learn:
- How to interface a temperature sensor (LM35) with a PIC microcontroller.
- How to generate PWM (Pulse Width Modulation) signals for speed control.
- How to convert ADC (Analog-to-Digital Conversion) values to real-world temperature.
- Basics of fan speed control using PWM.
- Debugging and calibration techniques for sensor-based projects.
Tools and Components
Hardware
- PIC16F877A Microcontroller
- LM35 Temperature Sensor
- 12V DC Fan (or a 5V small fan for testing)
- L293D Motor Driver (for driving the fan)
- 16×2 LCD Display (optional, for displaying temperature)
- Potentiometer (for LCD contrast control)
- Breadboard and jumper wires
- Power supply (5V and 12V)
- Resistors and capacitors (as per circuit requirements)
Software
- MPLAB X IDE
- XC8 Compiler
- PICkit 3/4 Programmer
Background/Definitions
- PIC16F877A: A popular 8-bit microcontroller with 10-bit ADC, PWM, and plenty of I/O ports.
- LM35: A temperature sensor that provides a linear output of 10mV per degree Celsius. For example, at 25°C, the output voltage is 250mV.
- PWM (Pulse Width Modulation): Used to control the speed of a DC fan by varying the duty cycle of the control signal.
Circuit Diagram
Let me describe the circuit connections:
- LM35 Sensor:
- VCC → +5V
- GND → GND
- Output → AN0 (RA0 pin of PIC16F877A)
- Fan Control (via L293D):
- Enable Pin (PWM input) → CCP1 (RC2 pin of PIC16F877A)
- Input Pins → RB0 and RB1
- Fan Power Supply → 12V
- LCD Display (optional):
- RS, RW, E → Connected to RB2, RB3, RB4
- Data Pins → RD4 to RD7
Step-by-Step Guide
1. Configure the ADC for Temperature Reading
- Configure the ADC module of PIC16F877A to read the analog voltage from the LM35.
- Convert the ADC value to the corresponding temperature in Celsius.
2. Generate PWM for Fan Speed Control
- Use CCP1 (Capture/Compare/PWM) module to generate PWM signals.
- Adjust the duty cycle based on the temperature reading.
3. Display the Temperature on LCD (Optional)
- Use a 16×2 LCD to show the temperature in real time.
4. Write the Code
Below is the annotated code for the project.
Code with Comments
#include <xc.h>
#define _XTAL_FREQ 20000000 // Define the system clock frequency (20MHz)
// Configuration Bits
#pragma config FOSC = HS // High-Speed Oscillator
#pragma config WDTE = OFF // Watchdog Timer Disabled
#pragma config PWRTE = ON // Power-up Timer Enabled
#pragma config BOREN = ON // Brown-out Reset Enabled
#pragma config LVP = OFF // Low Voltage Programming Disabled
#pragma config CPD = OFF // Code Protection Disabled
#pragma config WRT = OFF // Flash Program Memory Write Protection Disabled
#pragma config CP = OFF // Code Protection Disabled
// Function Prototypes
void ADC_Init(); // Initialize ADC module
unsigned int ADC_Read(unsigned char channel); // Read ADC value
void PWM_Init(); // Initialize PWM module
void Set_PWM_Duty(unsigned int duty); // Set PWM duty cycle
void main() {
unsigned int adc_value;
float temperature;
// Initialization
ADC_Init();
PWM_Init();
while(1) {
// Read the temperature from LM35
adc_value = ADC_Read(0); // Read from channel 0 (AN0)
temperature = (adc_value * 5.0 / 1023.0) * 100.0; // Convert ADC value to temperature
// Adjust fan speed based on temperature
if (temperature < 30) {
Set_PWM_Duty(0); // Fan off
} else if (temperature >= 30 && temperature <= 40) {
Set_PWM_Duty(512); // 50% speed
} else {
Set_PWM_Duty(1023); // Full speed
}
__delay_ms(500); // Wait for 500 ms
}
}
// Initialize the ADC module
void ADC_Init() {
ADCON0 = 0x41; // ADC enabled, channel 0 selected
ADCON1 = 0x80; // Right justified, Fosc/32
}
// Read ADC value from specified channel
unsigned int ADC_Read(unsigned char channel) {
ADCON0 &= 0xC5; // Clear previous channel selection
ADCON0 |= (channel << 3); // Select new channel
__delay_ms(2); // Acquisition time
GO_nDONE = 1; // Start conversion
while(GO_nDONE); // Wait for conversion to complete
return ((ADRESH << 8) + ADRESL); // Return result
}
// Initialize the PWM module
void PWM_Init() {
TRISC2 = 0; // Set RC2 as output
PR2 = 255; // Set PWM period
CCP1CON = 0x0C; // Configure CCP1 as PWM mode
T2CON = 0x04; // Timer2 on, prescaler 1:1
}
// Set PWM duty cycle (0-1023)
void Set_PWM_Duty(unsigned int duty) {
if (duty < 1024) {
CCPR1L = duty >> 2; // Set the 8 most significant bits
CCP1CON &= 0xCF;
CCP1CON |= ((duty & 0x03) << 4); // Set the 2 least significant bits
}
}
Testing and Debugging Tips
- Check Power Supply: Ensure the PIC and sensor receive a stable 5V supply. The fan may need a separate 12V supply.
- Verify ADC Readings: Use a multimeter to measure the LM35 output and compare it to the ADC result.
- PWM Calibration: If the fan speed control is inconsistent, adjust the PWM frequency by changing the
PR2register. - LCD Display Issues: If the display is blank, check the contrast pin (connected to a potentiometer) and wiring.
- Common Code Errors: Ensure correct ADC channel selection and that the
GO_nDONEbit is properly monitored.
Extensions and Advanced Modifications
- Add a Fan Speed Display: Use the LCD to show the current fan speed percentage.
- Use an Interrupt for ADC Reading: Improve efficiency by using ADC interrupts instead of polling.
- Add Overheat Protection: Turn off the system if the temperature exceeds a critical value (e.g., 70°C).
- Bluetooth Monitoring: Add a Bluetooth module to monitor temperature and control the fan from a smartphone.
Conclusion
This project offers practical experience in interfacing sensors, controlling actuators using PWM, and working with PIC microcontrollers. By understanding how temperature affects the fan speed, you’ve built a smart system with real-world applications. Keep experimenting with advanced features and improvements!