Go Down

Topic: Perform time-based task once only, at set times per hour, every hour (Read 884 times) previous topic - next topic

brice3010

I read time from a DS3231, and want to perform a specific task just once, but at different times per hour.

For example: perform task A (contained in void actionTime() in code below) at 10 minutes past the hour, at 20 minutes past the hour and at 40 minutes past the hour, every hour, but each time this task may be performed just once.

What would be the most appropriate way to do this without using delay, without using alarm functions and using the setup code below:

(EDIT: removed erroneous delay function in code below; sorry!)

EDIT 2: task A is pretty large, it would be preferred to have all time conditions tested in one if

Code: [Select]

/*
// https://tronixlabs.com.au/news/tutorial-using-ds1307-and-ds3231-realtime-clock-modules-with-arduino/
// uses no library

#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val / 10 * 16) + (val % 10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val / 16 * 10) + (val % 16) );
}

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  // set the initial time here:
  // DS3231 seconds, minutes, hours, day, date, month, year
  // setDS3231time(30,17,15,7,18,11,17);
}

void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
                   dayOfMonth, byte month, byte year)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}
void readDS3231time(byte *second,
                    byte *minute,
                    byte *hour,
                    byte *dayOfWeek,
                    byte *dayOfMonth,
                    byte *month,
                    byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}
void actionTime()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
                 &year);
  static byte trigger = 1;

/*
 * How to write code to perform a specific task just once, but each time at specific times in an hour, and every hour?
 * For example: execute task just once, at 10 minutes past the hour, at 20 minutes past the hour and at 40 minutes past the hour.
 *
 */

}


void loop()
{
  actionTime(); // display the real-time clock data on the Serial Monitor,

}

TonyWilk

You want to do something when the minute changes to whatever value you choose, so

Code: [Select]
static byte lastMinute=0;

  if( minute == lastMinute ){
    return;
  }
  lastMinute= minute;   // remember what minute was last time we looked

  // minute has changed... what is it now?
  if( minute == ??? ){
     do something
  }


Yours,
  TonyWilk

larryd

Pseudo code:

if(taskAflag == true && minute == 10)
{
taskAflag = false; //disable, do only one taskA
. . .
}

if(taskAflag == false && minute == 11)
{
taskAflag = true; //enable taskA for next time
}
No technical PMs.
The last thing you did is where you should start looking.

brice3010

You want to do something when the minute changes to whatever value you choose, so

Code: [Select]
static byte lastMinute=0;

  if( minute == lastMinute ){
    return;
  }
  lastMinute= minute;   // remember what minute was last time we looked

  // minute has changed... what is it now?
  if( minute == ??? ){
     do something
  }


Yours,
  TonyWilk
The issue here I think is that "do something" will be performed for as long as the "minute == ???" condition is valid, and not just once?

brice3010

Pseudo code:

if(taskAflag == true && minute == 10)
{
taskAflag = false; //disable, do only one taskA
. . .
}

if(taskAflag == false && minute == 11)
{
taskAflag = true; //enable taskA for next time
}
So by the same token, if I have task A to be performed once at 3 instances per hour, is the following correct?
Code: [Select]

if((taskAflag == true && minute == 10) || (taskAflag == true && minute == 20) || (taskAflag == true && minute == 40))
{
taskAflag = false; //disable, do only one taskA
. . .
}

if((taskAflag == false && minute == (10+1)) || (taskAflag == false && minute == (20+1)) || (taskAflag == false && minute == (40+1)))
{
taskAflag = true; //enable taskA for next time
}

TonyWilk

The issue here I think is that "do something" will be performed for as long as the "minute == ???" condition is valid, and not just once?
No, when minute changes, say from 9 to 10, then "minute == lastMinute" is not true, so we go on to set lastMinute= minute; (which is now 10) and then do e.g. if( minute == 10 ){ do something }

Next time thru, "minute == lastMinute"  is true, we're still in minute 10, so the function return;'s

Yours,
  TonyWilk

brice3010

No, when minute changes, say from 9 to 10, then "minute == lastMinute" is not true, so we go on to set lastMinute= minute; (which is now 10) and then do e.g. if( minute == 10 ){ do something }

Next time thru, "minute == lastMinute"  is true, we're still in minute 10, so the function return;'s

Yours,
  TonyWilk

Hi Tony, so, if on for example at three time-instances (say at 10, at 20 and at 40 values for minute) the task is to be performed, the code should be like following? (I am not sure)

Code: [Select]

static byte lastMinute=0;

  if( minute == lastMinute ){
    return;
  }
  lastMinute= minute;   // remember what minute was last time we looked

  // minute has changed... what is it now?
  if( minute == 10 || minute == 20 || minute == 40 ){
     do something
  }

TonyWilk

Hi Tony, so, if on for example at three time-instances (say at 10, at 20 and at 40 values for minute) the task is to be performed, the code should be like following? (I am not sure)
Yes, spot on !



Yours,
 TonyWilk

brice3010

No, when minute changes, say from 9 to 10, then "minute == lastMinute" is not true, so we go on to set lastMinute= minute; (which is now 10) and then do e.g. if( minute == 10 ){ do something }

Next time thru, "minute == lastMinute"  is true, we're still in minute 10, so the function return;'s

Yours,
  TonyWilk

Hi Tony, just to understand correctly: the "return" in the first function inhibits execution of code after that statement? Meaning, if minute == lastMinute then the code behind that "if" is not executed?

What an elegant piece of code!!!
Thanks,
Erik


UKHeliBob

When the return statement is encountered the code stops at that point and the program immediately returns back to where it was called.  If this happens in the loop() function then it effectively causes the loop() function to restart.  What actually happens is that the program returns to the hidden main() function that called the loop() function in the first place and loop() is called again immediately.
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

el_supremo

Quote
without using alarm functions
Why not use the alarms?

Pete
Don't send me technical questions via Private Message.

brice3010


el_supremo

When you originally posted your question you didn't know how to do it nor whether it would be easy to do, yet you excluded use of alarms.

Pete
Don't send me technical questions via Private Message.

brice3010

When you originally posted your question you didn't know how to do it nor whether it would be easy to do, yet you excluded use of alarms.

Pete
Because I knew it was going to be simple  :)

What would be the advantage of using alarms instead?

el_supremo

It must be nice to be psychic.

I didn't say alarms would necessarily be easier but all it would require is an alarm interrupt every minute. The code in loop() would look almost the same except that the alarm must be reset and there's no need to test if minute == lastMinute.


Pete
Don't send me technical questions via Private Message.

Go Up