Wednesday, June 13, 2012

Detecting liquified petroleum gas (LPG)

Figaro manufactures sensors that can sniff out various kinds of gases (e.g. hydrogen, methane, carbon monoxide, etc.). I've designed a simple circuit built around the Figaro LPM2610 module which will sound an alarm if and when the level of liquified petroleum gas (LPG) in the kitchen rises above a certain predetermined level.

I knew the dimensions of the module from the datasheet but when they arrived I was still quite surprised they're tiny. Nothing against it of course. I don't want a huge daughter board sitting on my main board. The surface mount chips are all resistors. No electrostatic discharge sensitive components here at all. The thermistor is the unmarked black chip at the upper left corner. 



As per datasheet the dark blue bands on the trimpot should be lined up to ensure it's in the calibrated position.





The Figaro module contains the TGS2610 sensor and various resistors to create two voltage dividers--one for the sensor output and the other for the reference voltage. Whenever sensor voltage VOUT is equal to the temperature-compensated reference voltage this indicates the LPG concentration in the air is (theoretically) 10% of the lower explosive limit (LEL) of isobutane. As per the datasheet, butane LEL is 18,000 ppm which is equivalent to 1.8% by volume (although one website puts it at 16,000 ppm or 1.6%).

In Application Note for LP Gas Detectors using TGS2610 Figaro provides a wealth of information to get an application up and running. One of the more important tips therein is that the TGS2610 needs a warm up time to get the sensor up to its working temperature. Figaro recommends waiting 2.5 minutes. During this preheating stage the sensor's output is unreliable. In the same AN Figaro suggests circuits to detect heater as well as sensor failures.

