0% found this document useful (0 votes)
68 views17 pages

Logical Expressions and Selection

The document discusses logical expressions and selection in C++ programming. It introduces Boolean variables that can only store true or false values, and Boolean operators like AND and OR that perform logical operations on Boolean values. The document then provides an example of an Arduino sketch that uses these concepts to turn on a hallway light only when it is dark and motion is detected. The sketch declares Boolean variables to store the results of light and motion sensors, uses Boolean operators to combine these values logically, and conditionally turns the light on or off based on the result.

Uploaded by

Raj Kumar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
68 views17 pages

Logical Expressions and Selection

The document discusses logical expressions and selection in C++ programming. It introduces Boolean variables that can only store true or false values, and Boolean operators like AND and OR that perform logical operations on Boolean values. The document then provides an example of an Arduino sketch that uses these concepts to turn on a hallway light only when it is dark and motion is detected. The sketch declares Boolean variables to store the results of light and motion sensors, uses Boolean operators to combine these values logically, and conditionally turns the light on or off based on the result.

Uploaded by

Raj Kumar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

Logical expressions and selection

There are ​int​ type variables to work with integers in C / C ++. However, operations on
integers is not the only tool in the developer's arsenal. One of the most important elements
of programming are logical operations, expressions and data types.

An ​int​ type variable can store arbitrary integers and operations with them are subject to the
laws of integer arithmetic. Boolean variables can store only one of the two values: true or
false, and operations with them are subject to the laws of Boolean algebra.

Boolean algebra is a clever name for some easily comprehensible things, such as "and",
"or", and "not" operations over statements that are either true or false. For example, let’s
consider the following logical expression: "​it is dark in the hallway​ ​and​ ​there is a man walking
down it.​" It consists of two Boolean values ​(statements on the darkness and the man) and
one operator (the "and" conjunction). Its final value will also be a Boolean value, which can
be used, for example, as a signal to turn on the light in the hallway of the hotel.

In programming, variables that store logical values ​are called ​Boolean variables​, and
operators, which perform actions on them, are called ​Boolean operators​, or simply ​logical
operators​.

Logical operations in C ++
In C ++, Boolean variables are of the ​bool​ type. The designation of the true value is done
with the help of the word “​true​”, while for the false value, the word “​false​” is used. Thus, if we
use the following to declare an integer variable:
​int​ myValue = ​42​;
For logical variables we shall use:
bool​ tooDark = ​false​;

bool​ humanDetected = ​true​;


Since C ++ for Arduino is sort of a superstructure over some bare C ++, there also exists a
word “​boolean​” to indicate a logical type alongside with “​bool​”. They are absolute synonyms,
so you can use both. For uniformity of style and better readability of the code, try to select
one of the terms and use it everywhere. We shall be using the “​bool​” term in this article,
simply because it has fewer letters and it is included in the language standard.

Application in practice: an eco-friendly hotel


Let’s develop the topic of energy-efficient lighting and create a device on Arduino that turns
on the light in the hallway only when it is really necessary.
Supposedly, there is an analog light sensor connected to Arduino, as well as a digital
pyroelectric motion sensor and an eco-friendly LED lamp.
In this case, the sketch will look like this:
#define LIGHT_SENSOR_PIN A0

#define MOTION_SENSOR_PIN 2

#define LED_LAMP_PIN 5
#define LIGHT_LEVEL_THRESHOLD 600

void​ setup()

pinMode(LIGHT_SENSOR_PIN, INPUT);

pinMode(MOTION_SENSOR_PIN, INPUT);

pinMode(LED_LAMP_PIN, OUTPUT);

void​ loop()

int​ lightLevel = analogRead(LIGHT_SENSOR_PIN);

bool​ motionDetected = digitalRead(MOTION_SENSOR_PIN);

bool​ tooDark = lightLevel < LIGHT_LEVEL_THRESHOLD;

bool​ lightningRequired = tooDark && motionDetected;

digitalWrite(LED_LAMP_PIN, lightningRequired ? HIGH : LOW);

Let’s take a look at the ​loop ​and try to see what is happening here. Everything is clear with
the first line: we read the light value from the analog sensor with the help of the inbuilt
analogRead​ function and assign it to the variable named ​lightLevel.

