2 Structure
2 Structure
Structure
Created by: Dr. Daniel van Niekerk
Structure: setup()
• Description
̶ The setup() function is called when the sketch or code initially starts executing.
̶ It is mainly used to start using libraries, set digital pin modes and initialize variables.
̶ The setup() function only runs once, after each power-up or reset of the Arduino board.
• Example
const int pinButton = 3;
int iCnt;
void setup()
{
Serial.begin(9600); // start using libraries
pinMode(pinButton, INPUT); // set digital pin modes
iCnt = 10; // initialize variables
}
void loop()
{
// Statments...
}
Structure: loop()
• Description
̶ Runs after the setup() function, which configures initial values.
̶ The loop() function loops consecutively, allowing the user program to respond as input
data changes, thereby actively controlling the Arduino microcontroller output behavior.
• Example
const int pinButton = 3;
// setup initializes serial port and push button input pin
void setup() {
Serial.begin(9600);
pinMode(pinButton, INPUT);
}
// loop checks push button each time and will send serial if pressed
void loop() {
if(digitalRead(pinButton) == HIGH)
Serial.write('H');
else
Serial.write('L');
delay(1000); // wait one second before checking push button again
}
Control Structures: if (condition)
• Description
̶ if statement is used in conjunction with comparison operators, to test whether a
certain condition has been reached.
̶ For example if an input is above a certain number:
if(someVariable > 50){
// do something here
}
̶ When the condition in parentheses is true, the statements inside curly braces execute.
̶ If not true, the program skips over the statements inside the curly braces.
̶ Curly braces may be omitted after if statement, only with one conditional statement.
if(x > 120) digitalWrite(pinLED, HIGH);
̶ else can be proceeded by another if therefore, multiple exclusive tests can be done.
̶ Each test will proceed to the next one until a true test is encountered.
̶ When a true test is found, its associated block of code is run and the program then skips
to the line of code after the entire if/else construction.
Control Structures: else / if
̶ If no test proves to be true the default else block is executed, only if it is present and
therefore, will determine the default behavior.
̶ Note that an else/if block may be used with or without a terminating else block.
̶ An unlimited number of such else/if branches is allowed.
iVal = analogRead(A0); // read analog input pin A0
if(iVal < 500)
{
// do action A
}
else if(iVal >= 1000)
{
// do action B
}
else
{
// do default action
}
̶ Another way to express branching mutually exclusive tests, is with the switch…case
statement.
Control Structures: switch…case statements
• Description
̶ Like if statements, switch...case controls the flow of programs.
̶ It allows different code to executed depending on varying conditions.
̶ A switch statement compares the value of a variable to the values specified in the case
statement.
̶ When a case statement’s value matches the tested switch variable, the code in that
case statement is executed.
̶ Falling-through then occurs because the following case code will also be executed.
̶ However, the break statement can exit the switch statement and should be used at the
end of each case.
̶ Without a break statement, the switch statement will continue executing the following
case code until a break or the end of the switch is reached.
Control Structures: switch…case statements
• Syntax
switch(cVar)
{
case Constant_1:
// execute statements if cVar = Constant_1
break;
case Constant_2:
// execute statements if cVar = Constant_2
break;
default:
// execute statements if cVar != Constant_1 or Constant_2
}
• Parameters
̶ cVar: an integer or char variable’s value to compare to the various case constants.
̶ Constant: a constant literal value to compare the variable’s value too.
̶ switch provides a more elegant decision making structure than if, for multiple
conditions (if … else if … else if … else …).
̶ The drawback is that the conditions may only be constant literal values therefore, a
match of the variable's data to a particular constant literal value.
Example: switch…case statements
switch(cVar)
{
case 1:
//do something when cVar equals 1
break;
case 2:
//do something when cVar equals 2
break;
default:
// if nothing else matches, do the default (optional)
}
switch(cLetter)
{
case 'a':
Serial.println("Letter 'a' found in variable."); break;
case 'b':
Serial.println("Letter 'b' found in variable."); break;
case 'c':
Serial.println("Letter 'c' found in variable."); break;
default:
Serial.println("No valid letter found in variable.");
}
Example: switch…case statements
void setup(){
Serial.begin(9600);
}
void loop(){
/* wait to receive serial data */
while(!Serial.available());
/* read serial byte received */
char channel = Serial.read();
/* decide on response message */
switch(channel)
{
case '7'...'9': // apply this case to channel 7, 8 and 9
Serial.println("UHF Station"); break;
case '4'...'6': // apply this case to channel 4, 5 and 6
Serial.println("VHF Station"); break;
case '1': // case 1 and 2 are allowed to fall through to case 3
case '2':
case '3':
Serial.println("Weak Signal"); break;
default:
Serial.println("No Signal Available");
}
}
Control Structures: for statements
• Description
̶ The for loop statement is used to repeat a block of statements enclosed in curly braces.
̶ A counter is increment that is usually used to terminate the for loop.
̶ The for loop statement is useful for any repetitive operation and is often used in
combination with arrays to operate on collections of data or pins.
̶ There are three parts to the for loop header:
void setup() {
// no setup required
}
void loop()
{
for(int i=0; i<=255; i++)
{
analogWrite(pinPWM, i); // increase PWM every 10 ms
delay(10);
}
}
Control Structures: for statements
• Coding Tips
̶ Any or all of the three header elements may be omitted, but semicolons are required.
̶ Also, the statements for initialization, condition, and increment can be any valid C
statements with unrelated variables and use any C datatypes, including floats.
̶ These types of unusual for statements provide solutions to rare programming problems.
̶ Example: multiplication in the increment will generate a logarithmic progression.
// Generates: 2,4,8,16,32,64,128,256,512,1024,2048 etc…
for(int x = 2; x < 100; x = x * 2) {
println(x);
}
// Another example, fade an LED up and down with one for loop:
void loop(){
int x = 1;
for(int i=0; i>-1; i=i+x) // or use for(int i=0; i>-1; i+=x)
{
analogWrite(pinPWM, i);
if(i == 255) x = -1; // switch direction at peak “i” value
delay(10);
}
}
Control Structures: while loops
• Description
̶ while loops will continuously loop until the expression inside the parenthesis “( )”,
becomes false.
̶ The tested variable must change or the while loop will never end.
̶ This can be inside the while loop, such as incrementing the tested variable.
̶ Or an external condition, such as testing a sensor reading that changes.
• Syntax
while(expression)
{
// execute statement(s) as long as expression is true
}
• Parameters
̶ expression: any Boolean C statement that evaluates to true or false.
• Example
...
int iVar = 0;
while(iVar < 200)
{
// do some repetitive process for 200 times
iVar++;
}
...
Control Structures: do…while loop
• Description
̶ The do…while loop works in the same manner as the while loop.
̶ The exception is that the do…while condition is tested at the end of the loop.
̶ So the do…while loop code will always execute at least once.
• Syntax
do
{
// statement block
}while(test condition);
• Example
...
do
{
delay(50); // wait for sensor to stabilize
int iVar = analogRead(A0); // check the sensor reading again
}while(iVar < 100);
...
Control Structures: break
• Description
̶ A break statement is used to exit from a for, while or do…while loop and a switch…case
control structure thereby, bypassing normal code execution steps.
• Example
const int pinPWM = 10, pinSens = A0;
int iSens, iThreshold = 512;
...
for(int iPwm = 0; iPwm <= 255; iPwm++)
{
analogWrite(pinPWM, iPwm); // increase light bulb intensity
iSens = analogRead(pinSens); // get voltage divider LDR change
if(iSens > iThreshold) // bail out when sensor value > 512
{
analogWrite(pinPWM, 0); // switch off PWM
break; // exit for loop
}
delay(50); // short delay allows light bulb intensity to increase
}
...
Control Structures: continue
• Description
̶ A continue statement skips the rest of the statements inside either a for , while or
do…while loop.
̶ It then continues by checking the conditional expression of the loop and proceeds with
any subsequent iterations.
• Example
const int pinPWM = 10;
void loop()
{
return;
Bailout:
// more statements ...
Further Syntax: ; (semicolon)
• Description
̶ Used to end an instruction to form a C statement.
• Example
...
int iCnt = 0; // end line with ‘;’
do
{
Serial.println(iCnt); // end line with ‘;’
iCnt = iCnt + 1; // end line with ‘;’
}while(iCnt < 10); // end line with ‘;’
...
• Note
̶ Forgetting to end a line with a semicolon will result in a compiler error.
̶ The compiler error may be obvious and refer to a missing semicolon or it may not.
̶ If a seemingly illogical compiler error comes up, one of the first things to check is a
missing semicolon in the immediate vicinity and preceding the line of the compiler
error code line indicator.
Further Syntax: {} Curly braces
• Description
̶ Curly braces (also referred to as "braces" or as "curly brackets") is a major part of the C
programming language.
̶ They are used in several different constructs and can sometimes be confusing to new
programmers.
̶ An opening curly brace "{" must always be followed by a closing curly brace "}".
̶ This is a condition that is often referred to as: balance of curly braces.
̶ The Arduino integrated development environment (IDE) software includes a convenient
feature to check the balance of curly braces.
̶ Just select a brace or even click the insertion point immediately following a brace and its
logical companion will be highlighted in the IDE.
Further Syntax: {} Curly braces
̶ Beginner programmers and programmers coming to C from the BASIC language often
find using braces confusing or daunting.
̶ After all, the curly braces replace the RETURN statement in BASIC language functions,
the ENDIF statement in a conditional IF and the NEXT statement in a FOR loop.
̶ Because the curly brace is required in C, it is good programming practice to type a
closing brace immediately after typing the opening brace, when inserting a code block
construct which requires curly braces.
̶ Then insert some carriage returns between braces and begin inserting statements.
̶ In this way, braces will then never become unbalanced.
̶ Unbalanced braces can often lead to cryptic compiler errors that can sometimes be
hard to track down in a large program.
̶ Curly braces are incredibly important to the syntax of a C program.
̶ Moving a curly brace one or two lines, will often dramatically affect the operation of a C
program.
Examples: {} Curly braces
• The main uses of curly braces
//Functions
void myfunction(datatype argument)
{
//statements(s)
}
//Loops
while(boolean expression)
{
//statement(s)
}
do
{
//statement(s)
} while(boolean expression);
̶ Also, including an equal sign after the #define statement, will generate a compiler error.
#include <avr/pgmspace.h>
const unsigned int uiData[] PROGMEM = {1000, 1500, 2000, 2500, 3000,
3500, 4000, 4500, 5000, 5500,
6000, 6500, 7000, 7500, 8000,
8500, 9000, 9500, 10000};
Arithmetic Operators: Assignment operator (=)
• Description
̶ Stores value to the right of the equal sign, in the variable to the left of the equal sign.
̶ The single equal sign in the C programming language is called the assignment operator.
̶ Has a different meaning than in algebra, where it indicates an equation or equality.
̶ The assignment operator tells the microcontroller to evaluate whatever value or
expression is on the right side of the equal sign and store it in the variable to the left of
the equal sign.
• Example
int iSenVal; // declare an integer variable named iSenVal
• Programming Tips
̶ The variable on the left side of the assignment operator needs to be able to store the
size of the value assigned to it.
̶ If it is not large enough to hold a value, the value stored in the variable will be incorrect.
̶ Don't confuse the assignment operator (“= ” single equal sign) with the comparison
operator (“== ”, double equal signs), which evaluates whether two expressions are
equal.
Addition, Subtraction, Multiplication, & Division
• Description
̶ These operators return the sum, difference, product, or quotient of the two operands.
̶ The operation is conducted using the data type of the operands
̶ For example: 9 / 4 gives 2, only if 9 and 4 are integers.
̶ This also means that the operation can overflow if the result is larger than what can be
stored in the data type (e.g. adding 1 to an integer variable that contains a value of
32767, results in -32768).
̶ If operands are of different data types, the "larger" type is used for the calculation.
̶ If one of the numbers (operands) are of the type float or type double, then floating
point math will be used for the calculation.
• Examples
y = y + 3;
x = x - 7;
i = j * 6;
r = r / 5;
• Syntax
̶ result = value1 + value2;
̶ result = value1 - value2;
̶ result = value1 * value2;
̶ result = value1 / value2;
Addition, Subtraction, Multiplication, & Division
• Parameters:
̶ value1: any variable or constant value
̶ value2: any variable or constant value
• Programming Tips:
̶ Know that integer constants default to int, so some constant calculations may overflow
(e.g. 60 * 1000 will yield a negative result, because 60000 > 32767).
̶ Choose a variable size that is large enough to hold the largest result of the calculation.
̶ Know at what point the variable will "roll over" and also what happens in the other
direction (e.g. for an integer: (+32767 + 1) = –32768 and (–32768 – 1) = +32767).
̶ For math that requires fractions the variables must be float data types.
̶ However, the disadvantage of using a float data type, is slower computation speeds and
a larger required storage memory size.
̶ Use the cast operator “(int) myFloat”, to convert one variable data type to another on
the fly.
Arithmetic Operators: Modulo (%)
• Description
̶ Calculates the remainder, when one integer is divided by another.
̶ It is useful for keeping a variable within a particular range.
̶ Can be used to maintain the same size of an array (see example code).
• Syntax
̶ remainder = dividend % divisor
• Parameters
̶ dividend: the number to be divided.
̶ divisor: the number to divide by.
• Returns
̶ The remainder value.
• Examples
x = 7 % 5; // x now contains 2
x = 9 % 5; // x now contains 4
x = 5 % 5; // x now contains 0
x = 4 % 5; // x now contains 4
• Note
̶ The modulo operator does not work on float data types.
Example: Modulo (%)
/* maintain the same size of an array */
int iValues[10];
int iCnt = 0;
int iSum;
void setup(){
Serial.begin(9600);
}
void loop(){
// update one value in an array each time through the loop
iValues[iCnt] = analogRead(A0);
// when modulo is 10, remainder value will always be between 0 and 9
iCnt = (iCnt + 1) % 10; // modulo operator limits iCnt to < 10
if(iCnt == 0) // after obtain 10 sensor values, find ave
{
iSum = 0;
for(int i=0; i<10; i++)
iSum = iSum + iValues[i];
Serial.print("New averge: ");
Serial.println(iSum/10);
}
delay(250); // delay between sensor readings
}
Comparison Operators: ==, !=, <, >
̶ If statement uses a comparison operator to test whether a certain condition is true.
̶ Such as an input value above a certain number, for example:
̶ Using & between two int expressions causes 16 simultaneous AND operations to occur:
int a = 92; // in binary: 0000000001011100
int b = 101; // in binary: 0000000001100101
int c = a & b; // result: 0000000001000100, or 68 in decimal
̶ Each of the 16 bits in “a” and “b” are processed by using the bitwise AND operator and
all 16 resulting bits are stored in “c”
̶ One of the most common uses of bitwise AND is to set a particular bit (or bits) of an
integer value to zero, by using a masking integer where the particular bit (or bits) are
zero.
Bitwise Operator: OR (|)
• Description
̶ The bitwise OR operator is the vertical bar symbol ‘|’.
̶ Like the ‘&’ operator the ‘|’ operates independently on each bit between two integers.
̶ The bitwise OR of two bits is 1, if either or both of the bits are 1, otherwise it is 0:
0 0 1 1 //operand1
0 1 0 1 //operand2
----------
0 1 1 1 //(operand1 | operand2) - returned result
̶ One of the most common uses of bitwise OR is to set a particular bit (or bits) of an
integer value to one, by using a masking integer where the particular bit (or bits) are
one.
Bitwise Operator: XOR (^)
• Description
̶ The bitwise XOR operator is written using the caret symbol ‘^’.
̶ The bitwise XOR of two bits is 0, if both of the bits for that position are 1 or 0:
0 0 1 1 //operand1
0 1 0 1 //operand2
----------
0 1 1 0 //(operand1 ^ operand2) - returned result
̶ Another way to understand the bitwise XOR operator, is that each bit in the result is a 1
if the input bits are different, or 0 if the input bits are the same.
̶ Here is a simple code example:
int x = 12; // binary: 0000000000001100
int y = 10; // binary: 0000000000001010
int z = x ^ y; // binary: 0000000000000110, or decimal 6
̶ The ‘^’ operator is often used to toggle (change from 0 -> 1 or 1 -> 0) some of the bits in
an integer expression.
̶ One of the most common uses of bitwise XOR is to toggle a particular bit (or bits) of an
integer value, by using a masking integer where the particular bit (or bits) are one.
Bitwise Operator: NOT (~)
• Description
̶ The bitwise NOT operator is the tilde character ‘~’.
̶ Unlike ‘&’ and ‘|’, the bitwise NOT operator is applied to a single operand to its right.
̶ The bitwise NOT operator changes each bit to its opposite state (0->1 and 1-> 0).
̶ For example:
0 1 //operand1
----
1 0 //~ operand1
̶ The result is a negative number because the highest bit in an int variable is the sign bit.
̶ If the sign bit is 1, the number is interpreted as negative.
̶ This encoding of positive and negative numbers is referred to as two's complement.
̶ Therefore, complement or bitwise NOT the rest of the bits, add 1, convert the binary
number to decimal and then put the negative sign in front to get “-104”.
Operator: Bit shift left (<<), Bit shift right (>>)
• Description
̶ There are two bit shift operators, left shift operator ‘<<’ and right shift operator ‘>>’.
̶ These operators cause the bits in the left operand to be shifted left or right by the
number of positions specified by the right operand.
• Syntax
̶ variable << number_of_bits
̶ variable >> number_of_bits
• Parameters
̶ Variable: (byte, int, long)
̶ number_of_bits: an integer of less than or equal to 32.
• Example:
int a = 5; // binary: 0000000000000101
int b = a << 3; // binary: 0000000000101000, or 40 in decimal
int c = b >> 3; // binary: 0000000000000101, or back to 5
̶ When you shift a value x by y bits (x << y), the leftmost y bits in x are lost, literally
shifted out of existence:
int a = 5; // binary: 0000000000000101
int b = a << 14; // binary: 0100000000000000
// the first 1 in 101 was discarded or lost
Operator: Bit shift left (<<), Bit shift right (>>)
̶ The left-shift operator ‘<<’ can be used as an efficient way to multiply the left operand
by 2 raised to the right operand power.
̶ Therefore: y = x << 3, is the same as y = x * 2^3
̶ For example, to generate powers of 2, the following expressions can be employed:
1 << 0 == 1 // 2^0 = 1
1 << 1 == 2 // 2^1 = 2
1 << 2 == 4 // 2^2 = 4
...
1 << 7 == 128 // 2^7 = 128
1 << 8 == 256 // 2^8 = 256
...
̶ When you shift x right by y bits (x >> y) and the highest bit in x is a 1, the behavior
then depends on the exact data type of x.
̶ If x is of type int, the highest bit is the sign bit determining whether x is negative or not.
̶ If x is negative, the sign bit is copied into lower bits:
̶ By avoiding sign extension, the right-shift operator ‘>>’ can be used as an efficient way
to divide the left operand by 2 raised to the right operand power.
̶ Therefore: y = x >> 3, is the same as y = x / 2^3.
̶ For example:
int x = 1000;
int y = x >> 3; // integer division of 1000 by (2^3 = 8), y = 125
Compound Operators: Increment (++), Decrement (--)
• Description
̶ First increment/decrement a variable’s value and then use the variable value.
̶ Or use the variable value and then increment/decrement the variable’s value.
• Syntax
x++; // use x and then increment x by one
++x; // increment x by one and then use x
• Parameters
̶ x: an int or long and possibly unsigned.
• Returns
̶ The incremented or decremented value of the variable.
• Examples
x = 2;
y = ++x; // x now contains 3, y contains 3
y = x--; // x contains 2 again, y still contains 3
Compound Operators: += , -= , *= , /= , %=
• Description
̶ Performs a mathematical operation on a variable with another constant or variable.
̶ The += operators are just a convenient shorthand for the expanded syntax, listed below.
• Syntax
x += y; // equivalent to: x = x + y;
x -= y; // equivalent to: x = x - y;
x *= y; // equivalent to: x = x * y;
x /= y; // equivalent to: x = x / y;
x %= y; // equivalent to: x = x % y;
• Parameters
̶ x: any variable data type.
̶ y: any variable data type or constant.
• Examples
x = 2;
x += 4; // x now contains 6
x -= 3; // x now contains 3
x *= 10; // x now contains 30
x /= 2; // x now contains 15
x %= 5; // x now contains 0
Compound Operators: Bitwise AND (&=)
• Description
̶ The compound bitwise AND operator ‘&=’ is often used with a variable and a constant
to force or clear particular bits in a variable to zero.
̶ This is often referred to as "clearing" or "resetting" bits.
• Syntax:
x &= y; // equivalent to x = x & y;
• Parameters
̶ x: a char, int or long variable.
̶ y: an integer constant or char, int or long variable.
• Example:
0 1 1 1 //operand1
1 1 0 0 //operand2
----------
0 1 0 0 //(operand1 & operand2) - returned result
̶ Bits that are "bitwise ANDed" with 0 are cleared to 0, so if myByte is a byte variable
then: myByte & B00000000 = 0.
̶ Bits that are "bitwise ANDed" with 1 are unchanged, so if myByte is a byte variable
then: myByte & B11111111 = myByte.
Compound Operators: Bitwise AND (&=)
• Note
̶ When using the bitwise operator, it is convenient to use the binary formatter with
constants (such as B10101010).
̶ To clear bits 0 & 1 of a variable, while leaving the rest of the variable unchanged, use the
compound bitwise AND operator ‘&=’ with the constant B11111100.
1 0 1 0 1 0 1 0 //variable
1 1 1 1 1 1 0 0 //mask
----------------------
1 0 1 0 1 0 0 0
̶ Here is the same representation with the variable's bits replaced with the symbol x
x x x x x x x x //variable
1 1 1 1 1 1 0 0 //mask
----------------------
x x x x x x 0 0
̶ Bits that are "bitwise ORed" with 0 are unchanged, so if myByte is a byte variable
then: myByte | B00000000 = myByte.
̶ Bits that are "bitwise ORed" with 1 are set to 1, so if myByte is a byte variable
then: myByte | B11111111 = B11111111.
Compound Operators: Bitwise OR (|=)
̶ To set bits 0 & 1 of a variable, while leaving the rest of the variable unchanged, use the
compound bitwise OR operator ‘|=’ with the constant B00000011.
1 0 1 0 1 0 1 0 //variable
0 0 0 0 0 0 1 1 //mask
----------------------
1 0 1 0 1 0 1 1
̶ Here is the same representation with the variables bits replaced with the symbol x
x x x x x x x x //variable
0 0 0 0 0 0 1 1 //mask
----------------------
x x x x x x 1 1