POWER CONSUMPTION AND RFM69HW - HELP NEEDED

Started by ABL, May 27, 2015, 05:48:20 PM

Felix

Quote from: ABL on May 28, 2015, 04:31:29 PM
yes the hardware is functional, it's the code causing the problems, the strange thing is that the motionMOTE sketch is causing the exact same problem as the code i posted earlier...and it should work
How can you verify that without using an actual PIR motion sensor?
The sketch was not coded for a shock sensor specifically but for a motion PIR sensor which creates 1 HIGH pulse every few seconds if there's movement, so we only made assumptions here about your sensor. Don't expect the sketch to work if you just load it on your Moteino and then play with it in your hand. Static will cause D3 to go HIGH and create interrupts. You need a real PIR sensor to have it work properly. I don't know how your shock sensor works in reality, what the output is and how it responds to shocks. It may require different code to have it work as expected.

ABL

#16
Hi Felix & Tom

i have tried to change the code, and this seems to work, except from detachInterrupt(MOTIONPIN) i don't know if i should use a different command.. see line 3 in the void motionIRQ)

#define NODEID        2    //unique for each node on same network
#define NETWORKID     100  //the same on all nodes that talk to each other
#define GATEWAYID     1
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
//#define FREQUENCY     RF69_433MHZ
//#define FREQUENCY     RF69_868MHZ
#define FREQUENCY     RF69_915MHZ
#define ENCRYPTKEY    "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
#define IS_RFM69HW    //uncomment only for RFM69HW! Remove/comment if you have RFM69W! --------- DET VIRKER PERFEKT, SÅ LÆNGE JEG KOMMENTERER DENNE LINIE UD, ALTSÅ SÆTTER DEN TIL RFM69W
//*********************************************************************************************

#define ACK_TIME      30 // max # of ms to wait for an ack
#define MOTIONPIN      1 //hardware interrupt 1 (D3)

//#define SERIAL_EN             //comment this out when deploying to an installed SM to save a few KB of sketch size
#define SERIAL_BAUD    115200
#ifdef SERIAL_EN
#define DEBUG(input)   {Serial.print(input); delay(1);}
#define DEBUGln(input) {Serial.println(input); delay(1);}
#else
#define DEBUG(input);
#define DEBUGln(input);
#endif



RFM69 radio;
volatile boolean motionDetected = false;
char sendBuf[32];
byte sendLen;

void setup() 
{
  motionDetected = false;
  Serial.begin(SERIAL_BAUD);
  radio.initialize(FREQUENCY, NODEID, NETWORKID);
  
#ifdef IS_RFM69HW
  radio.setHighPower(); //uncomment only for RFM69HW!
#endif

  radio.encrypt(ENCRYPTKEY);
  
  char buff[50];
  sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY == RF69_433MHZ ? 433 : FREQUENCY == RF69_868MHZ ? 868 : 915);
  DEBUGln(buff);
  
  pinMode(MOTIONPIN, INPUT);
  attachInterrupt(MOTIONPIN, motionIRQ, FALLING);
  
  

}


volatile int detectedNumber = 0;
const int detectedRequired = 3;
//----------

void motionIRQ()
{  
  //Disable interrupt here!!!!
    detachInterrupt(MOTIONPIN);
  
  detectedNumber++;

  motionDetected = true;

//------------for debugging-------
  String s = "Motion detected, number: ";
  String message = s + detectedNumber;
  Serial.println(message); 
 //-------------------------------
 
  //delay(5000);
  attachInterrupt(MOTIONPIN, motionIRQ, FALLING); 
}