Next, we declare the logical variable ​motionDetected​, which is assigned the result of the
inbuilt ​digitalRead​ function once we’ve called it. The ​digitalRead​ function is similar in nature
to ​analogRead​, but it may return only one of the two values, either ​true​ or ​false​. This is a
function that returns a Boolean value. It is suitable for reading a variety of binary digital
sensors. In our example, we just used one of them: the pyroelectric sensor, which outputs 0
volts, when there is no movement within its radius, and 5 volts, when there is movement of a
warm object: a human, a cat or anyone else. The microcontroller assigns the ​false​ value to 0
V, and the ​true​ value to 5 V.

Thus, following the results of the execution of the second line, the ​motionDetected​ variable
will store either the true or the false value depending on whether or not any movement has
been detected in the hallway.
Next, we can see the definition of the ​tooDark​ Boolean variable, which is assigned the value
of the expression ​lightLevel <LIGHT_LEVEL_THRESHOLD​. The “​<​” symbol in C ++, as you
might guess, is the "​less than​" operator. The operator makes one logical result out of the two
numeric operands. The value of the whole expression is considered true if what is written on
the left of the sign (in our case, it’s ​lightLevel​) is less than what is written on the right of the
sign (​LIGHT_LEVEL_THRESHOLD​). This is quite logical and easily understandable, isn’t it?

Therefore, the ​tooDark​ variable will store the “​true​” value only if the value of the illumination
level of ​lightLevel​, which was obtained previously, is less than 600. Otherwise, the variable
will store the “​false​” value.

Specific values, such as 600 in our case, are often obtained experimentally, depending on
the configuration of the sensor and the room where the device is.

Let’s move on. We can see how the Boolean ​lightningRequired​ variable is declared, which is
assigned the value of the expression ​tooDark && motionDetected​. The “​&&​” symbol in C ++,
is the ​logical "and" operator.​ As you might guess, the whole expression is considered to be
true if and only if when the expressions that are both on the right and on the left of the
operator are true. Thus, the ​lightningRequired​ variable takes the “​true​” value if there is
human movement observed in the hallway and it’s dark at the same time. If at least one of
the conditions has not been satisfied, the result will be ​false​. This is exactly what we need.

And finally, the last expression is the calling of the ​digitalWrite​ function for the Arduino pin, to
which the lamp is connected. We need to turn on the lamp if the​ lightningRequired​ variable
contains the “true” value and turn it off if it contains “​false​”. To do this, we use the ternary
conditional operator ​? :​, where as a condition we simply use the value of the
lightningRequired ​variable. Remember? The condition in the ternary operator is considered
to be satisfied if its value is not zero, and not satisfied if its value is zero.

In reality, there is no such concept of logical values for a processor. All that it knows is how
to operate with integers. Therefore, in C ++ there is an automatic type conversion. Where it
expects an “​int​”, and we use a “​bool​”, there is an automatic conversion happening: “​true​” is
converted into an integer ​1​, and “​false​” into an integer ​0​.

Thus Boolean expressions and variables serve as another convenient tool for programmers,
which allows them to write more clear and comprehensible programs.

Returning to our example, in the expression:


digitalWrite(LED_LAMP_PIN, lightningRequired ? HIGH : LOW);
the second argument takes the ​HIGH​ value if ​lightningRequired​ is ​true​, and the ​LOW​ value if
lightningRequired​ is ​false​. Thus, we have achieved what we wanted: the light turns on when
we need it and it turns off when it is not appropriate.

Brevity of notation
If we recall the automatic conversion of variables of different types, and the fact that ​HIGH​ is
nothing but a macrodefinition of number ​1​, and ​LOW​ is a macrodefinition of number ​0​, the
last line in this example could be reduced to a concise statement:
digitalWrite(LED_LAMP_PIN, lightningRequired);
We have managed to do without the ternary operator, since the ​digitalWrite​ function will
anyway receive:
● 1: same as ​HIGH​, if ​lightningRequired ​is ​true
● 0: same as ​LOW​, if ​lightningRequired​ is ​false

