/*===================================================================== 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
    }
}