"Hold" or "pause" command/statement. Many statements. Mixing "if", "&&" and "||"

Hi
I am a total newbie, and i think its hard to understand the "Control Structures" and even when to use curly baces more than in the beginning and at the end of a scetch. Any good tutorials or explenations?

My questions:

1: How to program a "hold" or "pause" command/statement.. or some workaround. Any ideas? If i "delay" i also delay the whole loop!

2: How to put more statements after each other? Is it maximum two statements before";", or is it possible to add more statements/commands with a ","?

3: Is it possible to mix "if", "else if", "else", &&(and) and || (or) ? What are the limits/rules?

The case:

I have a sensor, and when it gets over an threshold on input A0- i want HIGH as an output, and stay "HIGH" until A0 senses an another input value above the threshold and then output "LOW". Any Ideas to write the code?

void setup() {
Serial.begin(9600);
pinMode (4, OUTPUT);
}
void loop() {
int sensorValue = analogRead(A0);
Serial.println(sensorValue);
digitalWrite(4, HIGH);
if (sensorValue > 360);

Problems: Here it should stay HIGH until an another input above treshold is representing...

}

Check out the blink without delay example.

void loop() {
 int sensorValue = analogRead(A0);
  Serial.println(sensorValue);
   digitalWrite(4, HIGH);
   if (sensorValue > 360) {
   // do action in braces
  }
   else {
  // optional - do other action in these braces
  }
} // end loop

Use CTRL-T, will autoformat the code to make it more readable, and also help you find mis-matched ( ), { }, and missing ;

Welcome to Intro to C Programming. OK, here we go! :slight_smile:

superolav:
i think its hard to understand ... when to use curly baces more than in the beginning and at the end of a scetch.

Braces signify a "block" of code that is basically an atomic (inseparable) unit. For example:

void loop () {
    // Everything in between these braces is part of the loop() function.
    // The '{' brace defines the beginning, and '}' defines the end.
}

// This is not part of loop()

There are many places where this construct is used. Here are a few others:

if (x == y) {
    // Everything in these braces will be run if x is equal to y
}

else {
    // Everything in these braces will be run if x is NOT equal to y
}

Or ...

x = 100;
while (x > 10) {
    // Here, everything in the braces runs while x is greater than 10
    x--;
}

You don't always have to use braces. Most of the examples above will work without them, but you're limited to one statement, like this:

// These two examples are the exact same
if (x == y) {
    x++;
}

if (x == y)
    x++;

// However, these two are NOT the same
if (x == y) {
    x++;    // Both of these lines will be executed
    y--;    // when x == y because of the braces
}

if (x == y)
    x++;    //  This line will be executed ONLY when x == y
    y--;    //  This line will be executed regardless

The example above illustrates the purpose of the braces. It "contains" a block of code so that it is treated as a single entity. The 'if' statement will either execute one single statement without braces, or it will execute everything within the braces.

You'll notice in the example above that the statement "y--;" is indented, so it looks like it matches the "x++;" statement right above it. Well, in C (including Arduino sketches), spaces and tabs mean nothing. In other words, these two statements are identical:

// This uses proper indentation (and line breaks)
if (x == y)
    x++;    // Part of the if statement

y--;    // Not part of the if statement

// This uses improper indentation, but is technically the same code
// and thus works exactly the same way.
if (x == y)
    x++;    // Part of the if statement
    y--;    // Not part of the if statement
            // though it looks like it was meant to be

The "x++;" line is part of the conditional statement. Another way to write it is like this:

if (x == y) x++;
y++;

The C compiler doesn't care whether you use a line break, or indent with spaces or tabs. The code is the same either way. Which brings us to your other question:

superolav:
How to put more statements after each other? Is it maximum two statements before";", or is it possible to add more statements/commands with a ","?

The semicolon ends a statement. You can stack them up any way you'd like. For example:

// This is how you usually see code written
x++;
y--;
x = y;

// But this is the same thing to the compiler
x++; y--; x = y;

