fork download
  1. /*=====================================================================
  2.   PIC18F4550 FLAME DETECTOR – FINAL VERSION
  3.   NO 32.768 kHz CRYSTAL | LCD on RC0/RC1 | LM35 on RA0
  4.   Compiler: XC8
  5. =====================================================================*/
  6.  
  7. #include <xc.h>
  8. #include <pic18f4550.h>
  9.  
  10. // ---------- CONFIGURATION BITS ----------
  11. #pragma config FOSC = INTOSCIO_EC // Internal 8 MHz
  12. #pragma config PLLDIV = 1
  13. #pragma config CPUDIV = OSC1_PLL2
  14. #pragma config USBDIV = 1
  15. #pragma config FCMEN = OFF
  16. #pragma config IESO = OFF
  17. #pragma config PWRT = ON
  18. #pragma config BOR = ON
  19. #pragma config WDT = OFF
  20. #pragma config MCLRE = ON
  21. #pragma config LVP = OFF
  22. #pragma config PBADEN = OFF
  23. // NO T1DIG → NO CRYSTAL NEEDED
  24.  
  25. #define _XTAL_FREQ 8000000UL
  26.  
  27. // ---------- PIN DEFINITIONS ----------
  28. #define LCD_RS LATCbits.LATC0 // RC0
  29. #define LCD_EN LATCbits.LATC1 // RC1
  30. #define LCDPORT LATB
  31. #define FLAME_SENSOR PORTDbits.RD3
  32. #define FLAME_TRIS TRISDbits.TRISD3
  33. #define BUZZER LATAbits.LATA5 // RA5
  34. #define LED LATCbits.LATC2 // RC2 (was RB0)
  35. #define RESET_SW PORTAbits.RA2
  36. #define TEST_SW PORTAbits.RA3
  37. #define TEMP_PIN 0 // AN0 = RA0
  38.  
  39. // ---------- FUNCTION PROTOTYPES ----------
  40. void InitLCD(void);
  41. void LCD_Display(unsigned char row, unsigned char col, const char *str);
  42. void Alarm_On(void);
  43. void Alarm_Off(void);
  44. void Heartbeat(void);
  45. void EEPROM_WriteByte(unsigned char addr, unsigned char data);
  46. unsigned char EEPROM_ReadByte(unsigned char addr);
  47. void CheckLastFire(void);
  48. unsigned int ReadTemperature(void);
  49. unsigned char ReadFlameDebounced(void);
  50. void Init_Timer1(void);
  51. void Enter_Idle(void);
  52.  
  53. // ---------- GLOBAL VARIABLES ----------
  54. volatile unsigned char wake_flag = 0;
  55. static unsigned char last_sensor_state = 1;
  56. static unsigned int stable_count = 0;
  57.  
  58. /*=====================================================================
  59.   MAIN
  60. =====================================================================*/
  61. void main(void)
  62. {
  63. // ----- SYSTEM SETUP -----
  64. OSCCON = 0x72; // 8 MHz internal
  65. CMCON = 0x07; // Disable comparators
  66. ADCON1 = 0x0E; // AN0 analog, others digital
  67.  
  68. // ----- I/O CONFIGURATION -----
  69. TRISB = 0x00; // LCD data (RB0–RB7)
  70. TRISCbits.TRISC0 = 0; // LCD RS
  71. TRISCbits.TRISC1 = 0; // LCD EN
  72. TRISCbits.TRISC2 = 0; // LED
  73. FLAME_TRIS = 1; // RD3 input
  74. TRISAbits.TRISA5 = 0; // Buzzer
  75. TRISAbits.TRISA2 = 1; // Reset switch
  76. TRISAbits.TRISA3 = 1; // Test switch
  77.  
  78. // Internal pull-ups for switches
  79. WPUAbits.WPUA2 = 1;
  80. WPUAbits.WPUA3 = 1;
  81. INTCON2bits.RBPU = 0;
  82.  
  83. BUZZER = 0; LED = 0;
  84.  
  85. // ----- LCD & SELF-TEST -----
  86. InitLCD();
  87. LCD_Display(1,1,"System Booting...");
  88. __delay_ms(1000);
  89. Alarm_On();
  90. Alarm_Off();
  91. LCD_Display(2,1,"Self-Test OK ");
  92. __delay_ms(1000);
  93. LCD_Display(1,1,"Flame Status: ");
  94.  
  95. // ----- CHECK LAST FIRE -----
  96. CheckLastFire();
  97.  
  98. // ----- TIMER1 (1 Hz wake) -----
  99. Init_Timer1();
  100. INTCONbits.PEIE = 1;
  101. INTCONbits.GIE = 1;
  102.  
  103. unsigned int inactive_time = 0;
  104.  
  105. while (1)
  106. {
  107. Heartbeat();
  108.  
  109. // ----- TEST MODE -----
  110. if (TEST_SW == 0) {
  111. LCD_Display(2,1,"Running Test... ");
  112. Alarm_On();
  113. __delay_ms(500);
  114. LCD_Display(2,1,"Test Complete ");
  115. __delay_ms(1000);
  116. continue;
  117. }
  118.  
  119. // ----- FLAME DETECTION -----
  120. if (ReadFlameDebounced()) {
  121. LCD_Display(2,1,"Flame Detected! ");
  122. unsigned char temp = (unsigned char)(ReadTemperature() * 0.488f);
  123. if (temp > 47) LCD_Display(2,1,"CRITICAL FIRE! ");
  124. Alarm_On();
  125. EEPROM_WriteByte(0x00, 1);
  126. inactive_time = 0;
  127. }
  128. else {
  129. LCD_Display(2,1,"No Flame Found ");
  130. Alarm_Off();
  131. if (++inactive_time >= 10) {
  132. Enter_Idle();
  133. inactive_time = 0;
  134. }
  135. }
  136.  
  137. // ----- MANUAL RESET -----
  138. if (RESET_SW == 0) {
  139. LCD_Display(2,1,"Manual Reset... ");
  140. Alarm_Off();
  141. __delay_ms(1000);
  142. }
  143.  
  144. // ----- SENSOR FAULT -----
  145. if (FLAME_SENSOR == last_sensor_state) stable_count++;
  146. else { stable_count = 0; last_sensor_state = FLAME_SENSOR; }
  147.  
  148. if (stable_count > 600) {
  149. LCD_Display(2,1,"SENSOR FAULT! ");
  150. Alarm_On();
  151. stable_count = 0;
  152. }
  153.  
  154. __delay_ms(100);
  155. }
  156. }
  157.  
  158. /*=====================================================================
  159.   LCD FUNCTIONS
  160. =====================================================================*/
  161. void SendInstruction(unsigned char cmd)
  162. {
  163. LCD_RS = 0;
  164. LCDPORT = cmd;
  165. LCD_EN = 1; __delay_us(1); LCD_EN = 0;
  166. __delay_us(40);
  167. }
  168. void SendData(unsigned char data)
  169. {
  170. LCD_RS = 1;
  171. LCDPORT = data;
  172. LCD_EN = 1; __delay_us(1); LCD_EN = 0;
  173. __delay_us(40);
  174. }
  175. void InitLCD(void)
  176. {
  177. __delay_ms(20);
  178. SendInstruction(0x30); __delay_ms(5);
  179. SendInstruction(0x30); __delay_us(100);
  180. SendInstruction(0x30);
  181. SendInstruction(0x38); // 8-bit, 2 lines
  182. SendInstruction(0x0C); // Display on
  183. SendInstruction(0x01); __delay_ms(2);
  184. SendInstruction(0x06); // Entry mode
  185. }
  186. void LCD_Display(unsigned char row, unsigned char col, const char *str)
  187. {
  188. unsigned char addr = (row == 1) ? 0x80 : 0xC0;
  189. addr += col - 1;
  190. SendInstruction(addr);
  191. while (*str) SendData(*str++);
  192. }
  193.  
  194. /*=====================================================================
  195.   ALARM & HEARTBEAT
  196. =====================================================================*/
  197. void Alarm_On(void)
  198. {
  199. for (unsigned char i = 0; i < 3; ++i) {
  200. BUZZER = 1; LED = 1; __delay_ms(100);
  201. BUZZER = 0; LED = 0; __delay_ms(100);
  202. }
  203. }
  204. void Alarm_Off(void) { BUZZER = 0; LED = 0; }
  205. void Heartbeat(void) { LED = 1; __delay_ms(20); LED = 0; }
  206.  
  207. /*=====================================================================
  208.   EEPROM
  209. =====================================================================*/
  210. void EEPROM_WriteByte(unsigned char addr, unsigned char data)
  211. {
  212. EEADR = addr;
  213. EEDATA = data;
  214. EECON1bits.EEPGD = 0;
  215. EECON1bits.CFGS = 0;
  216. EECON1bits.WREN = 1;
  217. INTCONbits.GIE = 0;
  218. EECON2 = 0x55;
  219. EECON2 = 0xAA;
  220. EECON1bits.WR = 1;
  221. while (PIR2bits.EEIF == 0);
  222. EECON1bits.WREN = 0;
  223. INTCONbits.GIE = 1;
  224. PIR2bits.EEIF = 0;
  225. }
  226. unsigned char EEPROM_ReadByte(unsigned char addr)
  227. {
  228. EEADR = addr;
  229. EECON1bits.EEPGD = 0;
  230. EECON1bits.CFGS = 0;
  231. EECON1bits.RD = 1;
  232. return EEDATA;
  233. }
  234. void CheckLastFire(void)
  235. {
  236. if (EEPROM_ReadByte(0x00) == 1) {
  237. LCD_Display(2,1,"Prev Fire Event!");
  238. __delay_ms(1500);
  239. }
  240. }
  241.  
  242. /*=====================================================================
  243.   TEMPERATURE (LM35 on AN0)
  244. =====================================================================*/
  245. unsigned int ReadTemperature(void)
  246. {
  247. ADCON0bits.CHS = TEMP_PIN;
  248. ADCON2 = 0b10101110; // Right justify, 12 TAD, Fosc/32
  249. ADCON0bits.ADON = 1;
  250. __delay_us(20);
  251. ADCON0bits.GO = 1;
  252. while (ADCON0bits.GO);
  253. return (ADRESH << 8) | ADRESL;
  254. }
  255.  
  256. /*=====================================================================
  257.   FLAME DEBOUNCE
  258. =====================================================================*/
  259. unsigned char ReadFlameDebounced(void)
  260. {
  261. if (FLAME_SENSOR == 0) {
  262. __delay_ms(50);
  263. if (FLAME_SENSOR == 0) return 1;
  264. }
  265. return 0;
  266. }
  267.  
  268. /*=====================================================================
  269.   TIMER1 – 1 Hz wake from internal 8 MHz
  270. =====================================================================*/
  271. void Init_Timer1(void)
  272. {
  273. T1CON = 0x30; // 1:8 prescaler, internal clock
  274. TMR1H = 0x0B; // 65536 - 1000000 = 0x0B8D
  275. TMR1L = 0x8D; // ~1 second at 8MHz / 8 = 1MHz
  276. PIE1bits.TMR1IE = 1;
  277. PIR1bits.TMR1IF = 0;
  278. T1CONbits.TMR1ON = 1;
  279. }
  280.  
  281. /*=====================================================================
  282.   IDLE MODE – LOW POWER, AUTO SCAN
  283. =====================================================================*/
  284. void Enter_Idle(void)
  285. {
  286. static unsigned int overflow_cnt = 0;
  287. LCD_Display(2,1,"Idle Mode Active");
  288.  
  289. OSCCONbits.IDLEN = 1; // IDLE sleep (peripherals alive)
  290.  
  291. while (1) {
  292. __delay_ms(50);
  293. if (wake_flag) {
  294. wake_flag = 0;
  295. Heartbeat();
  296.  
  297. if (++overflow_cnt >= 180) { // ~3 min
  298. overflow_cnt = 0;
  299. LCD_Display(2,1,"Auto Scan Mode ");
  300. if (ReadFlameDebounced()) {
  301. LCD_Display(2,1,"FIRE DETECTED! ");
  302. Alarm_On();
  303. EEPROM_WriteByte(0x00, 1);
  304. } else {
  305. LCD_Display(2,1,"No Fire Found ");
  306. }
  307. return; // EXIT IDLE
  308. }
  309. }
  310. SLEEP();
  311. }
  312. }
  313.  
  314. /*=====================================================================
  315.   ISR – Timer1 Overflow
  316. =====================================================================*/
  317. void __interrupt() ISR(void)
  318. {
  319. if (PIR1bits.TMR1IF) {
  320. PIR1bits.TMR1IF = 0;
  321. wake_flag = 1;
  322. TMR1H = 0x0B;
  323. TMR1L = 0x8D; // Reload for 1 sec
  324. }
  325. }
Success #stdin #stdout 0.03s 25672KB
stdin
Standard input is empty
stdout
/*=====================================================================
  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
    }
}