question about return;

In a program I use void loop(); to call void actionTime();

In this last function I read DS3231 time to execute a task when a certain time is met. Otherwise the tasks in the void loop(); should continue to be executed.

Is it proper to use a return; function while checking if the actual time has changed from the previous time that the condition was met? Without interfering with the execution of the void loop(); ?
In other words: the void loop(); is the main loop program, void actionTime(); is a time dependent program to be executed only once if certain time conditions are met.

The purpose of the return; is to make sure that the time dependent if condition in void actionTime(); is executed only once as soon as the required time is met.

#define DS3231_I2C_ADDRESS 0x68
#include <Wire.h>
const int buttonPin1 = 12;
const int buttonPin2 = 13;
const int LED1 = 14;
const int LED2 = 16;
int ledState = HIGH;
int buttonState1;
int buttonState2;
int lastButtonState1 = LOW;
int lastButtonState2 = LOW;

unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
unsigned long elapsedTime;
unsigned long startTime;
unsigned long currentTime;

// 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() {

  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  Serial.begin(115200);   // Setup Serial Communication.
  digitalWrite(LED1, ledState);
}


/**************************
   R E A D   T I M E
**************************/

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() {
  // do something once, using Ds3231: read time and
  // act only if certain time criteria are met
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);

  // execute time dependent task only once
  static byte lastSecond = 0;  // execute time dependent task only once
  if ( second == lastSecond ) {
    return;
  }
  lastSecond = second;  // remember what second was last time we looked
  // second has changed... what is it now?

  if (second == 01)
  {
    //    do something once
  }

}

void loop() {

  currentTime = millis();

  // debounce
  if (currentTime - lastDebounceTime > debounceDelay) {
    lastDebounceTime += debounceDelay;
    buttonState1 = digitalRead(buttonPin1);

    // then check the change of state
    if (buttonState1 != lastButtonState1) {
      if (buttonState1 == HIGH) {
        ledState = !ledState;
        if (ledState == HIGH) {
          startTime = currentTime;
        }
      }
      lastButtonState1 = buttonState1;
    }
  }
  digitalWrite(LED1, ledState);

  // manage LED2
  if (currentTime - startTime > 3000 && ledState == HIGH) {
    digitalWrite(LED2, HIGH);
  }
  else {
    digitalWrite(LED2, LOW);
  }
  actionTime(); // do something, time based
}

From a very brief look at your code your use of return in the function actionTime() seems to be correct.

...R

Robin2:
From a very brief look at your code your use of return in the function actionTime() seems to be correct.

...R

Thank you Robin2, that is all that was needed: some double checking :sunglasses: from a knowledgeable person about a specific programming aspect.

You can use the return statement in that manner.

Why not turn the if statement around and if (second != lastSecond) {}?

The advantage is you don't have to find or notice the statement in the middle of the subroutine that "aborts" execution. The subroutine will execute all the way to the end every time, but only execute inside the if statement if the criteria is met.

One of my personal rules for programming or program architecture is not to program in a way that I will have to figure out or remember how I did two-four-six months from now or at 2am on Saturday morning when the phones rings and somebodies production line is down (in the case of work).

adwsystems:
You can use the return statement in that manner.

Why not turn the if statement around and if (second != lastSecond) then {}?

The advantage is you don't have to find or notice the statement in the middle of the subroutine that "aborts" execution. The subroutine will execute all the way to the end every time, but only execute inside the if statement if the criteria is met.

Good response! However, in my case there are only specific seconds where I want action. For example, at second 01, 21, 41.

adwsystems:
You can use the return statement in that manner.

Why not turn the if statement around and if (second != lastSecond) {}?

The advantage is you don't have to find or notice the statement in the middle of the subroutine that "aborts" execution. The subroutine will execute all the way to the end every time, but only execute inside the if statement if the criteria is met.

One of my personal rules for programming or program architecture is not to program in a way that I will have to figure out or remember how I did two-four-six months from now or at 2am on Saturday morning when the phones rings and somebodies production line is down (in the case of work).

... with some afterthought: your statement shoudl work too, my mistake!
Using if(second != lastsecond) makes sure execution only takes place when second has changed, and then I still verify for the correct seconds.
My apologies!