The second example is usually poor form, but there's technically nothing wrong with it. Using multiple statements on a single line is sometimes used (particularly with trivial statements like the assignments above) by coders who feel it's unnecessarily verbose to put each statement on a separate line. It's purely aesthetic. You risk confusing readers, or having them miss the fact that it's actually multiple statements. (You could blame that on poor code reading skills, sure, but there's no reason to obfuscate your code.)

You also mentioned the comma operator. In general, it would be wise to forget that even exists in C, with the possibly forgivable exception of multiple statements in a for loop initializer -- although even then there's probably another way to do it that is less obtuse. For completeness, here's how the comma works:

// This line evaluates the first statement, discards any return
// value, then evaluates the second statement, keeping that
// return value
x = (y++, a + b);

// It is basically the same thing as this:
y++;
x = (a + b);

Since those two examples lead to the same result, why would anyone use the first? It only confuses the reader into thinking there's something special about the relationship between x, y, a, and b -- there isn't. While x ends up with the value of a + b, the value of y has nothing to do with anything -- it's just lumped in for no good reason.

As I said, you could argue that it might have a place in a for loop initializer like this:

for (x = a + b; x < 10; x++, y++) ...

Since you can't use multiple statements (terminated with semicolons) without breaking the three-statement syntax of the for loop initializer, you can squeak in some extra work by using the comma. Then, you get the chance to increment both x and y every loop iteration.

On the other hand, you could just do this instead:

for (x = a + b; x < 10; x++) {
    y++;
    // whatever else your loop does ...
}

That's much more obvious. The only thing it costs you is having to use braces when the for loop could otherwise be a one-liner like this:

for (x = a + b; x < 10; x++, y++) Serial.print("x = %u, y = %u\n", x, y);

Dubious benefit in my opinion, since many coders would look at that and have to remember what the comma does again. Some people have the same complaint about the tertiary operator:

// This is the tertiary operator that some people hate for its "obscurity"
x = (a == b) ? a : b;

// It does the same thing as this
if (a == b)
    x = a;
else
    x = b;

I personally love the tertiary operator for its concise and obvious (to me!) syntax. YMMV. Same with the comma I suppose. (Notice I didn't use braces in the if / else statement, since only one statement needed to be executed in each case.)

(Had to break this up into two posts due to message length restrictions.)

superolav:
How to program a "hold" or "pause" command/statement.. or some workaround. Any ideas? If i "delay" i also delay the whole loop!

I think the concept you're looking for here is the "state machine". Given your pin reading example, you would do it like this:

void loop() {
    int sensorValue;
    int lastPinState = LOW;
    
    // Loop infinitely here:
    while (1) {
        sensorValue = analogRead(A0);
        
        if (sensorValue > 360) {
            if (lastPinState == LOW) {
                digitalWrite(4, HIGH);
                lastPinState = HIGH;
                
            // lastPinState == HIGH
            } else {
                digitalWrite(4, LOW);
                lastPinState = LOW;
            }
        }  // if (sensorValue > 360)
    } // while(1)
}

This is the logic that you described, but it's probably not going to do what you actually want because it's very likely you'll get a value over 360 with each loop iteration, meaning pin 4 is going to be twiddled back and forth at a super high speed. That might be what you're looking for, but probably not. Generally, you would want to only toggle the pin once the value at A0 goes over 360, then falls below 360, then goes back over 360 again. Or maybe you want it to toggle as long as A0 is over 360, but not more than once every 100ms. Or maybe you want the pin to go HIGH when A0 is over 360, and LOW again when A0 is over 630 (or whatever).

Let's assume you only want it to toggle each time it goes above 360, falls below, then goes back above 360 again:

void loop() {
    int sensorValue;
    int lastPinState = LOW;
    int lastSensorValue = 0;
    
    // Loop infinitely here:
    while (1) {
        sensorValue = analogRead(A0);
        
        if ( (sensorValue > 360) && (lastSensorValue < 360) ) {
            if (lastPinState == LOW) {
                digitalWrite(4, HIGH);
                lastPinState = HIGH;
            } else {
                digitalWrite(4, LOW);
                lastPinState = LOW;
            }
        }  // if (sensorValue > 360)
        
        lastSensorValue = sensorValue;
    } // while(1)
}

One more thing you might want to account for is called "hysteresis" -- which means, you might want there to be a "dead zone" to prevent the pin from toggling when the analog value hovers around, say, 358 to 362 for example. Technically, it fell below 360 when it's 359, so the code will toggle the pin. But the difference is negligible and you probably don't want it to change so close to the threshold value, since any amount of noise will set it off. And there WILL be noise.

You only need to change one line to implement this kind of buffer area:

        if ( (sensorValue > 360) && (lastSensorValue < 350) ) {

That will provide a 10-value cushion where the analog value has to drop below 350 before it's considered "below the threshold" again. You could tweak this value to be as large or small as you want.

There are a lot of ways this can be further optimized (not using ints when a single byte would work, or using the PINB register to toggle the pin instead of tracking its state, etc...) but this will get the job done.

Hope this short novel helps. :wink: