using interrupt - cant back to void loop



  • Hello,

    I'm checking some sensors in some time period:

    void loop()     
    {   
        
    
    unsigned long currentMillis_gas = millis();
    unsigned long currentMillis_temp = millis();
      
    if (currentMillis_temp - previousMillis_temp >= interval) {
    check_temp();
    check_gas();
    check_light();
    previousMillis_temp = currentMillis_temp;
    }
    }
    

    All working fine.

    But i have also PIR sensor.

    To catch PIR status I'm using interrupt

    attachInterrupt(digitalPinToInterrupt(2), check_pir, CHANGE);
    

    All works fine - except one think.
    When I call function check_pir() using interrupt, program is not able to back (after finishing function check_pir()) to running void loop.

    Its like program jump to check_pir() and stay there for ever....

    Any idea what im doing wrong ?


  • Mod

    @afick would you mond posting the code for the check_pir function? That would help a lot when trying to figure out why it is wrong.

    Also, please use thr auto-format function (ctrl/cmd+T) in the Arduino IDE. That will make the code much easier to read, for yourself and everyone else.



  • check_pir is standard function created from mysensors example (motion)

    void check_pir()
    {
     Serial.println("check  PIR");
        // Read digital motion value
      boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; 
            
      Serial.println(tripped);
      send(msg.set(tripped?"1":"0"));  // Send tripped value to gw 
       
    }```

  • Mod

    @afick that code is supposed to be in the loop. It is not supposed to be an interrupt handler. Interrupt handlers can not interact with Serial and they can not call the MySensors send function.

    See the section "About Interrupt Service Routines" at https://www.arduino.cc/en/Reference/attachInterrupt


  • Mod

    @afick please post your whole sketch first, otherwise we won't be able to help.



  • A little bit messy 😆

    /**
       The MySensors Arduino library handles the wireless radio link and protocol
       between your home built sensors/actuators and HA controller of choice.
       The sensors forms a self healing radio network with optional repeaters. Each
       repeater and gateway builds a routing tables in EEPROM which keeps track of the
       network topology allowing messages to be routed to nodes.
    
       Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
       Copyright (C) 2013-2015 Sensnology AB
       Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
    
       Documentation: http://www.mysensors.org
       Support Forum: http://forum.mysensors.org
    
       This program is free software; you can redistribute it and/or
       modify it under the terms of the GNU General Public License
       version 2 as published by the Free Software Foundation.
    
     *******************************
    
       REVISION HISTORY
       Version 1.0 - Henrik Ekblad
    
       DESCRIPTION
       Motion Sensor example using HC-SR501
       http://www.mysensors.org/build/motion
    
    */
    
    // Enable debug prints
    #define MY_DEBUG
    
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    
    #include <SPI.h>
    #include <MySensors.h>
    
    
    //pir================================================================================================================
    unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds)
    #define DIGITAL_INPUT_SENSOR 2   // The digital input you attached your motion sensor.  (Only 2 and 3 generates interrupt!)
    #define CHILD_ID 40   // Id of the sensor child
    
    // Initialize motion message
    MyMessage msg(CHILD_ID, V_TRIPPED);
    bool lasttripped;
    
    //gas================================================================================================================
    
    
    
    #define   CHILD_ID_MQ                   43
    /************************Hardware Related Macros************************************/
    #define   MQ_SENSOR_ANALOG_PIN         (4)  //define which analog input channel you are going to use
    #define         RL_VALUE                     (5)     //define the load resistance on the board, in kilo ohms
    #define         RO_CLEAN_AIR_FACTOR          (9.83)  //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO,
    //which is derived from the chart in datasheet
    /***********************Software Related Macros************************************/
    #define         CALIBARAION_SAMPLE_TIMES     (50)    //define how many samples you are going to take in the calibration phase
    #define         CALIBRATION_SAMPLE_INTERVAL  (500)   //define the time interal(in milisecond) between each samples in the
    //cablibration phase
    #define         READ_SAMPLE_INTERVAL         (50)    //define how many samples you are going to take in normal operation
    #define         READ_SAMPLE_TIMES            (5)     //define the time interal(in milisecond) between each samples in 
    //normal operation
    /**********************Application Related Macros**********************************/
    #define         GAS_LPG                      (0)
    #define         GAS_CO                       (1)
    #define         GAS_SMOKE                    (2)
    /*****************************Globals***********************************************/
    //VARIABLES
    float Ro = 10000.0;    // this has to be tuned 10K Ohm
    int val = 0;           // variable to store the value coming from the sensor
    float valMQ = 0.0;
    float lastMQ = 0.0;
    float           LPGCurve[3]  =  {2.3, 0.21, -0.47}; //two points are taken from the curve.
    //with these two points, a line is formed which is "approximately equivalent"
    //to the original curve.
    //data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59)
    float           COCurve[3]  =  {2.3, 0.72, -0.34};  //two points are taken from the curve.
    //with these two points, a line is formed which is "approximately equivalent"
    //to the original curve.
    //data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000,  0.15)
    float           SmokeCurve[3] = {2.3, 0.53, -0.44}; //two points are taken from the curve.
    //with these two points, a line is formed which is "approximately equivalent"
    //to the original curve.
    //data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22)
    
    
    MyMessage msg_gas(CHILD_ID_MQ, V_LEVEL);
    unsigned long interval_gas = 10000; // sprawdzanie czasu dla gazu
    
    //light
    #define CHILD_ID_LIGHT 44
    #define LIGHT_SENSOR_ANALOG_PIN 2
    
    
    
    MyMessage msgLight(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
    int lastLightLevel;
    
    
    
    
    //dht================================================================================================================
    #include <DHT.h>
    #define CHILD_ID_HUM 41
    #define CHILD_ID_TEMP 42
    #define HUMIDITY_SENSOR_DIGITAL_PIN 6
    DHT dht;
    float lastTemp;
    float lastHum;
    boolean metric = true;
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    unsigned long previousMillis_temp = 0;
    const long interval = 10000;
    
    
    
    
    void setup()
    {
      pinMode(DIGITAL_INPUT_SENSOR, INPUT);      // sets the motion sensor digital pin as input
      dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
    
      metric = getConfig().isMetric;
      //gas
      Ro = MQCalibration(MQ_SENSOR_ANALOG_PIN);         //Calibrating the sensor. Please make sure the sensor is in clean air
    }
    
    void presentation()  {
    
      //dht
      present(CHILD_ID_HUM, S_HUM);
      present(CHILD_ID_TEMP, S_TEMP);
    
      //pir
    
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Piwnica przejscie", "0.3");
    
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID, S_MOTION);
    
      attachInterrupt(digitalPinToInterrupt(2), check_pir, CHANGE);
    
    
      //gas
      present(CHILD_ID_MQ, S_AIR_QUALITY);
    
      //light
      present(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
    }
    
    void loop()
    {
    
    
      unsigned long currentMillis_gas = millis();
      unsigned long currentMillis_temp = millis();
    
      if (currentMillis_temp - previousMillis_temp >= interval) {
        check_temp();
        check_gas();
        check_light();
        previousMillis_temp = currentMillis_temp;
      }
    }
    
    void check_light()
    {
      int lightLevel = (1023 - analogRead(LIGHT_SENSOR_ANALOG_PIN)) / 10.23;
      Serial.println(lightLevel);
      if (lightLevel != lastLightLevel) {
        send(msgLight.set(lightLevel));
        lastLightLevel = lightLevel;
      }
    
    
    }
    
    void check_pir()
    {
      Serial.println("check  PIR");
      // Read digital motion value
      boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH;
    
      Serial.println(tripped);
      send(msg.set(tripped ? "1" : "0")); // Send tripped value to gw
    
    }
    
    
    void check_temp()
    {
      delay(dht.getMinimumSamplingPeriod());
    
      // Fetch temperatures from DHT sensor
      float temperature = dht.getTemperature();
      if (isnan(temperature)) {
        Serial.println("Failed reading temperature from DHT");
      } else if (temperature != lastTemp) {
        lastTemp = temperature;
        if (!metric) {
          temperature = dht.toFahrenheit(temperature);
        }
        send(msgTemp.set(temperature, 1));
    #ifdef MY_DEBUG
        Serial.print("T: ");
        Serial.println(temperature);
    #endif
      }
    
      // Fetch humidity from DHT sensor
      float humidity = dht.getHumidity();
      if (isnan(humidity)) {
        Serial.println("Failed reading humidity from DHT");
      } else if (humidity != lastHum) {
        lastHum = humidity;
        send(msgHum.set(humidity, 1));
    #ifdef MY_DEBUG
        Serial.print("H: ");
        Serial.println(humidity);
    #endif
      }
    }
    
    
    void check_gas()
    {
      uint16_t valMQ = MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN) / Ro, GAS_CO);
      Serial.println(val);
    
      Serial.print("LPG:");
      Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN) / Ro, GAS_LPG) );
      Serial.print( "ppm" );
      Serial.print("    ");
      Serial.print("CO:");
      Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN) / Ro, GAS_CO) );
      Serial.print( "ppm" );
      Serial.print("    ");
      Serial.print("SMOKE:");
      Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN) / Ro, GAS_SMOKE) );
      Serial.print( "ppm" );
      Serial.print("\n");
    
      if (valMQ != lastMQ) {
        send(msg_gas.set((int)ceil(valMQ)));
        lastMQ = ceil(valMQ);
      }
    }
    
    
    float MQResistanceCalculation(int raw_adc)
    {
      return ( ((float)RL_VALUE * (1023 - raw_adc) / raw_adc));
    }
    
    /***************************** MQCalibration ****************************************
      Input:   mq_pin - analog channel
      Output:  Ro of the sensor
      Remarks: This function assumes that the sensor is in clean air. It use
             MQResistanceCalculation to calculates the sensor resistance in clean air
             and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about
             10, which differs slightly between different sensors.
    ************************************************************************************/
    float MQCalibration(int mq_pin)
    {
      int i;
      float val = 0;
    
      for (i = 0; i < CALIBARAION_SAMPLE_TIMES; i++) {      //take multiple samples
        val += MQResistanceCalculation(analogRead(mq_pin));
        delay(CALIBRATION_SAMPLE_INTERVAL);
      }
      val = val / CALIBARAION_SAMPLE_TIMES;                 //calculate the average value
    
      val = val / RO_CLEAN_AIR_FACTOR;                      //divided by RO_CLEAN_AIR_FACTOR yields the Ro
      //according to the chart in the datasheet
    
      return val;
    }
    /*****************************  MQRead *********************************************
      Input:   mq_pin - analog channel
      Output:  Rs of the sensor
      Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs).
             The Rs changes as the sensor is in the different consentration of the target
             gas. The sample times and the time interval between samples could be configured
             by changing the definition of the macros.
    ************************************************************************************/
    float MQRead(int mq_pin)
    {
      int i;
      float rs = 0;
    
      for (i = 0; i < READ_SAMPLE_TIMES; i++) {
        rs += MQResistanceCalculation(analogRead(mq_pin));
        delay(READ_SAMPLE_INTERVAL);
      }
    
      rs = rs / READ_SAMPLE_TIMES;
    
      return rs;
    }
    
    /*****************************  MQGetGasPercentage **********************************
      Input:   rs_ro_ratio - Rs divided by Ro
             gas_id      - target gas type
      Output:  ppm of the target gas
      Remarks: This function passes different curves to the MQGetPercentage function which
             calculates the ppm (parts per million) of the target gas.
    ************************************************************************************/
    int MQGetGasPercentage(float rs_ro_ratio, int gas_id)
    {
      if ( gas_id == GAS_LPG ) {
        return MQGetPercentage(rs_ro_ratio, LPGCurve);
      } else if ( gas_id == GAS_CO ) {
        return MQGetPercentage(rs_ro_ratio, COCurve);
      } else if ( gas_id == GAS_SMOKE ) {
        return MQGetPercentage(rs_ro_ratio, SmokeCurve);
      }
    
      return 0;
    }
    
    /*****************************  MQGetPercentage **********************************
      Input:   rs_ro_ratio - Rs divided by Ro
             pcurve      - pointer to the curve of the target gas
      Output:  ppm of the target gas
      Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm)
             of the line could be derived if y(rs_ro_ratio) is provided. As it is a
             logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic
             value.
    ************************************************************************************/
    int  MQGetPercentage(float rs_ro_ratio, float *pcurve)
    {
      return (pow(10, ( ((log(rs_ro_ratio) - pcurve[1]) / pcurve[2]) + pcurve[0])));
    }
    

  • Mod

    @afick Sorry for my request for the full sketch -- for some reason I only saw your first post.
    Anyway, @mfalkvidd is right, you should not access the MySensors library (e.g. send messages) from an interrupt handler. That will certainly mess up things.
    What you could do is set e.g. a flag from the interrupt handler and check in the loop() function if this flag has been set. If so, send a message and clear the flag.

    E.g. (untested):

    static volatile bool pirChanged = false;
    static volatile bool pirTripped;
    
    void check_pir()
    {
      pirTripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH;
      pirChanged = true;
    }
    
    void loop()
    {
      // .. your old code ..
    
      if (pirChanged)
      {
        send(msg.set(pirTripped ? "1" : "0"));   // Send tripped value to gw
        pirChanged = false;
      }
    }
    

Log in to reply
 

283
Online

6.7k
Users

7.6k
Topics

80.4k
Posts

Looks like your connection to MySensors Forum was lost, please wait while we try to reconnect.