brice3010:
Good response! However, in my case there are only specific seconds where I want action. For example, at second 01, 21, 41.

 if ( second != lastSecond )
 {
  lastSecond = second;  // remember what second was last time we looked
  // second has changed... what is it now?

  if (second == 01)
  {
    //    do something once
  }
  if (second == 21)
  {
    //    do something once
  }
  if (second == 41)
  {
    //    do something once
  }
//....
 }

or better yet

 if ( second != lastSecond )
 {
  lastSecond = second;  // remember what second was last time we looked
  // second has changed... what is it now?

  switch (second)
  {
    case 1 :
    //    do something once
              break;
    case 21 :
    //    do something once
              break;
    case 41 :
    //    do something once
              break;
//....
    default :
               break;
  }
 }

adwsystems:

 if ( second != lastSecond )

{
  lastSecond = second;  // remember what second was last time we looked
  // second has changed… what is it now?

if (second == 01)
  {
    //    do something once
  }
  if (second == 21)
  {
    //    do something once
  }
  if (second == 41)
  {
    //    do something once
  }
//…
}




or better yet


if ( second != lastSecond )
{
  lastSecond = second;  // remember what second was last time we looked
  // second has changed… what is it now?

switch (second)
  {
    case 1 :
    //    do something once
              break;
    case 21 :
    //    do something once
              break;
    case 41 :
    //    do something once
              break;
//…
  }
}

You are right, I had just realised your first post here is in fact very applicable (see my previous post), thanks!

adwsystems:
You can use the return statement in that manner.

Why not turn the if statement around and if (second != lastSecond) {}?

The advantage is you don't have to find or notice the statement in the middle of the subroutine that "aborts" execution. The subroutine will execute all the way to the end every time, but only execute inside the if statement if the criteria is met.

One of my personal rules for programming or program architecture is not to program in a way that I will have to figure out or remember how I did two-four-six months from now or at 2am on Saturday morning when the phones rings and somebodies production line is down (in the case of work).

Would it matter if I initialise like this:

static byte lastSecond = 0;

or like this:

static byte lastSecond;

brice3010:
Would it matter if I initialise like this:

Because you are using "static" I assume it is a local variable and in that case you need to give it an initial value - otherwise it will use whatever happened to be in that memory location.

...R

If I use variables in my void loop() that I want to retain their values when I jump to void actionTime () and then back to void loop() I must use them as static, right?

And if so may I assign them before setup() or must they be declared in the void where used?

I assume it is a local variable and in that case you need to give it an initial value - otherwise it will use whatever happened to be in that memory location.

My understanding from comments in other threads was that both global and static local integer variables are initialised to zero by default but I have no definitive reference for that, and in any case doing it explicitly makes the intention obvious and is, I suggest, the preferred method.

or must they be declared in the void where used?

What are the “voids” that you refer to ? Do you have holes in your programs ?

After over 500 posts I would expect you to know that what you are calling voids are in fact functions and that the word void indicates that the function will not return a value.

brice3010:
If I use variables in my void loop() that I want to retain their values when I jump to void actionTime () and then back to void loop() I must use them as static, right?

Not necessarily.
If you want the variables in the function loop, to retain their values when you return from the function loop, then yes, they need to be either global or static.
However, if you call another function from loop, then the variables do not necessarily need to be static - when you return from the function you called, the variables will have the values that they had before you called the function

UKHeliBob:
My understanding from comments in other threads was that both global and static local integer variables are initialised to zero by default but I have no definitive reference for that

Refer to K&R.

TolpuddleSartre:
Refer to K&R.

What is K&R?

Kernighan and Ritchie.

TolpuddleSartre:
Kernighan and Ritchie.

Thanks for that information. Is it better than Embedded C Programming and the Atmel AVR (Barnett, Cox, O'Cull)?

Without K&R, there would be no "Embedded C Programming".

You need to decide what "better" means to you (I have read neither book you mention)

TolpuddleSartre:
Kernighan and Ritchie.

The "Bible" says :

External and static variables are initialized to zero by default.