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. Pro Mini + RFM95 and two ISR-watched buttons possible?

Pro Mini + RFM95 and two ISR-watched buttons possible?

Scheduled Pinned Locked Moved General Discussion
16 Posts 4 Posters 111 Views 4 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.
  • J Offline
    J Offline
    Joost
    wrote on last edited by
    #6

    Hi everybody,
    thanks for you help, I got as far as this:

    #include <Arduino.h>
    #include <avr/interrupt.h>
    
    #define MY_RADIO_RFM95
    #include <MySensors.h>
    
    volatile int value = 1000;
    volatile char PinRegLast, ChangedPin, PinRegister;
    volatile unsigned long last_debounce_time=0;
    
    void setup()
    {
    noInterrupts();
    PCICR |= 0b00000011; // Enables Ports B and C Pin Change Interrupts
    PCMSK1 |= 0b00000110; //PCINT9 & PCINT10 = A1 & A2
    PCMSK1 |= 0b00001000; // PCINT11
    PCIFR  = B00000001; // Reset Interruptflag
    interrupts();
    pinMode(A1, INPUT_PULLUP); pinMode(A2, INPUT_PULLUP);
    Serial.begin(38400);
    }
    
    void presentation() {}
    
    void loop()
    {
      //_wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
      Serial.print(value); Serial.print(" : ");Serial.println(PinRegister, BIN);
      sleep(160000);
    }
    
    ISR(PCINT1_vect)
    {
      if ( (long) millis() - last_debounce_time > 30)
      {
        //_wokeUpByInterrupt = 0xFE;
        PinRegister = PINC;
        ChangedPin = PinRegister ^ PinRegLast;
        PinRegLast = PinRegister;
        switch (ChangedPin){
        case (1 << PINC1):
          if (~PinRegister & (1 << PINC1)) value++;
          break;
        case (1 << PINC2):
          if (~PinRegister & (1 << PINC2)) value--;
          break;
        default:
          break;
        }
        last_debounce_time = millis();
    
      }
    }
    
    

    When I have this code without the MySensors parts (e.g. #inclue MySensors.h & sleep(..)) in it running, it kind of works plus/minus some debouncing issues. But when including MySensors and sleeping in loop(), there is rarely a reaction to pin changes and at no time a change of the variable "value", which is working without the MySensors bits in there.

    Is there something special to deal with when using sleep() together with PinChangeInterrupts?

    mfalkviddM 1 Reply Last reply
    0
    • J Joost

      Hi everybody,
      thanks for you help, I got as far as this:

      #include <Arduino.h>
      #include <avr/interrupt.h>
      
      #define MY_RADIO_RFM95
      #include <MySensors.h>
      
      volatile int value = 1000;
      volatile char PinRegLast, ChangedPin, PinRegister;
      volatile unsigned long last_debounce_time=0;
      
      void setup()
      {
      noInterrupts();
      PCICR |= 0b00000011; // Enables Ports B and C Pin Change Interrupts
      PCMSK1 |= 0b00000110; //PCINT9 & PCINT10 = A1 & A2
      PCMSK1 |= 0b00001000; // PCINT11
      PCIFR  = B00000001; // Reset Interruptflag
      interrupts();
      pinMode(A1, INPUT_PULLUP); pinMode(A2, INPUT_PULLUP);
      Serial.begin(38400);
      }
      
      void presentation() {}
      
      void loop()
      {
        //_wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
        Serial.print(value); Serial.print(" : ");Serial.println(PinRegister, BIN);
        sleep(160000);
      }
      
      ISR(PCINT1_vect)
      {
        if ( (long) millis() - last_debounce_time > 30)
        {
          //_wokeUpByInterrupt = 0xFE;
          PinRegister = PINC;
          ChangedPin = PinRegister ^ PinRegLast;
          PinRegLast = PinRegister;
          switch (ChangedPin){
          case (1 << PINC1):
            if (~PinRegister & (1 << PINC1)) value++;
            break;
          case (1 << PINC2):
            if (~PinRegister & (1 << PINC2)) value--;
            break;
          default:
            break;
          }
          last_debounce_time = millis();
      
        }
      }
      
      

      When I have this code without the MySensors parts (e.g. #inclue MySensors.h & sleep(..)) in it running, it kind of works plus/minus some debouncing issues. But when including MySensors and sleeping in loop(), there is rarely a reaction to pin changes and at no time a change of the variable "value", which is working without the MySensors bits in there.

      Is there something special to deal with when using sleep() together with PinChangeInterrupts?

      mfalkviddM Offline
      mfalkviddM Offline
      mfalkvidd
      Mod
      wrote on last edited by
      #7

      @Joost I think you need to use a custom sleep command, like at https://github.com/rikki78/MySensors/blob/master/WallRemote/WallRemote.ino#L142

      J 1 Reply Last reply
      0
      • mfalkviddM mfalkvidd

        @Joost I think you need to use a custom sleep command, like at https://github.com/rikki78/MySensors/blob/master/WallRemote/WallRemote.ino#L142

        J Offline
        J Offline
        Joost
        wrote on last edited by
        #8

        @mfalkvidd Thanks, will try that.
        TBH I had seen that already in there, but hoped it would not be needed anymore (since that sketch is from 2016).
        Would I need to power down my RFM95 radio like it is done with the NRF24?
        Don't want to loose my 9microAmp sleeping current :-)

        Will get back with results tomorrow,

        Joost

        mfalkviddM 1 Reply Last reply
        0
        • J Joost

          @mfalkvidd Thanks, will try that.
          TBH I had seen that already in there, but hoped it would not be needed anymore (since that sketch is from 2016).
          Would I need to power down my RFM95 radio like it is done with the NRF24?
          Don't want to loose my 9microAmp sleeping current :-)

          Will get back with results tomorrow,

          Joost

          mfalkviddM Offline
          mfalkviddM Offline
          mfalkvidd
          Mod
          wrote on last edited by
          #9

          @Joost yes you would need to power down the rfm95 to get low sleeping current. I think the radio will need to be reinitialized when it is powered on again but I have no experience working on this low level.

          J 1 Reply Last reply
          0
          • BearWithBeardB Offline
            BearWithBeardB Offline
            BearWithBeard
            wrote on last edited by
            #10

            A good while ago I have experimented with a multi (touch) button node which used both external and pin change interrupts and did not need to use a custom sleep function. Here is the relevant excerpt of the latest sketch which I used. As far as I remember, it was working fine.

            Note that I was using a NRF24 radio. I'm not familiar with the RFM95, but I don't think that should be a problem. (Is the IRQ pin even needed for a regular sensor node?)

            #include <Arduino.h>
            #include <avr/interrupt.h>
            
            #define MY_RADIO_RF24
            [ other MySensors stuff ]
            #include <MySensors.h>
            
            void sense()
            {
                // Handle interrupt
            }
            
            ISR(PCINT2_vect)
            {
                // Handle interrupt
            }
            
            setup () 
            {
                pinMode(2, INPUT);
                pinMode(3, INPUT);
                pinMode(4, INPUT);
                cli();
                PCICR |= 0b00000100; // Port D
                PCMSK2 |= 0b00010000; // PCINT20 (D4)
                sei();
                attachInterrupt(0, sense, RISING); // (D2)
                attachInterrupt(1, sense, RISING); // (D3)
            }
            
            void loop()
            {
                // Do stuff, send messages
            	
                sleep(0);
            }
            
            J 1 Reply Last reply
            0
            • mfalkviddM mfalkvidd

              @Joost yes you would need to power down the rfm95 to get low sleeping current. I think the radio will need to be reinitialized when it is powered on again but I have no experience working on this low level.

              J Offline
              J Offline
              Joost
              wrote on last edited by
              #11

              @mfalkvidd Will look into this tonight or tomorrow; just as a quick note for me and potentially others:
              Just found this thread with a very professional looking sketch by the author which seems a solid base to start upon:

              https://forum.mysensors.org/topic/5704/rfm95-sleep-mode/6

              Seemingly important parts from the sketch ( https://github.com/trlafleur/Soil_Moisture_Sensor_MS_R1.1-RFM95/blob/master/Soil_Moisture_Sensor_MS_R1.1-RFM95.ino ) :

              void systemSleep()
              {
                  debug1(PSTR("\n*** Going to Sleep ***\n"));
                  wait (100);
                  // put led's, radio and flash to sleep
                  // Turn off LED's
                  pinMode (MY_DEFAULT_TX_LED_PIN, INPUT);
                  pinMode (MY_DEFAULT_RX_LED_PIN, INPUT);
                  pinMode (MY_DEFAULT_ERR_LED_PIN, INPUT);
                  pinMode (OnBoardLed, INPUT); 
                  
                  // Put Flash to sleep
                  
              
                  // Put Radio and transport to Sleep
                  transportPowerDown();               // Shut down radio and MySensor transport
                  
                  interrupts();                       // make sure interrupts are on...
                  LowPower.standby();                 // SAMD sleep from LowPower systems
                  
                     //  .... we will wake up from sleeping here if triggered from an interrupt
                  interrupts();                       // make sure interrupts are on...                                      
              }
              
              /* **************** System Wake-up from Sleep ******************* */
              void systemWakeUp() 
              {                                          
                  
              //  re enable LED's if needed
              //    pinMode (MY_DEFAULT_TX_LED_PIN, OUTPUT);
              //    pinMode (MY_DEFAULT_RX_LED_PIN, OUTPUT);
              //    pinMode (MY_DEFAULT_ERR_LED_PIN, OUTPUT);
              //    pinMode (OnBoardLed, OUTPUT);  
              
                  // wake up Flash if needed
              
                  // wake up MySensor transport and Radio from Sleep
                  //transportInit();
                  hwSleep(1);                         // as MySensor had NO sleep or Watch Dog for SAMD, this will
                                                      // wake us up so that we can send and receive messages
                  while (!isTransportReady()) {       // Make sure transport is ready
                  _process(); }
              
                  interrupts();                       // make sure interrupts are on...
              }
              
              1 Reply Last reply
              0
              • BearWithBeardB BearWithBeard

                A good while ago I have experimented with a multi (touch) button node which used both external and pin change interrupts and did not need to use a custom sleep function. Here is the relevant excerpt of the latest sketch which I used. As far as I remember, it was working fine.

                Note that I was using a NRF24 radio. I'm not familiar with the RFM95, but I don't think that should be a problem. (Is the IRQ pin even needed for a regular sensor node?)

                #include <Arduino.h>
                #include <avr/interrupt.h>
                
                #define MY_RADIO_RF24
                [ other MySensors stuff ]
                #include <MySensors.h>
                
                void sense()
                {
                    // Handle interrupt
                }
                
                ISR(PCINT2_vect)
                {
                    // Handle interrupt
                }
                
                setup () 
                {
                    pinMode(2, INPUT);
                    pinMode(3, INPUT);
                    pinMode(4, INPUT);
                    cli();
                    PCICR |= 0b00000100; // Port D
                    PCMSK2 |= 0b00010000; // PCINT20 (D4)
                    sei();
                    attachInterrupt(0, sense, RISING); // (D2)
                    attachInterrupt(1, sense, RISING); // (D3)
                }
                
                void loop()
                {
                    // Do stuff, send messages
                	
                    sleep(0);
                }
                
                J Offline
                J Offline
                Joost
                wrote on last edited by
                #12

                @BearWithBeard Thanks; will look into this as well.
                Seems to me that the main difference is your sleep(0) vs. my sleep(16000), but who knows, perhaps that makes a difference. Btw, I believe Pin2 with the attached IRQ is obligatory for RFM95 radios (at least it's the default in MySensors, and I designed my PCB according to this).

                1 Reply Last reply
                0
                • J Offline
                  J Offline
                  Joost
                  wrote on last edited by
                  #13

                  Well, seems MySensors and the Low-Power lib in its latest revisions don't play nice together, bummer...

                  Getting

                  Compiling .pio/build/pro8MHzatmega328/src/main.cpp.o
                  Linking .pio/build/pro8MHzatmega328/firmware.elf
                  LowPower.cpp.o (symbol from plugin): In function `LowPowerClass::idle(period_t, adc_t, timer2_t, timer1_t, timer0_t, spi_t, usart0_t, twi_t)':
                  (.text+0x0): multiple definition of `__vector_6'
                  .pio/build/pro8MHzatmega328/src/main.cpp.o (symbol from plugin):(.text+0x0): first defined here
                  collect2: error: ld returned 1 exit status
                  *** [.pio/build/pro8MHzatmega328/firmware.elf] Error 1
                  

                  and it looks like I'm not the only one: :confused:
                  Github issue

                  electrikE 1 Reply Last reply
                  0
                  • J Joost

                    Well, seems MySensors and the Low-Power lib in its latest revisions don't play nice together, bummer...

                    Getting

                    Compiling .pio/build/pro8MHzatmega328/src/main.cpp.o
                    Linking .pio/build/pro8MHzatmega328/firmware.elf
                    LowPower.cpp.o (symbol from plugin): In function `LowPowerClass::idle(period_t, adc_t, timer2_t, timer1_t, timer0_t, spi_t, usart0_t, twi_t)':
                    (.text+0x0): multiple definition of `__vector_6'
                    .pio/build/pro8MHzatmega328/src/main.cpp.o (symbol from plugin):(.text+0x0): first defined here
                    collect2: error: ld returned 1 exit status
                    *** [.pio/build/pro8MHzatmega328/firmware.elf] Error 1
                    

                    and it looks like I'm not the only one: :confused:
                    Github issue

                    electrikE Offline
                    electrikE Offline
                    electrik
                    wrote on last edited by
                    #14

                    @Joost I've used mysensors V2 I believe...

                    1 Reply Last reply
                    0
                    • J Offline
                      J Offline
                      Joost
                      wrote on last edited by Joost
                      #15

                      *** Edit: sorry, all below seems to be wrong / misuse of sleep(); see end of linked thread from 2017

                      Some news: I found this comment https://forum.mysensors.org/post/56372 by @DavidZH who possibly described what I seem to be seeing as well (no wakeups via PinChangeInterrupt when using MySensors sleep() function as posted above) and who also posted a workaround (thanks David for posting this in 2017!!):

                      sleep(0xff,0x00, 0xff, 0x00, 0); 
                      

                      Quote: "...As soon as I change any of the parameters, the node will not wake up anymore...."

                      Now indeed my node can be woken via PinChangeInterrupts on Pin A1 and A2 and is down to some unbelievable 1microAmp in between (by means of a cheap Multimeter) with no radio/transport initialization so far.
                      So, with just preliminary testing so far this might be the solution (did not check radio transmission after interrupts for now).
                      Could someone shed some light on what these parameters do to the sleep function? Looked here of course https://www.mysensors.org/download/sensor_api_20#sleeping but couldn't make sense out of 0xFF, 0x00 .
                      Thanks everyone,

                      Joost

                      ********************** End of edit

                      1 Reply Last reply
                      0
                      • J Offline
                        J Offline
                        Joost
                        wrote on last edited by Joost
                        #16

                        PS: one downside will probably be not being able to wake up programmatically and double the node as a e.g. temperature / climate sensor, as I had in mind.

                        Sorry for the confusion above, too little sleep in the last days (at least I hope that explains it :-) )

                        Perhaps @Yveaux can help here on how to combine pin change interrupts and timer wake into a successful sleep() command? So far it looks like that would be possible with Low-Power lib, but this is not compiling in conjunction with MySensors 2.3.2.

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


                        12

                        Online

                        11.7k

                        Users

                        11.2k

                        Topics

                        113.1k

                        Posts


                        Copyright 2025 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