void loop()
{
  //------------for debugging-------
    Serial.println("Loop entered");
  //--------------------------------
    
  if (motionDetected == true && (detectedNumber >= detectedRequired))
  {
    //------------for debugging---------
    Serial.println("Motion - Do stuff");
    //----------------------------------
    
    detectedNumber = 0; //reset "counter"
    
    //Radio stuff--------
    //Serial.println("Radio - sending begin");
    
    sprintf(sendBuf, "HI");
    sendLen = strlen(sendBuf);
    
    if (radio.sendWithRetry(GATEWAYID, sendBuf, sendLen))
    {
      DEBUG("HI ACK:OK! RSSI:");
      DEBUG(radio.RSSI);
      
      //Serial.println("Radio - sending done");
    }
    
    //Serial.print("Radio sleep");
    radio.sleep();
 }
  //------------for debugging-------
  Serial.println("motionDetected set to false");
  //--------------------------------
  
  motionDetected = false; //do NOT move this after the SLEEP line below or motion will never be detected
  
  //------------for debugging-------
  Serial.println("Enable interrupt");
  //--------------------------------
  
  attachInterrupt(MOTIONPIN, motionIRQ, FALLING); 

//------------for debugging-------
  Serial.println("Power down");
//--------------------------------

  delay(100);
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
 
}

TomWS

Anders, I wouldn't bother using 'detachInterrupt()' if all you want to do is temporarily disable that specific interrupt.  I suggest that you research "interrupt masking on AVR".  You should be able to simply mask the interrupts while you wait for the pin to quiesce and then re-enable just before you sleep (once the pin is quiet, of course). Also think about how you might code a simple filter to effectively 'debounce' the signal (hint: use 'debounce' as a keyword).

If you need help with this I might be able to post a snippet of code later today, but you should be able to find something on the web.

Tom

ABL

Hi Tom :)

That is exactly what i want to do..  I have tried to find something useful about interrupt masking on AVR.. i find something about sei() and cli() but i don't know if that is what you had in mind.. if this is correct, how do i call these commands.. do i need avr/interrupts.h, and if so do you where to download it..?

I have tried to debounce to, but with no luck, so if you can post a snippet of code, it would be great.

Anders

TomWS

Ok, I'll post a snippet sometime my tomorrow morning (East Coast US)...

Tom

TomWS

Quote from: TomWS on May 30, 2015, 02:17:29 PM
Ok, I'll post a snippet sometime my tomorrow morning (East Coast US)...

Tom
Well I'm afraid I got carried away...