Additionally, logical expressions are the most common expressions in C ++, to which general
rules of embedding apply. Therefore, the entire ​loop​ code in the example with eco-friendly
lighting could actually be written in one line:
void​ loop()

digitalWrite(LED_LAMP_PIN, analogRead(LIGHT_SENSOR_PIN) <


LIGHT_LEVEL_THRESHOLD && digitalRead(MOTION_SENSOR_PIN));

Yes, the code is more readable now, but it's just a demonstration of its possibilities. In reality,
it’s better to use a couple of intermediate variables:
void​ loop()

bool​ tooDark = analogRead(LIGHT_SENSOR_PIN) < LIGHT_LEVEL_THRESHOLD;

bool​ motionDetected = digitalRead(MOTION_SENSOR_PIN);

digitalWrite(LED_LAMP_PIN, tooDark && motionDetected);

Or at least use a line break for clarity:


​ oid​ loop()
v

digitalWrite(LED_LAMP_PIN,

analogRead(LIGHT_SENSOR_PIN) < LIGHT_LEVEL_THRESHOLD &&

digitalRead(MOTION_SENSOR_PIN)

);

}
What if we actually want the light on: “if” conditional expression
Attentive readers may have noticed that the given sketch can hardly work in the real world. If
we turn on the light, when it is too dark and motion is detected, next time you run the ​loop​,
the sensor will detect the light of our own lamp, so the program will think that there is already
enough light and will turn off the lamp. The process of constant switching on and off will
continue until the pyroelectric sensor detects motion. In the best-case scenario, the lamp will
be glowing, and at worst, it will be irritating us with its flickering. What shall we do?

The program can be put to sleep after the lamp turns on, say, for 30 seconds. It is enough
time for the guest of the hotel to walk down the hallway and it is not so wasteful in terms of
energy savings.

How to create a 30-second delay after the lamp is turned on but not after it’s turned off?
There is the ​“if” conditional expression​ in C ++ for this purpose. If we use it, the sketch will
be as follows:
#define LIGHT_SENSOR_PIN A0

#define MOTION_SENSOR_PIN 2

#define LED_LAMP_PIN 5

#define LIGHT_LEVEL_THRESHOLD 600

void​ setup()

pinMode(LIGHT_SENSOR_PIN, INPUT);

pinMode(MOTION_SENSOR_PIN, INPUT);

pinMode(LED_LAMP_PIN, OUTPUT);

void​ loop()

bool​ tooDark = analogRead(LIGHT_SENSOR_PIN) < LIGHT_LEVEL_THRESHOLD;

bool​ motionDetected = digitalRead(MOTION_SENSOR_PIN);

if​ (tooDark && motionDetected) {

digitalWrite(LED_LAMP_PIN, HIGH);

delay(​30000​); ​// спать 30 секунд


} ​else​ {

digitalWrite(LED_LAMP_PIN, LOW);

}
The program starts in the same way, but in the ​loop​ there is a new compound expression,
denoted by words “​if​”, “​else​”, and with braces. Let’s try to understand what this all means.

Immediately after the “​if​” word, the C ++ compiler expects to see a logical expression in
parentheses, which in this case is called a condition. It has the same meaning as it does for
the ternary operator. If its value is not zero and true, we execute the code block that
immediately follows the condition in braces. In our case, if ​tooDark​ and ​motionDetected ​are
true, we execute the code block which is made up of two lines:
digitalWrite(LED_LAMP_PIN, HIGH);

delay(​30000​); ​// спать 30 секунд

If the condition was zero, or false, which is the same thing, the section of the code following
the condition is skipped and not executed at all. However, if this skipped code block is
followed by the “​else​” word, the code block in curly braces is executed, which comes after
this word. In this case, if either ​tooDark​ or ​motionDetected​ are ​false​, the code block made up
of a single line is executed:
digitalWrite(LED_LAMP_PIN, LOW);

It should be noted that if the condition is satisfied, the next code block after “​else​” is not
performed and is skipped. Thus, in fact, the “​if​“ expression represents a simple and clear
statement in a programming language: "if something is X, you should do Y, otherwise you
should do Z."

