Often it is useful to make a different action take place each time you press the same button. To do this there are two main obstacles: having the button do different things (on AND off), and spotting each button press. We will tackle these one stage at a time, using the example of turning an LED on and off each time the button is pressed.
First we will look at making the same button do a different thing. In order to do this we need to remember what state the LED is currently in (on or off) and make a decision when the button is pressed about how to change that state. We will do this remembering using a variable, and to be really clever we will use an integer which can actually store a representation of HIGH
and LOW
.
const int ledPin = 5;
const int button1 = A5;
int ledState;
LOW
, as well as initialising the output, so add the following: ledState=LOW;
pinMode(ledPin, OUTPUT);
if(digitalRead(button1)){
if(ledState==LOW){
ledState=HIGH;
}
else{
ledState=LOW;
}
digitalWrite(ledPin, ledState);
}
Notice two important things here:
if()
statement is not true. In this case, if ledState
is not equal to LOW
, then it must be equal to HIGH, as these are the only two options. You might expect this program to do everything we want, but if you download it, you will see that it doesn't quite work. This is because the program moves so quickly from checking for the first button press onto checking for the second button press that it is highly likely that we are still holding down the button from the first time. As such it will turn the LED off again. Then it will loop()
again, and we are probably still holding down the button, so it will turn the LED on again, and so on. When we do let go of the button, depending on exactly how long we held it for, the LED would end up either on or off, apparently randomly.
Save and paste your program in your notebook.
This brings us to the second problem. In order to make something happen each time we press the button, we need to make sure we wait until the button has been released before we check for the next press. In order to wait for the button to be released, we are not going to use a delay()
, as this could be too long or too short for different people. Instead we are going to actually wait until the button has been let go, however long that might take, and to do this we will use the while()
command.
Unlike the if()
command, the while()
command will continue to loop through the contents of its swirly brackets for as long as the "condition" is TRUE
. If at the end of a loop, the condition is no longer true, it will exit the swirly brackets. We are going to set up a while()
loop that will go round and round for as long as we are pressing the button, but in this case we don't actually want it to perform any actions during this period, so we will leave the swirly brackets empty.
It looks like this:
while(digitalRead(button1)){
}
delay(10);
Let's look at this specific example in more detail to make sure we understand this command.
When the program gets to the while()
, it evaluates the "condition" (in this case whether or not the button is being pressed, where TRUE
would mean it is, and FALSE
would mean it isn't). If the statement resolves to TRUE
, it does all the code in the swirly brackets immediately after the while()
. In this case that is empty so would do nothing. Once it has done this, it goes back to the while()
and re-evaluates the "condition". If it is still TRUE
(i.e. the button is still being pressed), then it will run the code in the swirly brackets again. It will keep going round and round this loop doing the code in the swirly brackets (in this case doing nothing) until the "condition" is FALSE
(i.e. we have let got of the button), at which point, just like the if(), it will jump to the next line after the close of the swirly brackets.
while()
statement within the if()
command after changing the LED, so that we don't exit the if()
's swirly brackets until the button has been released. The final program, including all variable declarations looks like this:
const int ledPin=5;
const int button1=A5;
int ledState;
void setup() {
pinMode(ledPin, OUTPUT);
ledState=LOW;
}
void loop() {
if(digitalRead(button1)){
if(ledState==LOW){
ledState=HIGH;
}
else{
ledState=LOW;
}
digitalWrite(ledPin, ledState);
while(digitalRead(button1)){
}
delay(10);
}
}
Download the program and see what happens when you press the button repeatedly.
Save and paste the program in your notebook.
Often it is useful to have an action occur only when the value of the variable is between two numbers, and to have a different action occur if it is not. An example might be a greenhouse control system where you want a heater to come on if the temperature drops below a certain point, and a fan to come on if it rises above a certain temperature, but for them to switch off if it is in between, and show the user that everything is OK.
There are two ways of checking ranges:
It is usually easier to do the first method, as each condition to check will be simpler, and often this will be fine, but there are some circumstances where it might not be suitable.
We will look at each method in turn, starting with the first, and don't worry, I'll explain the new terms as we go.
For the first scenario, we are going to try to create the greenhouse control system described above. We will assume an imaginary sensor which when read from, gives an analogue value of 200 at 0°C and 800 at 30°C. We will model this using our potentiometer.
if(value<200){
digitalWrite(heater, HIGH);
digitalWrite(ok, LOW);
digitalWrite(fan, LOW);
}
else if(value<800){
digitalWrite(heater, LOW);
digitalWrite(ok, HIGH);
digitalWrite(fan, LOW);
}
else{
digitalWrite(heater, LOW);
digitalWrite(ok, LOW);
digitalWrite(fan, HIGH);
}
Here we run through each option in turn: IF the value is lower than 200 (i.e. less than 0°C), turn on the heater. ELSE IF it is lower than the second level (i.e. in between my two bad options, where everything is OK) then turn on the OK light. ELSE (i.e. if it is higher than 600 and therefore over 30°C) turn on the fan.
Note that the else if() command is essentially a combination of else and if(). If() the first thing is not TRUE, then go on to check if() this second thing is TRUE.
This clearly works, but it is not always efficient to check every possible value, especially if there are a lot of them.
Save and paste the program in your notebook.
Now let's look at a scenario where we might only want an action to take place if the value is within a range.
When you are watering plants, it is important not to water them when it is too hot, as you might scorch the leaves. Equally, you shouldn't water them if the temperature is below freezing because you might freeze the roots. You should therefore only water them if the temperature is above 0°C AND below 30°C.
Only one output is needed, let's say pin 5, and call it "water".
Change checkLevel() to be:
if(value>200 && value<800){
digitalWrite(water, HIGH);
}
else{
digitalWrite(water, LOW);
}
This is what we called a compound if() statement earlier, and makes use of the AND functionality (in Arduino expressed by &&) to check if() two things are both true (i.e. if the value is greater than 200 AND the value is less than 800). Note both must be full logic statements (they must both contain the variable and a check).
Download it and see what happens as you adjust the potentiometer.
Save and paste the program in your notebook.