1

I have a datalogger using the RTC DS3231 as an interrupt generator. I am able to have the interrupts work but here is my problem. I would like to take 2 separate measures from 2 different sensors (one for humidity, temperature and the other for accelerations), one every 30 min et one every hour, the thing is that because I use the same pin (only one pin from the DS3231) for both of these alarms I cannot use a simple counter in my interrupt function otherwise one measure will not be taken when both of the alarms will trigger...

For example I just did a quick test with one alarm each min when seconds are 00 and an other alarm each minute when seconds are 20. The problem as I said is that I cannot increment counters for each since I use the same interrupt function (because of the single pin). Here is my loop function and interrupt handling function :

void loop() {
  delay(1000);
  sleepNow();
  if (alarm == true){
    handleAlarm(); // reset the possibility to trigger alarm
    if (counter_dtphl == COUNT_DTPHL){
      take_measure_DTPHL();
      counter_dtphl = 0;
    }
    else if (counter_accel == COUNT_ACCEL){
      take_measure_ACCEL();
      counter_accel = 0;
    }
  }
}

void wakeUpNow() {  
  Serial.println("In wake up now");
  delay(100);
  alarm = true;
  //Serial.println(counter);
  sleep_disable();//Disable sleep mode
  byte sec = get_date(SEC);
  Serial.println(sec);
  if (sec == 0){
  counter_dtphl +=1;
  }
  else if (sec == 30){
  counter_accel +=1;
  }
  detachInterrupt(digitalPinToInterrupt(interruptPin)); //Removes the interrupt from pin 2;
}

void handleAlarm() {
  alarm = false; 
  rtcObject.LatchAlarmsTriggeredFlags();
}

COUNT_ACCEL and COUNT_DTPHL are constant having the value of minutes corresponding to the trigger for the measure.

Has anybody an idea how to manage this situation ? For the acceleration I need to save the data for a period of 30 sec. One solution I tried is to increment the counter according to the time in second that corresponds each minute but I cannot put it in the wakeUpNow function since only fast processing should be done there (it is the function executed by the interrupt).

Thank you for your time !

3
  • what else does the sketch? why do you need RTC as timer? you can do something every 30 min with millis()
    – Juraj
    Commented Sep 2, 2019 at 16:09
  • why would you need two interrupts for an action that occurs every 30 minutes?
    – jsotola
    Commented Sep 2, 2019 at 16:49
  • Hello, I need a RTC as timer because the data logger will be an embedded system and the consumption is a key factor for this project. Thus, I cannot let it run with a simple millis() because I am powering down the card all the time and wake it up with alarm interrupt of DS3231.
    – JamesONeil
    Commented Sep 3, 2019 at 6:59

4 Answers 4

3

Consider it is good practice to leave as little code in an interrupt as possible. In this case, as the time in question is much greater then how often the loop() function is called, setting a single flag indicating an interrupt occurred would be sufficient.

Each time in your loop() function test for this flag. If TRUE, immediately set it to FALSE so as not forget to do so later. Next, while still in the scope of the IF statement, assuming the RTC DS3231 has been configured to create an interrupt every 30 minutes, take your "30 minute sample". Next, while still in the scope of the IF statement, increment a counter. Make sure this counter is defined as a global variable in order to persist between calls to the loop() function. If this counter has reached the value of 2, clear this counter to zero and take your "60 minute sample".

Consider the following pseudo code:

// Global variable defined outside of functions to track state & time.
bool state_interrupts;
int counter_interrupts;

void setup()
{
  // Initialize RTC to generate an interrupt once every 30 minutes.
  <RTC initialization code.>
  // Call attach interrupt to identify interrupt function name "wakeUpNow".
  attachInterrupt(...)
  // Initialize state & counter;
  interrupts_state = false;
  interrupts_counter = 0; 
}

void loop()
{
  // Check if interrupt occurred.
  if(interrupts_state)
  {
    interrupts_state = false;
    interrupts_counter++;
    // Sample 30 minute sensor.
    <Sample 30 minute sensor code.>
    if(interrupts_counter >= 2)
    {
      interrupts_counter = 0;
      // Sample 60 minute sensor.
      <Sample 60 minute sensor code.>
    }
  }
}

void wakeUpNow()
{
    interrupts_state = true;
}
5
  • Hi and thank you for your answer. I already tried what you say but it doesn't work for my need. I need 2 different measures from 2 different sensors. One every 30 min et the other every hour. The thing is that there will be a conflict each hour between the calls since 30 min is half of an hour. So I cannot use a counter that way
    – JamesONeil
    Commented Sep 3, 2019 at 6:55
  • @JamesONeil, are you sure you are not over thinking this? Or is there a problem constraint that you have not told us about? Yes, 2 different measurements from 2 sensors. The interrupt DOES'NT SAMPLE ANYTHING!!! The interrupt only sets a flag indicating 30 minutes has passed. YOUR CODE in the Loop function needs to keep track of the number of interrupts. Such that every time flag-set it samples the 30 minute sensor and every other time it samples the 60 minute sensor as well. REPEAT, the INTERRUPT DOES NOT SAMPLE ANY SENSORS!!! It's good practice to do as little as possible in interrupts!
    – st2000
    Commented Sep 3, 2019 at 19:29
  • @JamesONeil, since you made the effort to edit / improve your question, I added pseudo code to my answer to make the proposed solution easier to understand.
    – st2000
    Commented Sep 4, 2019 at 14:11
  • Hi ! Sorry for late answer I managed to have it worked the way I wanted :) Thank you for your pseudo code it is a good way also to solve my problem !
    – JamesONeil
    Commented Sep 5, 2019 at 8:03
  • "Initialize RTC to generate an interrupt once every 30 minutes." doesn't look like it is an option from the A2M2 bit's table in datasheets.maximintegrated.com/en/ds/DS3231.pdf -- It looks like you can only trigger every minute or when the minutes match a particular number. If you choose '30' you'll miss '00' & vice versa. You could trigger each minute and count minutes interruptState = (++elapsedMinutes % 30 == 0);, or read the minutes and act accordingly.
    – Dave X
    Commented Jan 10, 2022 at 15:14
2

The typical solution to this type of problem is:

  1. In the ISR set a flag to indicate an RTC interrupt has occurred.
  2. In the loop check the flag and if the set: a) Read the alarm flags from the RTC, b) Check the alarms, return value from LatchAlarmsTriggeredFlags(), and do the appropriate action.

What you should not do is write a lot of code in the ISR. Especially code that is also interrupt driven or depend on interrupts such as Wire, Serial, millis(), delay(), etc.

Cheers!

1

After the interrupt read the time from the RTC and then do the correct thing based on the result.

0

Try this: bool x = true; This is before setup bool done = false;

x = !x; Do this in the interrupt function. done = true; this is in your loop! if done == true{ // Determine if you have been here before if X !true do both functions else do the 30 second one I use the !X as it is faster. done = false;} This should give you an idea, I did not actually code this but i use code similar to this all the time. My goal is to do no more then 1 or two instructions in the interrupt service routine (ISR).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.