Let's start with the Button example (File > Examples > Digital > Button). We'll modify this using both pullup and pulldown resistors, then use Arduino's internal INPUT_PULLUP
Conditional statements allow a program to make decisions about which lines of code run and which do not. They let actions take place only when a specific condition is met.
The test must be an expression that resolves to true or false. When the test expression evaluates to true, the code inside the { (left brace) and } (right brace) is run. If the expression is false, the code is ignored. Code inside a set of braces is called a block.
Conditionals can be embedded to include more than one test to control which lines of code will run.
The Button example uses this simple conditional statement:
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(ledPin, HIGH);
} else {
// turn LED off:
digitalWrite(ledPin, LOW);
}
Build a circuit as described in the Button example (pushbutton attached to pin 2 from +3.3V and 10K resistor attached to pin 2 from ground):
The 10k resistor is acting as a PULLDOWN resistor, meaning that in the absence of a connection to +3.3V, pin 2 will report it's connection to ground (LOW). Essentially we've created a "path of some resistance" to ground. When the button is unpressed, the circuit will take this path. When the button is pressed, a "path of much less resistance" is created to +3.3V, so pin 2 will report HIGH. What happens if you remove the resistor? Try moving your hand around the circuit. The results will be unpredictable (floating input). Read more about pullup and pulldown resistors on SparkFun.
We can convert this to a PULLUP resistor configuration by switching the 3.3V and GND connections on the breadboard. The behavior of the button is now reversed (pressing button turns LED off).
Luckily, many microcontrollers have built-in PULLUP resistors, which operate in the opposite way. Open the DigitalInputPullup example and rewire your circuit so that the button connects pin 2 to ground:
This example also allows us to see what's going on under the hood with the Serial monitor.
We can put conditional statements inside one another in order to see if multiple conditions have been met. A great tool in Arduino is the millis()
function, which returns the number of milliseconds since the program began. We can make a simple time-based conditional statement:
if (millis() > 3000) {
// turn LED on:
digitalWrite(ledPin, HIGH);
} else {
// turn LED off:
digitalWrite(ledPin, LOW);
}
Now, we can nest that inside of our previous conditional statement:
if (buttonState == HIGH) {
if (millis() > 3000) {
// turn LED on:
digitalWrite(ledPin, HIGH);
} else {
// turn LED off:
digitalWrite(ledPin, LOW);
}
}
Logical operators are used to combine two or more relational expressions and to invert logical values. They allow for more than one condition to be considered simultaneously.
The logical operators are symbols for the logical concepts of AND (&&), OR (||), and NOT (!):
Expression | Evaluation |
---|---|
true && true | true |
true && false | false |
false && true | false |
true || true | true |
true || false | true |
false || false | false |
!true | false |
!false | true |
If we consider a = 8 and b = 12, we'd follow these steps in order to resolve the expression (a > 4) || (b < 24):
In this example, the expression "a > 15" is false, but "b < 30" is true. Because the OR operator requires only one part to be true in the entire expression, the code in the block will run. Try changing the code to logical AND instead of OR
const int ledPin = 13;
void setup(){
pinMode(ledPin, OUTPUT);
int a = 10;
int b = 20;
if ((a > 15) || (b < 30)) {
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}
}
We can modify our previous Button example such that both conditions are written in the same line.
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
// check if the pushbutton is pressed AND more than 3 seconds have passed.
// If both are true, the buttonState is HIGH:
if (buttonState == HIGH && millis() > 3000) {
// turn LED on:
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}
}
for()
Loops For this exercise, please collect the following:
The for()
structure performs repetitive calculations and is structured like this:
for (init; test; update) {
statements
}
Let's connect an LED to pin 10 with a 1K resistor in series.
Let's say you want to incrementally brighten an LED. You might do that with repetitive commands:
int PWMpin = 10; // LED in series with 1K resistor on pin 10
void setup() {
// no setup needed
}
void loop() {
analogWrite(PWMpin, 0);
delay(100);
analogWrite(PWMpin, 50);
delay(100);
analogWrite(PWMpin, 100);
delay(100);
analogWrite(PWMpin, 150);
delay(100);
analogWrite(PWMpin, 200);
delay(100);
analogWrite(PWMpin, 250);
delay(100);
}
However, the same result can be generated with fewer lines of code using a for
loop:
int PWMpin = 10; // LED in series with 1K resistor on pin 10
void setup() {
// no setup needed
}
void loop() {
for (int i = 0; i <= 255; i=i+50) {
analogWrite(PWMpin, i);
delay(100);
}
}
This flexible pattern allows you to easily change the resolution of the fade:
int PWMpin = 10; // LED in series with 1K resistor on pin 10
void setup() {
// no setup needed
}
void loop() {
for (int i = 0; i <= 255; i++) {
analogWrite(PWMpin, i);
delay(10);
}
}
The statements inside the loop can include conditional statements, and vice versa. Try modifying the conditions to get different results:
void loop() {
for (int i = 0; i <= 255; i++) {
if (millis() >= 2000) {
analogWrite(PWMpin, i);
} else {
analogWrite(PWMpin, 0);
}
delay(10);
}
}
The modulus operator is often used within loops to create cycles:
void loop() {
if (millis()%500 > 100) {
analogWrite(PWMpin, 255);
} else {
analogWrite(PWMpin, 0);
}
delay(10);
}
The modulus operator could even replace the for()
loop as a timer, which would produce a more precise cycle based on clock time instead of delays.
The for
structure allows us to cycle through the range of one parameter. Nesting this structure allows us to create more complex cycles. In this example, instead of always fading to the maximum analog value (255), we start by fading from 0-0, then 0-1, etc. until we fade from 0-255. Our new "maximum" variable is incremented in the outside loop.
void loop() {
for (int maximum = 0; maximum <= 255; maximum++) {
for (int i = 0; i < maximum; i++) {
analogWrite(PWMpin, i);
delay(1);
}
}
}
Now let's connect a potentiometer to A0, and open the AnalogInput example (File > Examples > Analog > AnalogInput). This example uses the potentiometer to control the blink frequency. See if you can modify that example so that the potentiometer controls the "maximum" variable in the for()
loop we used before:
void loop() {
// set maximum equal to the incoming value
for (int i = 0; i < maximum; i++) {
analogWrite(PWMpin, i);
delay(1);
}
}
You may notice that that sensor values range from 0-1023 while the analogWrite() function wants values between 0-255. Try using the map() function to convert one range to another. Your final code may look something like this:
int PWMpin = 10; // LED in series with 470 ohm resistor on pin 10
int potpin = A0; // select the input pin for the potentiometer
int potValue = 0; // variable to store the value coming from the sensor
int maximum;
void setup() {
Serial.begin(9600);
}
void loop() {
maximum = map(analogRead(potpin), 0, 1023, 0, 255);
Serial.println(maximum);
for (int j = 0; j < maximum; j++) {
analogWrite(PWMpin, j);
delay(1);
}
}
This is just the beginning! Please check out Arduino's default examples as well as additional examples in the Arduino Projects Book .