As promised, here is the code snippet to simply enable or disable the INT1 interrupt (leaving the other interrupts enabled).  Interestingly, the attachInterrupt and detachInterrupt functions are pretty efficient, but the macros below are very direct and allow you switch the interrupt on and off without affecting the other parts of your setup... (note that this doesn't work on all AVR processors, but does on Moteino processor)
#define MOTIONINT            1   // hardware interrupt 1 (D3) NOTE that this is DIFFERENT from PIN NUMBER!!!
// to understand following code, see: C:\Arduino\hardware\arduino\avr\cores\arduino\WInterrupts.c
#define enableShockInt    { EIMSK |=  (1<<MOTIONINT); }    // need to set int mask bit to one, hence OR with mask
#define disableShockInt   { EIMSK &= ~(1<<MOTIONINT); }    // need to set int mask bit to zero, hence AND with complement of mask


Now, as to getting 'carried away', I realized that even 'debounce' doesn't give you exactly what you want so I, uh, rewrote your code...  It's attached below and uses a function shockIntegrator() which integrates the shock sensor pulses based on a fixed sample interval and says motion is detected when a certain threshold has passed and says that it's ok to sleep after there is no motion for a certain number of samples.  The integrator is controlled by the following constants:
#define SHOCK_SAMPLE_TIME    50  // number of milliseconds between integrating samples
#define SHOCK_THRESHOLD      10  // number of accumulated pulses to trigger radio send
#define SHOCK_ZERO_THRESHOLD 20  // number of sequential samples with no motion (20 * 50mS = 1second)

You can play around with these three constants to control when motion is detected and how long before you go to sleep.

I've attached the whole sketch in a zip file as it was too big to include here, but here is the snippet of the integrator:
//==============================================================
// shockIntegrator() - filters the interrupts 
//    so that a certain number fall at a sufficiently high rate,
//    and also detects when its quiet enough to sleep
//==============================================================
int shockIntegrator(void)
{
  static int        // these variables need to be static to keep around between calls
    integral=0,
    numZeros=0;
  uint32_t          // general timer variables
    now,
    diff;
  static uint32_t   // this one needs to be static to keep it around between calls.
    last=0;
  int 
    rc=0;  // assume nothing to report
    
  now = millis();   // get current timestamp
  diff = now-last;  // calculate difference from last time to make rollover immune
  
  if (diff > SHOCK_SAMPLE_TIME)  // only check results at fixed intervals
  {
    last = now;         // reset time
    
    disableShockInt;    // disable the interrupt while we process the count
    
    if (detectedNumber) // did we get any interrupts inside of this window?
    {
      integral += detectedNumber;   // yes accumulate them
      detectedNumber=0;             // reset the counter
      // DEBUG - ok to do here since it's outside of interrupt handler and we've only masked OUR interrupt
      message = s + integral;
      DEBUGln(message);
    } else
    {
      integral -= 1;                // nothing this trip, bleed off the accumulated amount
    }
    
    enableShockInt;     // re-enable the interrupts
    
    if (integral >= SHOCK_THRESHOLD)
    {
      rc = 1;   // say that we've exceeded the count
      integral = SHOCK_THRESHOLD;   // saturate at this high value
    } else
    {
      if (integral <= 0)
      {
        integral = 0;  // 'saturate' at zero
        numZeros++;
        if (numZeros >= SHOCK_ZERO_THRESHOLD)  // have we had enough sequential zeros to sleep?
        {
          rc=-1;  // yup, tell the caller...
          numZeros = SHOCK_ZERO_THRESHOLD;    // saturate value
        }
      }
    }
  }
  return rc;
}


I've compiled the sketch just to make sure it builds but obviously did not attempt to test it...

Enjoy, let me know if you have any questions,
Tom

ABL

#21
Hi Tom  :)

Sorry for the late reply, I have been away because of work .

that is just awesome , i have just had a quick try with the full sketch and it seems to work perfectly :-)

just to be able to understand the whole interrupt concept, where can i read about it.... i can see you put something in the code snippet ..:

// to understand following code, see: C:\Arduino\hardware\arduino\avr\cores\arduino\WInterrupts.c 

but it seems to be a path to your C drive, can you point me in the right direction...

Thank you for your help, i really appreciate it :)

best regards
anders

TomWS

Quote from: ABL on June 09, 2015, 03:52:08 PM
Hi Tom  :)

Sorry for the late reply, I have been away because of work .

that is just awesome , i have just had a quick try with the full sketch and it seems to work perfectly :-)

just to be able to understand the whole interrupt concept, where can i read about it.... i can see you put something in the code snippet ..:

// to understand following code, see: C:\Arduino\hardware\arduino\avr\cores\arduino\WInterrupts.c 

but it seems to be a path to your C drive, can you point me in the right direction...

Thank you for your help, i really appreciate it :)

best regards
anders
Anders, the path:
C:\Arduino...

is where your Arduino IDE is installed.  Look on your system and see if you can determine where the IDE is installed and, once you've found it, then you can follow the rest of the path to look at this file, which is installed with the IDE.

Tom

JonM

TomWS - I am wondering if you'd be willing to assist on the "ShockTest" code included above.

I know I am reviving a 2 year old thread.  If this is bad form, please let me know and I'll start a new topic.


TomWS

Quote from: JonM on May 02, 2017, 08:15:31 PM
TomWS - I am wondering if you'd be willing to assist on the "ShockTest" code included above.

I know I am reviving a 2 year old thread.  If this is bad form, please let me know and I'll start a new topic.
I'd suggest starting a new thread and asking the question you really want answered.  I'm not sure I could help but there are plenty of others around here who are willing to help a specific question.