/*===================================================================== PIC18F4550 FLAME DETECTOR – FINAL VERSION NO 32.768 kHz CRYSTAL | LCD on RC0/RC1 | LM35 on RA0 Compiler: XC8 =====================================================================*/ #include <xc.h> #include <pic18f4550.h> // ---------- CONFIGURATION BITS ---------- #pragma config FOSC = INTOSCIO_EC // Internal 8 MHz #pragma config PLLDIV = 1 #pragma config CPUDIV = OSC1_PLL2 #pragma config USBDIV = 1 #pragma config FCMEN = OFF #pragma config IESO = OFF #pragma config PWRT = ON #pragma config BOR = ON #pragma config WDT = OFF #pragma config MCLRE = ON #pragma config LVP = OFF #pragma config PBADEN = OFF // NO T1DIG → NO CRYSTAL NEEDED #define _XTAL_FREQ 8000000UL // ---------- PIN DEFINITIONS ---------- #define LCD_RS LATCbits.LATC0 // RC0 #define LCD_EN LATCbits.LATC1 // RC1 #define LCDPORT LATB #define FLAME_SENSOR PORTDbits.RD3 #define FLAME_TRIS TRISDbits.TRISD3 #define BUZZER LATAbits.LATA5 // RA5 #define LED LATCbits.LATC2 // RC2 (was RB0) #define RESET_SW PORTAbits.RA2 #define TEST_SW PORTAbits.RA3 #define TEMP_PIN 0 // AN0 = RA0 // ---------- FUNCTION PROTOTYPES ---------- void InitLCD(void); void LCD_Display(unsigned char row, unsigned char col, const char *str); void Alarm_On(void); void Alarm_Off(void); void Heartbeat(void); void EEPROM_WriteByte(unsigned char addr, unsigned char data); unsigned char EEPROM_ReadByte(unsigned char addr); void CheckLastFire(void); unsigned int ReadTemperature(void); unsigned char ReadFlameDebounced(void); void Init_Timer1(void); void Enter_Idle(void); // ---------- GLOBAL VARIABLES ---------- volatile unsigned char wake_flag = 0; static unsigned char last_sensor_state = 1; static unsigned int stable_count = 0; /*===================================================================== MAIN =====================================================================*/ void main(void) { // ----- SYSTEM SETUP ----- OSCCON = 0x72; // 8 MHz internal CMCON = 0x07; // Disable comparators ADCON1 = 0x0E; // AN0 analog, others digital // ----- I/O CONFIGURATION ----- TRISB = 0x00; // LCD data (RB0–RB7) TRISCbits.TRISC0 = 0; // LCD RS TRISCbits.TRISC1 = 0; // LCD EN TRISCbits.TRISC2 = 0; // LED FLAME_TRIS = 1; // RD3 input TRISAbits.TRISA5 = 0; // Buzzer TRISAbits.TRISA2 = 1; // Reset switch TRISAbits.TRISA3 = 1; // Test switch // Internal pull-ups for switches WPUAbits.WPUA2 = 1; WPUAbits.WPUA3 = 1; INTCON2bits.RBPU = 0; BUZZER = 0; LED = 0; // ----- LCD & SELF-TEST ----- InitLCD(); LCD_Display(1,1,"System Booting..."); __delay_ms(1000); Alarm_On(); Alarm_Off(); LCD_Display(2,1,"Self-Test OK "); __delay_ms(1000); LCD_Display(1,1,"Flame Status: "); // ----- CHECK LAST FIRE ----- CheckLastFire(); // ----- TIMER1 (1 Hz wake) ----- Init_Timer1(); INTCONbits.PEIE = 1; INTCONbits.GIE = 1; unsigned int inactive_time = 0; while (1) { Heartbeat(); // ----- TEST MODE ----- if (TEST_SW == 0) { LCD_Display(2,1,"Running Test... "); Alarm_On(); __delay_ms(500); LCD_Display(2,1,"Test Complete "); __delay_ms(1000); continue; } // ----- FLAME DETECTION ----- if (ReadFlameDebounced()) { LCD_Display(2,1,"Flame Detected! "); unsigned char temp = (unsigned char)(ReadTemperature() * 0.488f); if (temp > 47) LCD_Display(2,1,"CRITICAL FIRE! "); Alarm_On(); EEPROM_WriteByte(0x00, 1); inactive_time = 0; } else { LCD_Display(2,1,"No Flame Found "); Alarm_Off(); if (++inactive_time >= 10) { Enter_Idle(); inactive_time = 0; } } // ----- MANUAL RESET ----- if (RESET_SW == 0) { LCD_Display(2,1,"Manual Reset... "); Alarm_Off(); __delay_ms(1000); } // ----- SENSOR FAULT ----- if (FLAME_SENSOR == last_sensor_state) stable_count++; else { stable_count = 0; last_sensor_state = FLAME_SENSOR; } if (stable_count > 600) { LCD_Display(2,1,"SENSOR FAULT! "); Alarm_On(); stable_count = 0; } __delay_ms(100); } } /*===================================================================== LCD FUNCTIONS =====================================================================*/ void SendInstruction(unsigned char cmd) { LCD_RS = 0; LCDPORT = cmd; LCD_EN = 1; __delay_us(1); LCD_EN = 0; __delay_us(40); } void SendData(unsigned char data) { LCD_RS = 1; LCDPORT = data; LCD_EN = 1; __delay_us(1); LCD_EN = 0; __delay_us(40); } void InitLCD(void) { __delay_ms(20); SendInstruction(0x30); __delay_ms(5); SendInstruction(0x30); __delay_us(100); SendInstruction(0x30); SendInstruction(0x38); // 8-bit, 2 lines SendInstruction(0x0C); // Display on SendInstruction(0x01); __delay_ms(2); SendInstruction(0x06); // Entry mode } void LCD_Display(unsigned char row, unsigned char col, const char *str) { unsigned char addr = (row == 1) ? 0x80 : 0xC0; addr += col - 1; SendInstruction(addr); while (*str) SendData(*str++); } /*===================================================================== ALARM & HEARTBEAT =====================================================================*/ void Alarm_On(void) { for (unsigned char i = 0; i < 3; ++i) { BUZZER = 1; LED = 1; __delay_ms(100); BUZZER = 0; LED = 0; __delay_ms(100); } } void Alarm_Off(void) { BUZZER = 0; LED = 0; } void Heartbeat(void) { LED = 1; __delay_ms(20); LED = 0; } /*===================================================================== EEPROM =====================================================================*/ void EEPROM_WriteByte(unsigned char addr, unsigned char data) { EEADR = addr; EEDATA = data; EECON1bits.EEPGD = 0; EECON1bits.CFGS = 0; EECON1bits.WREN = 1; INTCONbits.GIE = 0; EECON2 = 0x55; EECON2 = 0xAA; EECON1bits.WR = 1; while (PIR2bits.EEIF == 0); EECON1bits.WREN = 0; INTCONbits.GIE = 1; PIR2bits.EEIF = 0; } unsigned char EEPROM_ReadByte(unsigned char addr) { EEADR = addr; EECON1bits.EEPGD = 0; EECON1bits.CFGS = 0; EECON1bits.RD = 1; return EEDATA; } void CheckLastFire(void) { if (EEPROM_ReadByte(0x00) == 1) { LCD_Display(2,1,"Prev Fire Event!"); __delay_ms(1500); } } /*===================================================================== TEMPERATURE (LM35 on AN0) =====================================================================*/ unsigned int ReadTemperature(void) { ADCON0bits.CHS = TEMP_PIN; ADCON2 = 0b10101110; // Right justify, 12 TAD, Fosc/32 ADCON0bits.ADON = 1; __delay_us(20); ADCON0bits.GO = 1; while (ADCON0bits.GO); return (ADRESH << 8) | ADRESL; } /*===================================================================== FLAME DEBOUNCE =====================================================================*/ unsigned char ReadFlameDebounced(void) { if (FLAME_SENSOR == 0) { __delay_ms(50); if (FLAME_SENSOR == 0) return 1; } return 0; } /*===================================================================== TIMER1 – 1 Hz wake from internal 8 MHz =====================================================================*/ void Init_Timer1(void) { T1CON = 0x30; // 1:8 prescaler, internal clock TMR1H = 0x0B; // 65536 - 1000000 = 0x0B8D TMR1L = 0x8D; // ~1 second at 8MHz / 8 = 1MHz PIE1bits.TMR1IE = 1; PIR1bits.TMR1IF = 0; T1CONbits.TMR1ON = 1; } /*===================================================================== IDLE MODE – LOW POWER, AUTO SCAN =====================================================================*/ void Enter_Idle(void) { static unsigned int overflow_cnt = 0; LCD_Display(2,1,"Idle Mode Active"); OSCCONbits.IDLEN = 1; // IDLE sleep (peripherals alive) while (1) { __delay_ms(50); if (wake_flag) { wake_flag = 0; Heartbeat(); if (++overflow_cnt >= 180) { // ~3 min overflow_cnt = 0; LCD_Display(2,1,"Auto Scan Mode "); if (ReadFlameDebounced()) { LCD_Display(2,1,"FIRE DETECTED! "); Alarm_On(); EEPROM_WriteByte(0x00, 1); } else { LCD_Display(2,1,"No Fire Found "); } return; // EXIT IDLE } } } } /*===================================================================== ISR – Timer1 Overflow =====================================================================*/ void __interrupt() ISR(void) { if (PIR1bits.TMR1IF) { PIR1bits.TMR1IF = 0; wake_flag = 1; TMR1H = 0x0B; TMR1L = 0x8D; // Reload for 1 sec } }
Standard input is empty
/*=====================================================================
PIC18F4550 FLAME DETECTOR – FINAL VERSION
NO 32.768 kHz CRYSTAL | LCD on RC0/RC1 | LM35 on RA0
Compiler: XC8
=====================================================================*/
#include <xc.h>
#include <pic18f4550.h>
// ---------- CONFIGURATION BITS ----------
#pragma config FOSC = INTOSCIO_EC // Internal 8 MHz
#pragma config PLLDIV = 1
#pragma config CPUDIV = OSC1_PLL2
#pragma config USBDIV = 1
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = ON
#pragma config BOR = ON
#pragma config WDT = OFF
#pragma config MCLRE = ON
#pragma config LVP = OFF
#pragma config PBADEN = OFF
// NO T1DIG → NO CRYSTAL NEEDED
#define _XTAL_FREQ 8000000UL
// ---------- PIN DEFINITIONS ----------
#define LCD_RS LATCbits.LATC0 // RC0
#define LCD_EN LATCbits.LATC1 // RC1
#define LCDPORT LATB
#define FLAME_SENSOR PORTDbits.RD3
#define FLAME_TRIS TRISDbits.TRISD3
#define BUZZER LATAbits.LATA5 // RA5
#define LED LATCbits.LATC2 // RC2 (was RB0)
#define RESET_SW PORTAbits.RA2
#define TEST_SW PORTAbits.RA3
#define TEMP_PIN 0 // AN0 = RA0
// ---------- FUNCTION PROTOTYPES ----------
void InitLCD(void);
void LCD_Display(unsigned char row, unsigned char col, const char *str);
void Alarm_On(void);
void Alarm_Off(void);
void Heartbeat(void);
void EEPROM_WriteByte(unsigned char addr, unsigned char data);
unsigned char EEPROM_ReadByte(unsigned char addr);
void CheckLastFire(void);
unsigned int ReadTemperature(void);
unsigned char ReadFlameDebounced(void);
void Init_Timer1(void);
void Enter_Idle(void);
// ---------- GLOBAL VARIABLES ----------
volatile unsigned char wake_flag = 0;
static unsigned char last_sensor_state = 1;
static unsigned int stable_count = 0;
/*=====================================================================
MAIN
=====================================================================*/
void main(void)
{
// ----- SYSTEM SETUP -----
OSCCON = 0x72; // 8 MHz internal
CMCON = 0x07; // Disable comparators
ADCON1 = 0x0E; // AN0 analog, others digital
// ----- I/O CONFIGURATION -----
TRISB = 0x00; // LCD data (RB0–RB7)
TRISCbits.TRISC0 = 0; // LCD RS
TRISCbits.TRISC1 = 0; // LCD EN
TRISCbits.TRISC2 = 0; // LED
FLAME_TRIS = 1; // RD3 input
TRISAbits.TRISA5 = 0; // Buzzer
TRISAbits.TRISA2 = 1; // Reset switch
TRISAbits.TRISA3 = 1; // Test switch
// Internal pull-ups for switches
WPUAbits.WPUA2 = 1;
WPUAbits.WPUA3 = 1;
INTCON2bits.RBPU = 0;
BUZZER = 0; LED = 0;
// ----- LCD & SELF-TEST -----
InitLCD();
LCD_Display(1,1,"System Booting...");
__delay_ms(1000);
Alarm_On();
Alarm_Off();
LCD_Display(2,1,"Self-Test OK ");
__delay_ms(1000);
LCD_Display(1,1,"Flame Status: ");
// ----- CHECK LAST FIRE -----
CheckLastFire();
// ----- TIMER1 (1 Hz wake) -----
Init_Timer1();
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
unsigned int inactive_time = 0;
while (1)
{
Heartbeat();
// ----- TEST MODE -----
if (TEST_SW == 0) {
LCD_Display(2,1,"Running Test... ");
Alarm_On();
__delay_ms(500);
LCD_Display(2,1,"Test Complete ");
__delay_ms(1000);
continue;
}
// ----- FLAME DETECTION -----
if (ReadFlameDebounced()) {
LCD_Display(2,1,"Flame Detected! ");
unsigned char temp = (unsigned char)(ReadTemperature() * 0.488f);
if (temp > 47) LCD_Display(2,1,"CRITICAL FIRE! ");
Alarm_On();
EEPROM_WriteByte(0x00, 1);
inactive_time = 0;
}
else {
LCD_Display(2,1,"No Flame Found ");
Alarm_Off();
if (++inactive_time >= 10) {
Enter_Idle();
inactive_time = 0;
}
}
// ----- MANUAL RESET -----
if (RESET_SW == 0) {
LCD_Display(2,1,"Manual Reset... ");
Alarm_Off();
__delay_ms(1000);
}
// ----- SENSOR FAULT -----
if (FLAME_SENSOR == last_sensor_state) stable_count++;
else { stable_count = 0; last_sensor_state = FLAME_SENSOR; }
if (stable_count > 600) {
LCD_Display(2,1,"SENSOR FAULT! ");
Alarm_On();
stable_count = 0;
}
__delay_ms(100);
}
}
/*=====================================================================
LCD FUNCTIONS
=====================================================================*/
void SendInstruction(unsigned char cmd)
{
LCD_RS = 0;
LCDPORT = cmd;
LCD_EN = 1; __delay_us(1); LCD_EN = 0;
__delay_us(40);
}
void SendData(unsigned char data)
{
LCD_RS = 1;
LCDPORT = data;
LCD_EN = 1; __delay_us(1); LCD_EN = 0;
__delay_us(40);
}
void InitLCD(void)
{
__delay_ms(20);
SendInstruction(0x30); __delay_ms(5);
SendInstruction(0x30); __delay_us(100);
SendInstruction(0x30);
SendInstruction(0x38); // 8-bit, 2 lines
SendInstruction(0x0C); // Display on
SendInstruction(0x01); __delay_ms(2);
SendInstruction(0x06); // Entry mode
}
void LCD_Display(unsigned char row, unsigned char col, const char *str)
{
unsigned char addr = (row == 1) ? 0x80 : 0xC0;
addr += col - 1;
SendInstruction(addr);
while (*str) SendData(*str++);
}
/*=====================================================================
ALARM & HEARTBEAT
=====================================================================*/
void Alarm_On(void)
{
for (unsigned char i = 0; i < 3; ++i) {
BUZZER = 1; LED = 1; __delay_ms(100);
BUZZER = 0; LED = 0; __delay_ms(100);
}
}
void Alarm_Off(void) { BUZZER = 0; LED = 0; }
void Heartbeat(void) { LED = 1; __delay_ms(20); LED = 0; }
/*=====================================================================
EEPROM
=====================================================================*/
void EEPROM_WriteByte(unsigned char addr, unsigned char data)
{
EEADR = addr;
EEDATA = data;
EECON1bits.EEPGD = 0;
EECON1bits.CFGS = 0;
EECON1bits.WREN = 1;
INTCONbits.GIE = 0;
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1;
while (PIR2bits.EEIF == 0);
EECON1bits.WREN = 0;
INTCONbits.GIE = 1;
PIR2bits.EEIF = 0;
}
unsigned char EEPROM_ReadByte(unsigned char addr)
{
EEADR = addr;
EECON1bits.EEPGD = 0;
EECON1bits.CFGS = 0;
EECON1bits.RD = 1;
return EEDATA;
}
void CheckLastFire(void)
{
if (EEPROM_ReadByte(0x00) == 1) {
LCD_Display(2,1,"Prev Fire Event!");
__delay_ms(1500);
}
}
/*=====================================================================
TEMPERATURE (LM35 on AN0)
=====================================================================*/
unsigned int ReadTemperature(void)
{
ADCON0bits.CHS = TEMP_PIN;
ADCON2 = 0b10101110; // Right justify, 12 TAD, Fosc/32
ADCON0bits.ADON = 1;
__delay_us(20);
ADCON0bits.GO = 1;
while (ADCON0bits.GO);
return (ADRESH << 8) | ADRESL;
}
/*=====================================================================
FLAME DEBOUNCE
=====================================================================*/
unsigned char ReadFlameDebounced(void)
{
if (FLAME_SENSOR == 0) {
__delay_ms(50);
if (FLAME_SENSOR == 0) return 1;
}
return 0;
}
/*=====================================================================
TIMER1 – 1 Hz wake from internal 8 MHz
=====================================================================*/
void Init_Timer1(void)
{
T1CON = 0x30; // 1:8 prescaler, internal clock
TMR1H = 0x0B; // 65536 - 1000000 = 0x0B8D
TMR1L = 0x8D; // ~1 second at 8MHz / 8 = 1MHz
PIE1bits.TMR1IE = 1;
PIR1bits.TMR1IF = 0;
T1CONbits.TMR1ON = 1;
}
/*=====================================================================
IDLE MODE – LOW POWER, AUTO SCAN
=====================================================================*/
void Enter_Idle(void)
{
static unsigned int overflow_cnt = 0;
LCD_Display(2,1,"Idle Mode Active");
OSCCONbits.IDLEN = 1; // IDLE sleep (peripherals alive)
while (1) {
__delay_ms(50);
if (wake_flag) {
wake_flag = 0;
Heartbeat();
if (++overflow_cnt >= 180) { // ~3 min
overflow_cnt = 0;
LCD_Display(2,1,"Auto Scan Mode ");
if (ReadFlameDebounced()) {
LCD_Display(2,1,"FIRE DETECTED! ");
Alarm_On();
EEPROM_WriteByte(0x00, 1);
} else {
LCD_Display(2,1,"No Fire Found ");
}
return; // EXIT IDLE
}
}
SLEEP();
}
}
/*=====================================================================
ISR – Timer1 Overflow
=====================================================================*/
void __interrupt() ISR(void)
{
if (PIR1bits.TMR1IF) {
PIR1bits.TMR1IF = 0;
wake_flag = 1;
TMR1H = 0x0B;
TMR1L = 0x8D; // Reload for 1 sec
}
}