Returning to our example, the code can be interpreted as follows: "if you want light, turn on
the lights and let the program go to sleep for 30 seconds, and if the light is not needed - turn
it off." Pretty simple and logical, isn’t it?

Using expressions that change the course of the program depending on some conditions is
called ​program branching,​ and blocks of code after the words “​if​” and “​else​” are called
branches.

Short version of “if”


When using the “​if​“ expression, it is not necessary to use the “​else​” branch. If something
should happen when the condition is satisfied, and not happen if the condition is not
satisfied, the “​else​” branch can simply be omitted. For example, we can change the ​loop​ of
our program as follows:
void​ loop()

{
bool​ tooDark = analogRead(LIGHT_SENSOR_PIN) < LIGHT_LEVEL_THRESHOLD;

bool​ motionDetected = digitalRead(MOTION_SENSOR_PIN);

bool​ lightningRequired = tooDark && motionDetected;

digitalWrite(LED_LAMP_PIN, lightningRequired);

if​ (lightningRequired) {

delay(​30000​); ​// спать 30 секунд

This variation of the code does exactly the same thing as before. Only now the code is
organized differently. We will in any case pass on the instructions to the lamp bout whether it
should turn on or off, calling ​digitalWrite​ with the ​lightningRequired​ Boolean value. Moreover,
the program will fall asleep for 30 seconds only if we turn on the light, i.e. if ​lightningRequired
is true. If we have just turned off the light, sleep mode is not necessary: ​we need to skip the
delay​ and immediately go at the end of the ​loop​ function. Therefore, we did not write the
“​else​” branch at all.

Moreover, if the section of the code after “​if​” or “else” contains only one expression, we can
omit the curly brackets:
if​ (lightningRequired)

delay(​30000​); ​// спать 30 секунд

Nested “if” expressions


Code blocks used in conditional expressions are most common blocks that follow the
general rules of C ++. Therefore, one “​if​” expression can easily be placed in the branch of
another “​if​” expression.

For example, let’s consider the sketch of a device that controls the opening of a refrigerator
door, a car door or something like that. We want the backlight activated when we open the
door, and if the door remains open for more than 20 seconds, we want to hear a warning
beep. At the same time, I want to be able to turn off the beep with a switch in case the
load/unload process is too slow – thus, it will not irritate us that much.

Suppose there is a permanent magnet mounted on the door, and there is a binary digital
magnetic field sensor on the frame. If the magnetic field is fixed, the door is closed.
Otherwise, the magnet moves too far away from the sensor, where there is no magnetic
field, so we can understand that the door is open. We shall also connect a backlight, a piezo
beeper (buzzer) and a Rocker switch to Arduino.
In this case, the code of the operating device will look like this:
#define DOOR_SENSOR_PIN 2

#define BUZZER_PIN 3

#define SWITCH_PIN 4

#define LAMP_PIN 5

#define BUZZ_TIMEOUT 20

#define BUZZ_FREQUENCY 4000

void​ setup()

pinMode(DOOR_SENSOR_PIN, INPUT);

pinMode(SWITCH_PIN, INPUT);

pinMode(BUZZER_PIN, OUTPUT);

pinMode(LAMP_PIN, OUTPUT);

void​ loop()

bool​ doorOpened = !digitalRead(DOOR_SENSOR_PIN);

if​ (doorOpened) {

digitalWrite(LAMP_PIN, HIGH);

delay(BUZZ_TIMEOUT * ​1000​);

bool​ buzzEnabled = digitalRead(SWITCH_PIN);

if​ (buzzEnabled) {

tone(BUZZER_PIN, BUZZ_FREQUENCY);

} ​else​ {

digitalWrite(LAMP_PIN, LOW);
noTone(BUZZER_PIN);

Let's look at what is happening in the ​loop​. First, we define the ​doorOpened​ variable and
assign it the value of the expression​! DigitalRead (DOOR_SENSOR_PIN)​. It has been
mentioned above that the door is considered open if there is no magnetic field, i.e.
digitalRead​ returns the “​false​” value to our sensor. The ​“!”​ symbol before the Boolean
expression in C ++ is the ​the logical "not"​ ​operator,​ or simply ​complementary operator​. It
affects the value recorded after it by turning ​true​ into ​false​ and vice versa. That’s exactly
what we need in this case.

Then comes the “​if​” statement that checks whether the door is open. If so, the program starts
the execution of the code block that comes immediately after the condition. First thing first,
we need to turn on the backlight in this code block. Then the program can go to sleep for 20
seconds (20 ms × 1000).

Next, we need to turn on the beeper if it had not been intentionally turned off before. To do
this, we shall check the state of the switch, which is responsible for this. We shall declare the
buzzEnabled​ variable, which is assigned the logical value read from the switch.

Please, note that the ​buzzEnabled​ variable is declared inside the code block which directly
follows the “​if​” expression. We can and we should do this, because it is good practice to
declare variables closer to the section where they are first used.

Let us recall the concept of the scope of variables: variables are available for use only within
the block where they are declared. In our case, ​buzzEnabled​ can be used in expressions
within the block of the code following the “​if​” espression (​doorOpened​). However, the attempt
to access it from somewhere else (for example, from the code block of the “​else​” branch or
directly from the ​loop​ outside the ”​if​” branch) will lead to an error of program compilation.
And this is actually good, since we should not involve a variable that is required at very
moment in some other ongoing processes. This makes the program more clear and
comprehensible.

After the readings of the switch, there comes an ​embedded conditional expression.​ Its
essence is exactly the same as before: it depends on the condition whether or not the code
should be executed. The only difference is that it is located directly in the code block of
another “​if​” branch. It is common practice that occurs quite often in programming. In fact, in a
nested “​if​”, you can put more “​if​” expressions, as many as you want: in the C ++ language,
this number is unlimited.

Returning to the example, if the switch is set to "enabled", i.e. ​buzzEnabled​ contains the
“​true​” value, we shall turn on the beep. This is done by using the inbuilt ​tone​ function. It
takes two arguments: the number of Arduino’s pin, which has the piezo buzzer connected
and the beep frequency. In our case, we have chosen the frequency of 4000 Hz, i.e. 4 kHz.
Finally, if the door is closed, i.e. ​doorOpened​ contains the “false” value, we need to make
sure that the lights and the buzzer are turned off. This is done in the “​else​” branch of the first
“​if​” condition. You now know how to turn off the lamp. The ​noTone​ function, as you might
guess, disables the beep on the selected pin.

If we take into consideration the rules of embedding expressions and keeping them short, we
can simplify the ​loop​ code a bit. It might look like this:
void​ loop()

if​ (!digitalRead(DOOR_SENSOR_PIN)) {

digitalWrite(LAMP_PIN, HIGH);

delay(BUZZ_TIMEOUT * ​1000​);

if​ (digitalRead(SWITCH_PIN))

tone(BUZZER_PIN, BUZZ_FREQUENCY);

} ​else​ {

digitalWrite(LAMP_PIN, LOW);

noTone(BUZZER_PIN);

We have removed curly brackets for the internal “​if​” expression and embedded ​digitalRead
callings directly into conditional expressions.

Please, note how the correct use of indenting in code blocks makes it easy to understand to
which “​if​” expression refers our “​else​” expression. It also helps us understand what follows
what and under which conditions. Never write without indented lines despite the fact that the
compiler won’t care anyway. This makes the code not readable for other people and for you
as well:
void​ loop()

if​ (!digitalRead(DOOR_SENSOR_PIN)) {

digitalWrite(LAMP_PIN, HIGH);

delay(BUZZ_TIMEOUT * ​1000​);

if​ (digitalRead(SWITCH_PIN))

tone(BUZZER_PIN, BUZZ_FREQUENCY);
} ​else​ {

digitalWrite(LAMP_PIN, LOW);

noTone(BUZZER_PIN);

Button clicks
One of the typical tasks when creating devices on microcontrollers is to determine the time
of the switch click to be able to respond to it somehow. The problem is that the switch, just
like the sensor, can only tell whether it is now pressed or released. It cannot tell us that it
“has just been pressed”.

But this problem is easily solved with a small trick in the software of the project. Let's make a
primitive device with a lamp and a switch that would turn the lamp on and off in turn by
pressing the button: one click – the lamp is on, another click – it’s off:
#define BUTTON_PIN 2

#define LAMP_PIN 5

bool​ lampState = ​false​;

bool​ wasButtonDown = ​false​;

void​ setup()

pinMode(BUTTON_PIN, INPUT);

pinMode(LAMP_PIN, OUTPUT);

void​ loop()

bool​ isButtonDown = digitalRead(BUTTON_PIN);

if​ (isButtonDown && !wasButtonDown) {

lampState = !lampState;

delay(​10​);

}
wasButtonDown = isButtonDown;

digitalWrite(LAMP_PIN, lampState);

In the sketch, we can see 2 Boolean variables:

● lampState​ contains the “​true​” value, if the lamp should now be on, and the “​false​”
value if the lamp should be off.
● wasButtonDown​ stores the switch status at the time of the last run of the ​loop​: if the
button has been pressed, the value is true.

Now let’s take a look at the ​loop​ itself. First, we need to read off the switch status into the
isButtonDown​ logical variable. If the switch is on, ​isButtonDown​ will contain the “​true​” value.

This is followed by a conditional “​if​” statement to check the conditions, the essence of which
is to understand whether the button has been pressed just now or a long time ago. To do
this, we shall use the ​wasButtonDown​ value.

Thus, the condition should be perceived as "​the button is pressed now​, ​but ​it ​wasn’t pressed
before​”. This is the immediate condition of the button click.

If the condition of the click is satisfied, we need to act. Let’s change the ​lampState​ value vice
versa:
lampState = !lampState;

Further on, there is ​delay (10)​ in the “​if​” branch. We call the ​delay​ here solely because of the
imperfections of mechanical buttons. When we press the button, in the microseconds that
the plates touch, the button can record the opening and closing dozens of times. By adding
delay (10)​, we experience a real storm of activity. Ten milliseconds is more than enough to
calm the button down, but is too short for people to notice it.

Next, we assign the ​wasButtonDown​ variable the recently read ​isButtonDown​ value, which
tells us if the button is pressed right now. If the button has been pressed just now, the
lampState​ switch status of the lamp will change, and the ​wasButtonDown​ variable will
eventually take the “​true​” value and will store it until the button is released. Thus, next time
you call the ​loop​, the condition will not be changed again.

If we hadn’t resorted to this trick and used only the current state of the button without looking
what was happening before, the status would have changed while the button was pressed
tens of thousands of times per second. From the point of view of a human, it would look like
there were some obvious and rather annoying problem with the device.

“If” chains
Finally, let’s program a device that represents a simple climate controller, say, for a
terrarium. Let’s say that a thermistor, an air conditioner, a heater and a green LED are
connected to Arduino. If the resulting temperature is too high, we have to turn on air
conditioning, if is it too low – the heater, and if it is in the normal range, the LED will turn on.

Thus, the program might look like this:


#define CONDITIONER_PIN 4

#define HEATER_PIN 5

#define OK_LED_PIN 6

#define THERMISTOR_PIN A0

#define TEMP_MIN 400

#define TEMP_MAX 500

void​ setup()

pinMode(CONDITIONER_PIN, OUTPUT);

pinMode(HEATER_PIN, OUTPUT);

pinMode(OK_LED_PIN, OUTPUT);

void​ loop()

int​ temp = analogRead(THERMISTOR_PIN);

if​ (temp < TEMP_MIN) {

digitalWrite(CONDITIONER_PIN, LOW);

digitalWrite(HEATER_PIN, HIGH);

digitalWrite(OK_LED_PIN, LOW);

} ​else​ ​if​ (temp > TEMP_MAX) {

digitalWrite(CONDITIONER_PIN, HIGH);

digitalWrite(HEATER_PIN, LOW);

digitalWrite(OK_LED_PIN, LOW);
} ​else​ {

digitalWrite(CONDITIONER_PIN, LOW);

digitalWrite(HEATER_PIN, LOW);

digitalWrite(OK_LED_PIN, HIGH);

In this program, everything should be familiar to you. The only question can be the use of “​if​”
and “​else​” next to each other, in the same line. In fact, this is just another way to write a
number of nested conditional statements. We could write the same thing in the following
way:
if​ (temp < TEMP_MIN) {

digitalWrite(CONDITIONER_PIN, LOW);

digitalWrite(HEATER_PIN, HIGH);

digitalWrite(OK_LED_PIN, LOW);

} ​else​ {

if​ (temp > TEMP_MAX) {

digitalWrite(CONDITIONER_PIN, HIGH);

digitalWrite(HEATER_PIN, LOW);

digitalWrite(OK_LED_PIN, LOW);

} ​else​ {

digitalWrite(CONDITIONER_PIN, LOW);

digitalWrite(HEATER_PIN, LOW);

digitalWrite(OK_LED_PIN, HIGH);

But you need to remember that a conditional expression is a righteous expression in C ++.
There is only one conditional expression in the external “​else​” branch, so the curly brackets
can be omitted:
if​ (temp < TEMP_MIN) {

digitalWrite(CONDITIONER_PIN, LOW);

digitalWrite(HEATER_PIN, HIGH);

digitalWrite(OK_LED_PIN, LOW);
} ​else

if​ (temp > TEMP_MAX) {

digitalWrite(CONDITIONER_PIN, HIGH);

digitalWrite(HEATER_PIN, LOW);

digitalWrite(OK_LED_PIN, LOW);

} ​else​ {

digitalWrite(CONDITIONER_PIN, LOW);

digitalWrite(HEATER_PIN, LOW);

digitalWrite(OK_LED_PIN, HIGH);

And if we remember that an empty space does not mean anything to the compiler, we can
remove some indents and line breaks, and we shall get:
if​ (temp < TEMP_MIN) {

digitalWrite(CONDITIONER_PIN, LOW);

digitalWrite(HEATER_PIN, HIGH);

digitalWrite(OK_LED_PIN, LOW);

} ​else​ ​if​ (temp > TEMP_MAX) {

digitalWrite(CONDITIONER_PIN, HIGH);

digitalWrite(HEATER_PIN, LOW);

digitalWrite(OK_LED_PIN, LOW);

} ​else​ {

digitalWrite(CONDITIONER_PIN, LOW);

digitalWrite(HEATER_PIN, LOW);

digitalWrite(OK_LED_PIN, HIGH);

Such chains made up from “​if​” expressions are a fairly common phenomenon. If there were
more than three options, the nested “​if​” expressions would look awkward and ugly, while
such a chain would still look quite clear and readable.

In fact, climate-control programs can be written in a more concise way. We have


demonstrated it as it is merely to show you the ​if - else if - else​ chain. Let us demonstrate
you the short version to give you a complete picture:
#define CONDITIONER_PIN 4

#define HEATER_PIN 5

#define OK_LED_PIN 6

#define THERMISTOR_PIN A0

#define TEMP_MIN 400

#define TEMP_MAX 500

void​ setup()

pinMode(CONDITIONER_PIN, OUTPUT);

pinMode(HEATER_PIN, OUTPUT);

pinMode(OK_LED_PIN, OUTPUT);

void​ loop()

int​ temp = analogRead(THERMISTOR_PIN);

bool​ tooCold = temp < TEMP_MIN;

bool​ tooHot = temp > TEMP_MAX;

digitalWrite(CONDITIONER_PIN, tooHot);

digitalWrite(HEATER_PIN, tooCold);

digitalWrite(OK_LED_PIN, !(tooCold || tooHot));

Again, everything is familiar to you except perhaps the value of the ​! (TooCold || tooHot)
expression. The “​||​” symbol in C ++ is the ​logical "or" operator.​ The value of the expression
is true if at least one of the values ​on the left or right of the operator are true.

Logical expressions are nothing more than arithmetic expressions. Here the same rules
apply: in one expression, there can be any number of operators, while the order of their
application can be designated by brackets. In this case, we first calculate the logical value
tooCold || tooHot​, and then the logical "not" (​!​) operator to invert the value obtained.
To sum up, we have got acquainted with logical variables, expressions and related
operators. It already allows us to create devices that look smart. So just use your
imagination, and go for it!

You might also like