According to the datasheet the typical current through the heater @5.0V is 56mA. Although Figaro suggests using a 3.57-ohm current sense resistor to detect heater failure, at the moment what I have are a couple of 2 ohms. 56mA x 2 ohms = 112mV. Therefore, my VDD has to be around 5.1V to obtain a voltage drop of ~5.0V across the heater. So I configured a power supply using an LM317 voltage regulator to output this value. VOUT and VREF were unity-gain buffered while the current sense voltage was gained by 20. Output of the op amps were hooked up to a Dataq DI-145 to record the values. I then performed a cold start (i.e, the module had not been powered for at least an hour to make sure it's at room temperature).

In the screenshot below you can see that while the heater is ramping up to its working temperature VOUT gradually settles down (approx 0.3 to 0.4V). This takes >100sec.

Interestingly, voltage across heater current sense resistor spikes upon power up and then exponentially settles. This inrush current suggests that the heater has a cold resistance lower than its hot resistance--just like the filament of an incandescent lamp.

Channel 1: VOUT
Ch2: VREF
Ch3: voltage across 2-ohm current sense resistor amplified 20x
Ch4: unused

Vertical: 0.5 volts/div
Horizontal: 5 sec/div
Data acquisition rate: 16 samples/sec


To get a higher resolution and better picture of what's happening during power up I increased the sample rate to the Dataq's maximum of 240/sec.

What's interesting in the image below is how VOUT stays at nearly zero volt (~20 to 30mV according to Windaq) for around 1 second before climbing. Since this is the voltage across the load resistor (RL), apparently the semiconductor sensor (RS) which is in series with RL has an extremely high resistance at room temperature which drops drops dramatically as it begins to heat up, thus behaving like a negative temperature coefficient (NTC) thermistor. However, its resistance begins to gradually increase as it reaches a certain temperature. Figaro has this short intro to the construction and operating principles of its sensors

Channel 1: VOUT
Ch2: VREF
Ch3: voltage across 2ohm current sense resistor and then amplified by a nominal gain of 20
Ch4: VDD

Vertical: 0.491 volts/div for Channels 1 to 3, 0.231 V/div for Ch4
Horizontal: 0.33 sec/div
Data acquisition rate: 240 samples/sec


Complete Working Circuit

Given that Figaro AN gives a suggestion on how to detect sensor failure, it must be that this is a distinct possibility. Since I'm using a quad op amp (MCP609) I decided to make use of what would be an unused device and connected VOUT to it and then configured it to have the same gain as the amplifier for the heater current sense resistor. Normally the output of this noninverting amplifier would be close to VDD. However, when the sensor does fail op amp output will be much closer to ground.

Schematic of a fully working LPG detector: 



Instead of using comparators as the Figaro AN suggests an MCU with ADC and/or a comparator simplifies the design and affords far more flexibility. The schematic shows the connections given a Microchip PIC12F615 8-pin microcontroller. The 1K resistors in series with the output of two op amps are only necessary because the MCU pins to which they are connected are also used for in-circuit serial programming. The resistors isolate the op amps during programming. Without them the PICkit2/3 will not be able to properly upload the firmware. A buzzer and an LED provide the alarms.

I've routed VOUT to one of the MCU's comparator inverting input pin (CIN0- / AN1) and VREF to the comparator noninverting input pin (CIN+ / AN0). This allows the firmware to use the comparator as well as the ADC to compare the two voltages. Thus, in the firmware below, I have preprocessor directives that allow the user to choose--before compilation--either ADC or voltage comparator.

To make sure the firmware works I initially used simple voltage dividers to emulate the outputs of the Figaro module:
Heater failure was simulated by simply disconnecting the 91-ohm resistor from VDD . Potentiometer permits testing the full range of VOUT from 0 to VDD.

After I was satisfied the firmware was bug-free, I removed all the resistors and plugged the LPM2610 into the breadboard and tested the circuit in the kitchen with the stove disconnected from the mains power so that the stove's spark plug like igniters wouldn't function as I turned the knobs to let gas out. During the test what got me immediately concerned is that it took what seemed a rather high concentration of gas to trigger the sensor. I had to place the breadboard really up close to the stove burner where the gas comes out to get the circuit to trigger the alarm. When the breadboard was a couple of feet away, I had to keep the stove knob depressed for longer than I felt safe (and the smell of gas was getting to me). I had a DMM hooked up to VOUT so I could monitor it. And from that feedback I felt that 10% LEL was still too high a threshold. Why not lower it to 5% or perhaps even less than that? And while at it why not include a digital display showing how much gas the sensor is detecting? Since that involves a host of mathematical acrobatics I will tackle that project in another blog entry.

One other revelation of note. LPG is usually a mix of butane and propane. At room temperature butane has a density of ~2.5 kg/m3, propane ~1.9, and air ~1.2. Since the two gases have higher densities than air (butane being twice as heavy as air) they ought to sink and crawl along the floor. And so that's where I plan to install the circuit when I finish building it. But during the test I got practically the same reading at floor level as before I started letting gas leak out. Instead, and oddly, the sensor was giving a higher reading at half a meter above the stove. It's possible that air currents at the time of the test could have carried the gas upwards. Exit velocity of the gas and its trajectory could be factors too. And there may be other parameters as well of course. Will need to reassess and determine where best to place the sensor circuit.

Firmware

Upon power up there will be a 150-second preheating period indicated by a an audible alert (a short beep once every second). During normal operation the outputs of the LPM2610 is checked four times a second--gas travels and diffuses through the air at a very low speed so there's no need to rapidly poll the sensor. In fact 4 samples/sec may even be considered too fast. During each reading heater and sensor are checked. If voltage across current sense resistor is below a set threshold then the LSb of the16-bit variable VHEAT is set (made = 1). The latest reading is in the LSb while the oldest reading is in the MSb. If VHEAT = 0xFFFF and its current state is that heater is ok, then state is now that heater is faulty. A "heater just became faulty" edge trigger is issued. On the other hand, if VHEAT = 0x0000 and and its current state is that heater is faulty then state is now that heater is ok. A "heater has just returned to normal operation" edge trigger is issued. Any VHEAT value other than 0x0000 and 0xFFFF is analogous to a bouncing switch contact and no action is taken. All bits in VHEAT are then shifted left with zero getting shifted into the LSb.

To check the integrity of the sensor the value of VOUT (gained by 20) is checked. If it dips below a set threshold then the LSb of the16-bit variable VSENSE is set (made = 1). The latest reading is in the LSb while the oldest reading is in the MSb. If VSENSE = 0xFFFF and its current state is that sensor is ok, then state is now that sensor is faulty. A "sensor just became faulty" edge trigger is issued. On the other hand, if VSENSE = 0x0000 and and its current state is that sensor is faulty then state is now that sensor is ok. A "sensor has just returned to normal operation" edge trigger is issued. Any VSENSE value other than 0x0000 and 0xFFFF is analogous to a bouncing switch contact and no action is taken. All bits in VSENSE are then shifted left with zero getting shifted into the LSb. 

If heater and sensor are both ok (but not if either is faulty), then VOUT is compared to VREF. If VOUT is > VREF then the LSb of the16-bit variable VLPG is set (made = 1). The latest reading is in the LSb while the oldest reading is in the MSb. If VLPG = 0xFFFF and its current state is that LPG is absent, then state is now that LPG is present. An "LPG present" edge trigger is issued. On the other hand, if VLPG = 0x0000 and and its current state is that LPG is present then state is now that LPG is absent. An "LPG absent" edge trigger is issued. Any VLPG value other than 0x0000 and 0xFFFF is analogous to a bouncing switch contact and no action is taken. All bits in VLPG are then shifted left with zero getting shifted into the LSb.

If either heater or sensor is faulty or if LPG is detected then the appropriate alarm is sounded. The alarm patterns for each of the conditions are as follows:

Heater fault: 100ms beep -> 500ms silence -> 100ms beep -> 4000ms silence -> repeat
Sensor fault: 100ms beep -> 500ms silence -> 100ms beep -> 500ms silence -> 100ms beep -> 4000ms silence -> repeat
LPG detection: 500ms beep -> 500ms silence -> 500ms beep -> 500ms silence ->  2000ms silence -> repeat

Should heater be faulty and for some strange reason reverts to normal, then firmware will enter an infinite loop to let the watchdog timer time out and reset the MCU. This is to force the heater to go through the preheating stage.


/*

Liquified petroleum gas (LPG) detector

When LPG level exceeds a set threshhold audible and visual alarms are activated
When Figaro LPM2610 heater or sensor fault is detected, alarms are activated

Configuration: all enabled except for code protect
               Internal oscllator @4MHz, I/0 on clock pins
               
CONFIG   :$2007 : 0x036C


ALARMS/ALERTS:

During power up delay: 25ms beeps every second for around 2.5mins
Heater fault: 100ms beep -> 500ms silence -> 100ms beep -> 4000ms silence -> repeat
Sensor fault: 100ms beep -> 500ms silence -> 100ms beep -> 500ms silence -> 100ms beep -> 4000ms silence -> repeat
LPG detection: 500ms beep -> 500ms silence -> 500ms beep -> 500ms silence ->  2000ms silence -> repeat


LEL = lower explosion limit
LEL of butane = 18,000ppm = 1.8% by volume

For the LPM2610 when Vout = Vref then LPG level is ~10% LEL

*/



// ===========================================================================================
//       Values for the following defines can be changed as needed
// ===========================================================================================

//***********************************************
// comment out the following define when done debugging
#define  debug
//***********************************************

#ifdef debug
  #define  powerupdelaysec     10
#else
  #define  powerupdelaysec     150     // number of seconds to allow heater to reach working temperature during power up reset
                                       // according to datasheet recommended preheating time is 2.5min
#endif

//***********************************************
// comment out the following define if vlpg and vref will be measured by the ADC instead of volt comaparator module
// either ADC or comparator can be used
#define  use_comparator
//***********************************************


#define  heat_resist_volt    75        // actual millivolts across current sense resistor below which is considered practically zero and therefore indication of heater failure
#define  sense_volt          50        // actual millivolts of LM2610 sensor output voltage below which is considered practically zero and therefore indication of sensor failure
#define  gain                20        // op amp gain

#define  shortbeep_ms        100       // duration of a short beep, in actual milliseconds. maximum of 524ms
#define  shortpause_ms       500       // duration of a short pause, in actual milliseconds. maximum of 524ms
#define  longpause_ms        4000      // duration of a long pause, in actual milliseconds. *minimum* of 500ms

#define  lpg_beep_ms         500       // LPG detected alarm: duration of first beep, in actual milliseconds. maximum of 524ms
#define  lpg_pause1_ms       500       // LPG detected alarm: duration of first pause, in actual milliseconds. maximum of 524ms
#define  lpg_pause2_ms       2000      // LPG detected alarm: duration of second pause, in actual milliseconds. *mininum* of 500ms

#define  reset_beep_ms       25        // power up delay alert: duration of beep, in actual milliseconds. maximum of 524ms
#define  reset_pause_ms      1000      // power up delay alert: duration of pause between beeps, in actual milliseconds. *mininum* of 500ms


// ===========================================================================================
//       !! WARNING WILL ROBINSON !! DO NOT ALTER THE DEFINES BELOW !!
// ===========================================================================================

#define  int1                bit
#define  int8                unsigned char
#define  int16               unsigned int
#define  int32               unsigned long

#define  on                  1
#define  off                 0

#define  input               1         // for TRISx
#define  output              0         // for TRISx

#define  analog              1         // for ANSELx
#define  digital             0         // for ANSELx

#define  hi                  1         // switch level high
#define  lo                  0         // switch level low


#define  Vdd                 5100                                   // Vdd voltage
#define  heater_threshold    heat_resist_volt*gain*1024/Vdd         // convert to 10-bit ADC value given ADC ref voltage = Vdd
#define  sense_threshold     sense_volt*gain*1024/Vdd               // convert to 10-bit ADC value given ADC ref voltage = Vdd

// TMR1H initial values for various alarms (Fosc = 4MHz, timer1 prescale = 1:8, TMR1L starts at zero)
#define  t1h_shortbeep       256-(shortbeep_ms*1000/(256*8) + 0.5)
#define  t1h_shortpause      256-(shortpause_ms*1000/(256*8) + 0.5)
#define  t1h_longpause       256-(500*1000/(256*8) + 0.5)
#define  longpause_cycles    longpause_ms / 500

// TMR1H initial values for LPG detection alarm (Fosc = 4MHz, timer1 prescale = 1:8, TMR1L starts at zero)
#define  t1h_lpgbeep         256-(lpg_beep_ms*1000/(256*8) + 0.5)
#define  t1h_lpgpause1       256-(lpg_pause1_ms*1000/(256*8) + 0.5)
#define  t1h_lpgpause2       256-(500*1000/(256*8) + 0.5)
#define  lpg_pause2_cycles   lpg_pause2_ms / 500

// TMR1H initial values for power-up delay alert (Fosc = 4MHz, timer1 prescale = 1:8, TMR1L starts at zero)
#define  t1h_resetbeep       256-(reset_beep_ms*1000/(256*8) + 0.5)
#define  t1h_resetpause      256-(500*1000/(256*8) + 0.5)
#define  reset_pause_cycles  reset_pause_ms / 500

#define  buz                 GPIO.f5   // buzzer
#define  tris_buz            TRISIO.f5

#define  tris_vref           TRISIO.f0 // LPM2610 Vref pin
#define  tris_vlpg           TRISIO.f1 // LPM2610 Vout pin
#define  tris_vsense         TRISIO.f2 // LPM2610 Vout pin with gain = 20
#define  tris_vheat          TRISIO.f4 // voltage across heater current sense resistor with gain = 20
                                       // GP4 is AN3

#define  an_vref             ANSEL.f0
#define  an_vlpg             ANSEL.f1
#define  an_vsense           ANSEL.f2
#define  an_vheat            ANSEL.f3

#define  ch_vref             0         // for use with ADCON0 when selecting analog channel
#define  ch_vlpg             1         // for use with ADCON0 when selecting analog channel
#define  ch_vsense           2         // for use with ADCON0 when selecting analog channel
#define  ch_vheat            3         // for use with ADCON0 when selecting analog channel

#define  cmch_vlpg           0         // for use with CMCON0 when selecting comparator channel

#define  _lpg_absent         0         // for use with variable statelpg
#define  _lpg_present        1         // for use with variable statelpg

#define  _heater_ok          0         // for use with variable stateheater
#define  _heater_fault       1         // for use with variable stateheater

#define  _sensor_ok          0         // for use with variable statesense
#define  _sensor_fault       1         // for use with variable statesense

#define  none                0         // for use with edge detect

bit stateheater;                       // status of LPM2610 heater, whether ok or faulty
bit statesense;                        // status of LPM2610 sensor, whether ok or faulty
bit statelpg;                          // status of lpg detection, whether detected or not
bit powerreset;                        // 1 = power up delay in progress; ISR needs this to determine which alarm pattern to sound

enum {heatfaultbegin = 1, heatfaultend} HEATEDGE;          // edge detect:  0 = no edge detected, 1 = heater fault has just been detected, 2 = heater fault has just been resolved
enum {sensefaultbegin = 1, sensefaultend} SENSEEDGE;       // edge detect:  0 = no edge detected, 1 = sensor fault has just been detected, 2 = sensor fault has just been resolved
enum {lpgdetectbegin = 1, lpgdetectend} LPGEDGE;           // edge detect:  0 = no edge detected, 1 = level of LPG in the air has just gone above detection threshold, 2 = level of LPG has just dropped below threshold

enum {_heatbeep1, _heatpause1, _heatbeep2, _heatpause2} STATEHEATALARM;
enum {_sensebeep1, _sensepause1, _sensebeep2, _sensepause2, _sensebeep3, _sensepause3} STATESENSEALARM;
enum {_lpgbeep1, _lpgpause1, _lpgbeep2, _lpgpause2} STATELPGALARM;
enum {_resetbeep1, _resetpause1} STATERESETALARM;

int16  VLPG = 0;             // 0x0000 = no lpg detected, 0xFFFF = lpg detected, any other value implies bouncing
int16  VHEAT = 0;            // 0x0000 = LPM2610 heater functioning, 0xFFFF = heater fault detected, any other value implies bouncing
int16  VSENSE = 0;           // 0x0000 = LPM2610 sensor functioning, 0xFFFF = sensor fault detected, any other value implies bouncing


// ===========================================================================================
//       Functions
// ===========================================================================================

void BuzzOn()
{
  buz = on;
}

void BuzzOff()
{
  buz = off;
}

// turn off buz and led and disable timer
void DisarmAlarm()
{
  T1CON.TMR1ON = 0;
  INTCON.GIE = 0;
  BuzzOff();
}

void ArmAlarm()
{
  INTCON.GIE = 1;
  TMR1L = 0;
  T1CON = 0b110001;      // prescale = 1:8, timer1 on
  PIR1.TMR1IF = 1;
}

// Figaro LPM2610 needs preheating time during which output signal is unreliable.
void PowerUpDelay()
{
  int8 i;
  
  OPTION_REG = 0b10001111;   // global weak pull ups disabled, prescaler assigned to WDT, prescale = 1:128
  STATERESETALARM = 0;
  powerreset = 1;
  ArmAlarm();
  for (i = 0; i < powerupdelaysec; i++)
  {
    asm clrwdt               // nominal WDT timeout = 18ms without prescale, given WDT prescale = 1:128 WDT = ~2sec
    Delay_ms(1000);
  }
  powerreset = 0;
  DisarmAlarm();
  OPTION_REG = 0b10000111;   // global weak pull ups disabled, prescaler assigned to timer0, prescale = 1:256
                             // WDT timeout = 18ms
}

void IniReg()
{
  GPIO = 0;
  ANSEL = 0b1011111;         // A/D Conversion Clock = Fosc/16, all four analog channels are analog
  tris_buz = output;

  WPU = 0;                   // disable individual pullups
  OPTION_REG.NOT_GPPU = 1;   // disable global pull up

  INTCON.PEIE = 1;
  PIE1.TMR1IE = 1;

  #ifdef use_comparator
  CMCON0 = 0b10000;          // comparator off, COUT internal only, COUT logic inverted, CMVin+ connected to CIN+
  CMCON0.CMCH = cmch_vlpg;   // only one comparator channel is used -- the one connected to Vout of LPM2610
  #endif
  
  stateheater = _heater_ok;
  statesense = _sensor_ok;
  statelpg = _lpg_absent;
}


int16 ADC(int8 channel)
{
  ADCON0 = channel << 2;     // shift in channel
  ADCON0.ADFM = 1;           // right justified format
  ADCON0.VCFG = 0;           // VDD as ref voltage
  ADCON0.ADON = 1;           // ADC on
  Delay_us(20);              // datasheet says ADC acquisition time typically takes 12us
  ADCON0.GO = 1;             // start ADC conversion
  while(ADCON0.GO) ;         // wait
  ADCON0.ADON = 0;           // ADC off
  return ADRESH*256 + ADRESL;
}


void ReadFigaro()
{
  HEATEDGE = none;
  SENSEEDGE = none;
  LPGEDGE = none;

  if (ADC(ch_vheat) < heater_threshold)
    ++VHEAT;

  if (VHEAT == 0xFFFF && stateheater == _heater_ok)
  {
    HEATEDGE = heatfaultbegin;
    stateheater = _heater_fault;
  }
  else if (!VHEAT && stateheater == _heater_fault)
  {
    HEATEDGE = heatfaultend;
    stateheater = _heater_ok;
  }
  VHEAT <<= 1;

  if (ADC(ch_vsense) < sense_threshold)
      ++VSENSE;

  if (VSENSE == 0xFFFF && statesense == _sensor_ok)
  {
    SENSEEDGE = sensefaultbegin;
    statesense = _sensor_fault;
  }
  else if (!VSENSE && statesense == _sensor_fault)
  {
    SENSEEDGE = sensefaultend;
    statesense = _sensor_ok;
  }
  VSENSE <<= 1;

  if (stateheater == _heater_ok && statesense == _sensor_ok);      // do not read figaro outputs if heater or sensor is faulty
  {
    // ===========================================================================================
    // ADC or comparator can be used to measure vlpg and vref
    #ifdef use_comparator
    CMCON0.CMON = 1;
    Delay_us(10);            // datasheet does not specify a settling time but it has a "mode change to output valid time" of 10us. So to be on the safe side allow some delay between comparator turn-on and reading of output
    if (CMCON0.COUT)
      ++VLPG;
    CMCON0.CMON = 0;         // comparator module consumes >60uA @5V so turn off after reading channel
    #else
    if (ADC(ch_vlpg) > ADC(ch_vref))
      ++VLPG;
    #endif
    // ===========================================================================================

    if (VLPG == 0xFFFF && statelpg == _lpg_absent)
    {
      LPGEDGE = lpgdetectbegin;
      statelpg = _lpg_present;
    }
    else if (!VLPG && statelpg == _lpg_present)
    {
      LPGEDGE = lpgdetectend;
      statelpg = _lpg_absent;
    }
    VLPG <<= 1;
  }
}


void Status()
{
  if (LPGEDGE == lpgdetectbegin)
  {
    STATELPGALARM = 0;
    ArmAlarm();
  }
  else if (LPGEDGE == lpgdetectend)
    DisarmAlarm();

  if (SENSEEDGE == sensefaultbegin)
  {
    STATESENSEALARM = 0;
    ArmAlarm();
  }
  else if (SENSEEDGE == sensefaultend)
    DisarmAlarm();

  if (HEATEDGE == heatfaultbegin)
  {
    STATEHEATALARM = 0;
    ArmAlarm();
  }
  else if (HEATEDGE == heatfaultend)
    while(1) ;     // if heater was faulty but somehow fault condition got resolved then restart the MCU
                   // let WDT timeout reset the MCU so that heater will have preheat time
} // void Status()


void interrupt()
{
  int8 COUNT;
  
  if (PIR1.TMR1IF)
  {
    PIR1.TMR1IF = 0;
    if (stateheater == _heater_fault)
    {
      switch (STATEHEATALARM)
      {
        default:
        case _heatbeep1:
          BuzzOn();
          TMR1H = t1h_shortbeep;
          STATEHEATALARM = _heatpause1;
          break;

        case _heatpause1:
          BuzzOff();
          TMR1H = t1h_shortpause;
          STATEHEATALARM = _heatbeep2;
          break;

        case _heatbeep2:
          BuzzOn();
          TMR1H = t1h_shortbeep;
          STATEHEATALARM = _heatpause2;
          COUNT = 0;
          break;

        case _heatpause2:
          BuzzOff();
          TMR1H = t1h_longpause;
          if (++COUNT >= longpause_cycles)
            STATEHEATALARM = _heatbeep1;
          break;
      } // switch (STATEHEATALARM)
    } // if (stateheater == _heater_fault)

    else if (statesense == _sensor_fault)
    {
      switch (STATESENSEALARM)
      {
        default:
        case _sensebeep1:
          BuzzOn();
          TMR1H = t1h_shortbeep;
          STATESENSEALARM = _sensepause1;
          break;

        case _sensepause1:
          BuzzOff();
          TMR1H = t1h_shortpause;
          STATESENSEALARM = _sensebeep2;
          break;

        case _sensebeep2:
          BuzzOn();
          TMR1H = t1h_shortbeep;
          STATESENSEALARM = _sensepause2;
          break;

        case _sensepause2:
          BuzzOff();
          TMR1H = t1h_shortpause;
          STATESENSEALARM = _sensebeep3;
          break;

        case _sensebeep3:
          BuzzOn();
          TMR1H = t1h_shortbeep;
          STATESENSEALARM = _sensepause3;
          COUNT = 0;
          break;

        case _sensepause3:
          BuzzOff();
          TMR1H = t1h_longpause;
          if (++COUNT >= longpause_cycles)
            STATESENSEALARM = _sensebeep1;
          break;
      } // switch (STATESENSEALARM)
    } // if (statesense == _sensor_fault)
    
    else if (statelpg == _lpg_present)
    {
      switch (STATELPGALARM)
      {
        default:
        case _lpgbeep1:
          BuzzOn();
          TMR1H = t1h_lpgbeep;
          STATELPGALARM = _lpgpause1;
          break;

        case _lpgpause1:
          BuzzOff();
          TMR1H = t1h_lpgpause1;
          STATELPGALARM = _lpgbeep2;
          break;

        case _lpgbeep2:
          BuzzOn();
          TMR1H = t1h_lpgbeep;
          STATELPGALARM = _lpgpause2;
          COUNT = 0;
          break;

        case _lpgpause2:
          BuzzOff();
          TMR1H = t1h_lpgpause2;
          if (++COUNT >= lpg_pause2_cycles)
            STATELPGALARM = _lpgbeep1;
          break;
      } // switch (STATELPGALARM)
    } // if (statelpg == _lpg_present)
    
    else if (powerreset)
    {
      switch (STATERESETALARM)
      {
        default:
        case _resetbeep1:
          BuzzOn();
          TMR1H = t1h_resetbeep;
          STATERESETALARM = _resetpause1;
          COUNT = 0;
          break;

        case _resetpause1:
          BuzzOff();
          TMR1H = t1h_resetpause;
          if (++COUNT >= reset_pause_cycles)
            STATERESETALARM = _resetbeep1;
          break;
      } // switch (STATERESETALARM)
    } // if (powerreset)
  } // if (PIR1.TMR1IF)
} // void interrupt()

void main() 
{
  int8 T0COUNT = 0;
  
  IniReg();
  PowerUpDelay();
  while(1)
  {
    asm clrwdt;
    if (INTCON.T0IF)
    {
      INTCON.T0IF = 0;
      if (++T0COUNT >= 4)    // read sensor approx every quarter second
      {
        T0COUNT = 0;
        ReadFigaro();
        Status();
      } // if (++T0COUNT >= 4)
    } // if (INTCON.T0IF)
  } // while(1)
} // void main()

4 comments:

  1. Hi,

    Its really a very good blog for LPG sensor.
    I just want some information regarding how sensor 5-pins are connected to micro-controller. Please send schematic.

    Regards.

    ReplyDelete
  2. Prevention is better than Cure - Like that Gas Detector you shared in this post was very useful. This is a perfect solution to protect our family from hazardous situations.

    ReplyDelete
  3. Wow, that's very great and useful project and most importantly thanks for sharing such an interesting update with us. Hope this will help many peoples. Good work! To buy quality gas detector choose the best gas company in the market.

    ReplyDelete
  4. The simplicity and reliability of LPG valves make them a preferred choice for residential and commercial gas installations.

    ReplyDelete