Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. General Discussion
  3. Multiple interrupts

Multiple interrupts

Scheduled Pinned Locked Moved General Discussion
9 Posts 5 Posters 6.1k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    kolaf
    Hero Member
    wrote on last edited by kolaf
    #1

    Hi guys,

    I previously posted a question regarding how to use multiple interrupts on my Arduino together with my RF 69 radio. The suggestion was to use pinChangeInt, but I couldn't exactly get it to work.i decided to pick this up again today, and I found this new library which appears to supersede it, called EnableInterrupt.

    https://github.com/GreyGnome/EnableInterrupt

    At first it did not work since it apparently had some kind of conflict with the radio library which relies on interrupt 0, and possibly also something in the mysensors framework related to sleeping, I guess? Anyway, since I didn't needed to handle the external interrupts, just the pinChangeInt, I was able to modify the header file to remove the clashing definitions.

    I finally have a working sensor that can cover multiple buttons and reed switches through interrupts. This means it can sleep most of the time, but still wake and act immediately if something changes :-)

    1 Reply Last reply
    1
    • AWIA Offline
      AWIA Offline
      AWI
      Hero Member
      wrote on last edited by
      #2

      Can you elaborate a little on the changes to the header file? Maybe post your sketch?

      1 Reply Last reply
      0
      • A Offline
        A Offline
        andriej
        wrote on last edited by
        #3

        Yes, please post your sketch and share more info.
        Or even more - edit the sketch available at mysensors repository, so 'water pulse sensor' is supported properly by default, for two values. :-)

        :-)

        1 Reply Last reply
        0
        • K Offline
          K Offline
          kolaf
          Hero Member
          wrote on last edited by kolaf
          #4

          I have included my sketch here. It uses the RF69 radio on a moteino platform. Since I'm lazy I have added the weather shield also from lowpowerlabs. In addition to the sensors on this I use a soil moisture sensor, and I have added support for three interrupt driven reed switches (for one door and two Windows).

          I downloaded the latest version of the EnableInterrupts library from the link in my first post and made the following changes to EnableInterrupts.h. I cannot guarantee that these changes will work for everyone, but I suspect it at least should work on the 328p versions of the process that used on the moteino and other similar arduinos

          Comment out lines 956 to 999:

          /*
          ISR(INT0_vect) {
          #ifndef NEEDFORSPEED
            (*functionPointerArrayEXTERNAL[0])();
          #else
          #if defined ARDUINO_MEGA
          #ifdef INTERRUPT_FLAG_PIN21
            INTERRUPT_FLAG_PIN21++;
          #endif
          #endif
          #if defined ARDUINO_LEONARDO
          #ifdef INTERRUPT_FLAG_PIN3
            INTERRUPT_FLAG_PIN3++;
          #endif
          #endif
          #if defined ARDUINO_328
          #ifdef INTERRUPT_FLAG_PIN2
            INTERRUPT_FLAG_PIN2++;
          #endif
          #endif
          #endif // NEEDFORSPEED
          }
          
          ISR(INT1_vect) {
          #ifndef NEEDFORSPEED
            (*functionPointerArrayEXTERNAL[1])();
          #else
          #if defined ARDUINO_MEGA
          #ifdef INTERRUPT_FLAG_PIN20
            INTERRUPT_FLAG_PIN20++;
          #endif
          #endif
          #if defined ARDUINO_LEONARDO
          #ifdef INTERRUPT_FLAG_PIN2
            INTERRUPT_FLAG_PIN2++;
          #endif
          #endif
          #if defined ARDUINO_328
          #ifdef INTERRUPT_FLAG_PIN3
            INTERRUPT_FLAG_PIN3++;
          #endif
          #endif
          #endif // NEEDFORSPEED
          }
          */
          

          Comment out the last part of the line 480:

          arduinoPin=interruptDesignator;// & ~PINCHANGEINTERRUPT;
          

          Here is the sketch. I have commented out the code related to the environmental sensors since I have not yet attached these to the board.

          #include <EnableInterrupt.h>
          
          #include <MySigningNone.h>
          #include <MyTransportRFM69.h>
          #include <MyTransportNRF24.h>
          #include <MyHwATMega328.h>
          #include <MySigningAtsha204Soft.h>
          #include <MySigningAtsha204.h>
          
          #include <MySensor.h>
          #include <SPI.h>
          #include <DHT.h>
          #include <Bounce2.h>
          #include <SFE_BMP180.h>    //get it here: https://github.com/LowPowerLab/SFE_BMP180
          #include <SI7021.h>        //get it here: https://github.com/LowPowerLab/SI7021
          #include <Wire.h>
          
          #define REPORT_INTERVAL 9000
          #define ALTITUDE 220
          #define BUTTON 3 //cannot change because of interrupt
          #define MOISTURE A4
          #define DOOR 5
          #define WINDOW_ONE 6
          #define WINDOW_TWO 7
          
          #define CHILD_TEMPERATURE 1
          #define CHILD_HUMIDITY 2
          #define CHILD_PRESSURE 3
          #define CHILD_MOISTURE 4
          #define CHILD_DOOR 5
          #define CHILD_WINDOW_ONE 6
          #define CHILD_WINDOW_TWO 7
          #define CHILD_POWER 9
          
          SI7021 sensor;
          SFE_BMP180 pressure;
          int BATTERY_SENSE_PIN  = A7;  // select the input pin for the battery sense point
          
          MyTransportRFM69 transport;
          // Hardware profile
          MyHwATMega328 hw;
          
          MySensor gw(transport, hw /*, signer*/);
          
          // Change to V_LIGHT if you use S_LIGHT in presentation below
          MyMessage temperatureMessage(CHILD_TEMPERATURE, V_TEMP);
          MyMessage humidityMessage(CHILD_HUMIDITY, V_HUM);
          MyMessage pressureMessage(CHILD_PRESSURE, V_PRESSURE);
          MyMessage moistureMessage(CHILD_MOISTURE, V_HUM);
          MyMessage doorMessage(CHILD_DOOR, V_TRIPPED);
          MyMessage windowOneMessage(CHILD_WINDOW_ONE, V_TRIPPED);
          MyMessage windowTwoMessage(CHILD_WINDOW_TWO, V_TRIPPED);
          MyMessage powerMessage(CHILD_POWER, V_VOLTAGE);
          
          unsigned long lastReport = 0, time, buttonStart = 0, buttonFinish = 0, lastCheck = 0, lastReduce = 0;
          
          void setup()
          {
            pinMode(BATTERY_SENSE_PIN, INPUT);
            pinMode(DOOR, INPUT_PULLUP);
            pinMode(WINDOW_ONE, INPUT_PULLUP);
            pinMode(WINDOW_TWO, INPUT_PULLUP);
            sensor.begin();
            pressure.begin();
            gw.begin(NULL, 7, false);
            gw.sendSketchInfo("Water control", "1.0");
            delay(250);
            gw.present(CHILD_TEMPERATURE, S_TEMP);
            delay(250);
            gw.present(CHILD_HUMIDITY, S_HUM);
            delay(250);
            gw.present(CHILD_MOISTURE, S_HUM);
            delay(250);
            gw.present(CHILD_PRESSURE, S_BARO);
            delay(250);
            gw.present(CHILD_DOOR, S_DOOR);
            delay(250);
            gw.present(CHILD_WINDOW_ONE, S_DOOR);
            delay(250);
            gw.present(CHILD_WINDOW_TWO, S_DOOR);
            delay(250);
            gw.present(CHILD_POWER, S_POWER);
            enableInterrupt(DOOR, notifyDoor, CHANGE);
            enableInterrupt(WINDOW_ONE, notifyWindowOne, CHANGE);
            enableInterrupt(WINDOW_TWO, notifyWindowTwo, CHANGE);
          }
          volatile int doorInterrupt = 0, windowOneInterrupt = 0, windowToInterrupt = 0;
          
          void notifyDoor() {
            //  gw.send(doorMessage.set(digitalRead(DOOR)));
            doorInterrupt++;
          }
          
          void notifyWindowOne() {
            //  gw.send(windowOneMessage.set(digitalRead(WINDOW_ONE)));
            windowOneInterrupt++;
          }
          
          void notifyWindowTwo() {
            //  gw.send(windowTwoMessage.set(digitalRead(WINDOW_TWO)));
            windowToInterrupt++;
          }
          //  Check if digital input has changed and send in new value
          void loop()
          {
            // Get the update value
            gw.process();
            if (doorInterrupt > 0) {
              gw.send(doorMessage.set(digitalRead(DOOR)));
              doorInterrupt = 0;
            }
            if (windowOneInterrupt > 0) {
              gw.send(windowOneMessage.set(digitalRead(WINDOW_ONE)));
              windowOneInterrupt = 0;
            }
            if (windowToInterrupt > 0) {
              gw.send(windowTwoMessage.set(digitalRead(WINDOW_TWO)));
              windowToInterrupt = 0;
            }
          
            //*************** READING BATTERY VOLTAGE *********************
            //turn MOSFET ON and read voltage, should give a valid reading
            pinMode(A3, OUTPUT);
            digitalWrite(A3, LOW);
            Serial.print("  BATT: ");
            int sensorValue = analogRead(A7);
            Serial.println(sensorValue);
            float batteryV  = sensorValue / 10 * 0.00520430107;
            int batteryPcnt = sensorValue / 100;
            gw.send(powerMessage.set(batteryV, 1));
            gw.sendBatteryLevel(batteryPcnt);
            pinMode(A3, INPUT); //put A3 in HI-Z mode (to allow mosfet gate pullup to turn it OFF)
            //*************** READING BATTERY VOLTAGE *********************
            float moistureReading = analogRead(MOISTURE);
            Serial.println(moistureReading);
            gw.send(moistureMessage.set(100 * (1024 - moistureReading) / 1024.0, 1));
          
            Serial.println("************ BMP180 *********************************");
            Serial.print("provided altitude: ");
            Serial.print(ALTITUDE, 0);
            Serial.print(" meters, ");
            Serial.print(ALTITUDE * 3.28084, 0);
            Serial.println(" feet");
            /*
              float temperature = sensor.getCelsiusHundredths() / 100;
              Serial.println("************ Si7021 *********************************");
              Serial.print("C: "); Serial.print(temperature);
              int humidity = sensor.getHumidityPercent();
              Serial.print("   H: "); Serial.print(humidity); Serial.print("%   ");
              gw.send(temperatureMessage.set(temperature, 1));
              gw.send(humidityMessage.set(humidity, 1));
              char status;
              double T, P, p0, a;
              status = pressure.startTemperature();
              if (status != 0)
              {
                // Wait for the measurement to complete:
                delay(status);
          
                // Retrieve the completed temperature measurement:
                // Note that the measurement is stored in the variable T.
                // Function returns 1 if successful, 0 if failure.
          
                status = pressure.getTemperature(T);
                if (status != 0) {
                  Serial.print("C: ");
                  Serial.print(T, 2);
                  Serial.print("    F:");
                  Serial.print((9.0 / 5.0)*T + 32.0, 2);
                  Serial.println("");
                  status = pressure.startPressure(3);
          
                  if (status != 0)
                  {
                    delay(status);
                    status = pressure.getPressure(P, T);
                    if (status != 0)
                    {
                      // Print out the measurement:
                      Serial.print("abs pressure: ");
                      Serial.print(P, 2);
                      Serial.print(" mb, ");
                      Serial.print(P * 0.0295333727, 2);
                      Serial.println(" inHg");
          
                      // The pressure sensor returns abolute pressure, which varies with altitude.
                      // To remove the effects of altitude, use the sealevel function and your current altitude.
                      // This number is commonly used in weather reports.
                      // Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m.
                      // Result: p0 = sea-level compensated pressure in mb
          
                      p0 = pressure.sealevel(P, ALTITUDE); // we're at 1655 meters (Boulder, CO)
                      Serial.print("relative (sea-level) pressure: ");
                      Serial.print(p0, 2);
                      Serial.print(" mb, ");
                      Serial.print(p0 * 0.0295333727, 2);
                      Serial.println(" inHg");
                      gw.send(pressureMessage.set(p0, 1));
                    }
                  }
                }
              }
              */
            gw.sleep(REPORT_INTERVAL);
          }```
          1 Reply Last reply
          0
          • K Offline
            K Offline
            kolaf
            Hero Member
            wrote on last edited by kolaf
            #5

            I took a quick look at the water pulse sketch. I believe that the only change required is to replace attachInterrupt with enableInterrupt and choose a pin other than 2 or 3 which are connected to the external interrupts.

            Adding multiple sensors simply requires the sensor to be connected to different pins and enabled using enableInterrupt. Make sure not to use anything else that uses interrupts inside the handler such as serial.print or anything related to the radio. It probably can't use anything related to the time, either, since sleeping breaks timing.

            1 Reply Last reply
            0
            • J Offline
              J Offline
              Jan Gatzke
              wrote on last edited by
              #6

              It would be great if those pin change interrupts could be combined with a timer interrupt. This way we could build a sensor which can collect temp / hum data and react on motion, window open etc, too. A modified version of the library could be included in the mysensors package. Should be possible, right?

              1 Reply Last reply
              0
              • K Offline
                K Offline
                kolaf
                Hero Member
                wrote on last edited by
                #7

                As far as I can tell my sketch works with timer interrupts as well as the pin interrupts.

                I have not tested this thoroughly, though.

                1 Reply Last reply
                0
                • K Offline
                  K Offline
                  kolaf
                  Hero Member
                  wrote on last edited by
                  #8

                  I just tested this, and both the pinChange interrupt and the timer interrupts work great.

                  1 Reply Last reply
                  0
                  • G Offline
                    G Offline
                    GreyGnome
                    wrote on last edited by
                    #9

                    Hello, GreyGnome here. Glad to see the library is helping you. Sorry to see you had to edit code.

                    In the next upcoming release I will include compiler directives that allow you to comment out conflicting interrupts.

                    Also, as someone else mentioned- don't use attachInterrupt() together with EnableInterrupt(). It just makes the code fatter, and EnableInterrupt() can already cover both interrupt types; eg on an Arduino Uno:

                    enableInterrupt(2, myFunkyExternalInterruptFunction, LOW);
                    enableInterrupt(10, myExcellentPinChangeInterruptFunction, CHANGE);

                    ...note that enableInterrupt will use External interrupts on pin 2 by default. You can force it to use pin change interrupts:

                    enableInterrupt(2 | PINCHANGEINTERRUPT, myFunkyExternalInterruptFunction, FALLING);

                    ...in which case, "myFunkyExternalInterruptFunction" is something of a misnomer. ALSO NOTE: Pin Change Interrupts do not support the LOW state!

                    1 Reply Last reply
                    0
                    Reply
                    • Reply as topic
                    Log in to reply
                    • Oldest to Newest
                    • Newest to Oldest
                    • Most Votes


                    10

                    Online

                    11.7k

                    Users

                    11.2k

                    Topics

                    113.0k

                    Posts


                    Copyright 2019 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                    • Login

                    • Don't have an account? Register

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • MySensors
                    • OpenHardware.io
                    • Categories
                    • Recent
                    • Tags
                    • Popular