Schedule‎ > ‎

06A: Counting Loops and Bar Charts

Questions, Answers and Review

  • Questions from last class?
  • Questions about labs or upcoming homework?

^ top


Counting Loops

Learner Outcomes

At the end of the lesson the student will be able to:

  • Design and implement counting loops
  • Apply counting loops to solve counting problems
  • Translate these designs into C/C++ code

^ top

Using Loops to Count

  • Counting is a way to solve many programming problems
  • As an example, assume we want a program to write a list of numbers
  • We want to start at the number 1 and let the user choose the ending number
  • Thus the program output will look something like:
    This program writes lists of numbers.
    Enter the maximum number:
    1
    2
    3
    4
    5
    
  • We cannot simply write five numbers with cout because the user chooses the maximum number
  • To help us understand how to approach the problem we try out some counting examples

ActivityA series of steps

  • Clap your hands 10 times.
  • True or false: as you are clapping, you are repeating an action.
  • You know when to stop clapping because you ________.
  • True or false: as you are counting, you are testing the count against the number 10.
  • Every time you clap, you update the count by ________.

Looping Statements

  • It turns out that counting is a very common use of loops
  • Loops that are controlled by a counter variable are called counter-controlled loops
  • We can visualize a counter-controlled loop as a series of steps to reach a goal
  • We use a counting variable to keep track of the number of times the loop has repeated
  • We have looked at two looping statements previously: for and while
  • Both statements can be used to solve counting problems, but the for loop is the one designed for counting
  • To finish designing our counting application, we will review our previous use of the for statement

Check Yourself

  1. For a computer to remember a count, we write code to declare a ________.
  2. Loops that are controlled by a counter variable are know as ________ loops.
  3. True or false: counter-controlled loops end after a certain number of steps.

^ top

Understanding for Statements

  • We have used for loops previously to repeat commands a certain number of times
  • For example, we wrote a sketch that:
    1. Blinks 20 times
    2. Pauses for 3 seconds
    3. Starts again
  • We could have written the blink code 20 time, like:
    digitalWrite(ledPin, HIGH);
    delay(delayPeriod);
    digitalWrite(ledPin, LOW);
    delay(delayPeriod);
    // repeat above 4 lines 20x
    delay(3000);
    
  • Such code requires lots of typing and is error prone

Looping with for

  • To repeat code a specific number of times we use a for-loop:
    for (int i = start; i < end; i = i + 1) {
        // code to repeat
    }
    
  • Where:
    • i: the name of a counter variable
    • start: the initial starting count
    • end: the final ending count
  • The commands to repeat are placed inside the curly braces
  • The looping code is shorter and easier to maintain than repeated code

Example for-loop Code

for (int i = 0; i < 20; i = i + 1) {
  digitalWrite(ledPin, HIGH);
  delay(delayPeriod);
  digitalWrite(ledPin, LOW);
  delay(delayPeriod);
}
delay(3000);

Diagram of for Loop Operation

for loop flow chart

Execution Steps

  1. When for loop is reached, execute the initialize statement (example: int i = 0)
  2. Check if condition is true (example: i < 20)
    1. if true then continue with Step 3
    2. Otherwise it is false so continue with Step 6
  3. Execute the block containing the statements to repeat (body)
  4. When end of loop body is reached, execute the update statement (example: i = i + 1)
  5. Return to Step 2
  6. Loop is finished: continue with statements after the loop

Check Yourself

for (int i = 0; i < max; i++) {
  cout << i;
}
  1. In the loop above, the initialization statement is ________.
    1. int i = 0
    2. i < max
    3. i++
    4. cout << i;
  2. In the same loop, the test condition is ________.
    1. int i = 0
    2. i < max
    3. i++
    4. cout << i;
  3. In the same loop, the update statement is ________.
    1. int i = 0
    2. i < max
    3. i++
    4. cout << i;
  4. In the same loop, if max is 3 the loop prints ________.
    1. 0, 1, 2, 3
    2. 1, 2, 3
    3. 0, 1, 2
    4. 1, 2, 3, 4

More Information

^ top

Exercise 1: Counting Numbers (5m)

  1. Start the Arduino IDE with a new sketch and save the program as counting.
  2. In the setup() function print the following to the user: 
    This sketch writes lists of numbers.
    Enter the maximum number:
    
  3. In the loop() function, add the code to get the maximum number from the user:
  4. After getting the input, add a loop to print out a count from 1 to the maximum number the user entered.
  5. Compile and run your code to verify it works.
    1. Does it start and stop with the correct numbers?
    2. If not, what needs to change?  make any changes needed.
  6. Save your counting.ino file to submit to Canvas.

When finished, please help those around you.

Summary

  • The for statement is used to repeat a block of statements enclosed inside its curly braces
  • A for statement is used whenever we have a certain number of commands to repeat
  • We use a counter variable to keep count of the number of iterations
  • Also, we use a test condition to decide when to keep looping and when to stop
  • The following is an illustration of the syntax of a for loop
For loop illustrate
  • We can use a counting loop to sum a series of numbers
    float sum = 0.0;
    for (int i = start; i < end; i++) {
      int value = Serial.parseFloat();
      sum += value;
    }
    
  • The summing loop requires a separate variable to tally the sum
  • With the sum, we can compute an average
    float average = sum / (end - start);
    
  • By changing the update statement we can sum only a portion of the numbers, like:
    for (int i = 0; i < 5; i += 2)
    
  • In addition, we can change the starting or ending value to remove some numbers from the sum
    for (int i = 1; i < 5; i += 2)
    
  • Be the computer
    Be the computer
    To truly understand what a loop is doing, we need to "be the computer" and trace the loop
  • To trace the loop we track all the values of the variables affected by the loop, like:
    sum   i   reading
    ---   -   -------
    0     0   1
    1     1   2
    3     2   3
    ...
    
  • As another looping application, we looked at Pulse-Width Modulation (PWM)
  • The analogWrite() function controls the duty cycle of power supplied to an output pin
  • This technique is called Pulse Width Modulation (PWM) and is used for getting analog results with digital controls
  • The following graphic shows PWM with various duty cycles

^ top

^ top

Counting Loop Applications

Learner Outcomes

At the end of the lesson the student will be able to:

  • Apply counting loops to solve a number of problems
  • Use counting loops to sum and average a series of numbers
  • Use a counting loop to apply the complete range of pulses for Pulse Width Modulation (PWM)

^ top

Averaging a Sensor Reading

  • Recall the temperature testing we did with the TMP36 Sensor
  • Here is the Fritzing file for the circuit: tmp36.fzz
  • We started with the following circuit breadboard

    Temperature measuring breadboard circuit

  • To measure the sensor we used a function like:
    double readTemperatureSensor() {
      int reading = analogRead(0);
      double voltage = (reading * 5.0) / 1024;
      cout << voltage << " volts" << endl;
      return voltage;
    }
    

Smoothing Readings

  • Sometimes a sensor reading fluctuates and gives "jumpy" readings
  • One way to solve the problem is to take multiple readings and average them
  • Continuously averaging a series of numbers is a form of data smoothing
  • To find an average, we sum a series of numbers and then divide by the count of numbers
  • If we wanted to average 5 readings, we would add a for-loop as shown below

Averaging Sensor Readings

double readTemperatureSensor() {
  float sum = 0.0;
  for (int i = 0; i < 5; i++) {
    int reading = analogRead(0);
    sum += reading;
    delay(1);
  }
  float average = sum / 5;
  float voltage = (average * 5.0) / 1024;
  cout << voltage << " volts" << endl;
  return voltage;
}

Check Yourself

  1. When sensor numbers are "jumpy", it is because the sensor readings ________.
  2. True or false: one technique to smooth jumpy readings is to average the numbers.
  3. In the following loop, if the analogRead() function returns the numbers 1, 2, 3, 4, 5 the value of sum after the loop finishes executing the sum is ________.
    double sum = 0.0;
    for (int i = 0; i < 5; i++) {
      int reading = analogRead(A0);
      sum += reading;
      delay(1);
    }
    
  4. After the above loop completes, the correct statement to average the readings is ________.
    1. int average = sum * 5;
    2. double average = sum / 5;
    3. int average = sum / 5;
    4. double average = sum * sum / 5;

^ top

Summing Numbers and Tracing Loops

  • Whenever we need to sum a list of numbers, coding a loop is a good approach
  • Notice that we have a separate variable to store the sum
    double sum = 0.0;
    
  • We need two variables in a summing loop
    • i: the counter variable to store the current count
    • sum: the variable to store the sum of the numbers
  • One we have a sum, we can divide by the number of numbers to find the average
    double average = sum / 5;
    

Variations

  • Sometimes we only want to sum part of the numbers we get
  • We can adjust the summing loop to read a different quantity of readings by changing the starting or ending value
  • For example, if we wanted to read six values we would change the for-loop like:
    for (int i = 0; i < 6; i++)
    
  • We could change the summing loop to read every other value by changing the update statement like:
    for (int i = 0; i < 5; i += 2)
    
  • What numbers does the above loop tally?
  • Another option is to change the starting or ending value
    for (int i = 1; i < 5; i += 2)
    
  • What numbers does the above loop tally?
Be the computer
Be the computer

Tracing a Loop

  • To understand what is happening with these loops it is important to trace iterations
  • In essence, we must "be the computer" and follow it execution path
  • The counting variable is used by the computer to track the number of iterations
  • Thus a good technique is to keep track of the counting variable to understand the loop
  • In addition, we want to keep track of any other variable processed inside the loop
  • For example, with the following loop we would want to track the variables: sum, i, and reading:
    int sum = 0;
    for (int i = 0; i < 5; i++) {
      int reading = analogRead(0);
      sum += reading;
      delay(1);
    }
    
  • Thus we would write out headings for each value and update the variables for each pass of the loop
    sum   i   reading
    ---   -   -------
    0     0   1
    1     1   2
    3     2   3
    ...
    

Activity: Tracing a Loop (4m)

In this activity, we will trace the execution of the following summing loop.

const int END = 10;
int sum = 0;
for (int i = 1; i <= END; i += 2) {
    int input = getNumber(); // assume 1, 2, 3, ... ,10
    sum = sum + i;
}
  1. Take out a piece of paper, write your name on the paper and add headings for the variables in the above code.
  2. Assume that the inputs to the loop are: 1, 2, 3, ... , 10.
  3. Perform each computation of the loop repeatedly until complete, recording both the starting values for every variable and all the changes.
  4. When finished tracing, have a classmate verify your trace and you verify a classmates trace.
  5. Add your name to the paper to show who verified the trace, like:
    Trace verified by Fred George
    
  6. Go over any issues with the class mate that you find in their trace.
  7. Turn in your paper to the instructor after the trace is verified.

Check Yourself

double sum = 0.0;
for (int i = 0; i < 5; i++) {
  int reading = analogRead(A0);
  sum += reading;
  delay(1);
}
  1. True or false: summing numbers in a loop requires a dedicated variable to store the sum.
  2. For the above loop, if the input numbers are 1, 2, 3, 4, 5 the value of sum after the loop finishes executing is ________.
    1. 3
    2. 5
    3. 10
    4. 15
  3. In the above loop, to sum even numbers only we would change the update statement to ________.
  4. To sum odd numbers only, we would additionally change the initialization statement to start at ________.
  5. To compute the product of the numbers, we would change the update statement to use the operator ________.
Be the computer

Be the computer


Bar Charts and Nested Loops

Learner Outcomes

At the end of the lesson the student will be able to:

  • Write code to graph a bar chart
  • Write nested for loops
  • Alternate symbols inside a loop

^ top

Graphing Bar Charts

  • We can use a counting loop to graph a horizontal bar
  • To make the chart, we display a series of '*' characters for the "bar", like:
    cout << '*';
    
  • At the end of the bar, after the loop, we print a newline using:
    cout << endl;
    
  • The following example prints a single bar for every number entered

Example Arduino Application That Displays a Bar Chart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void setup() {
Serial.begin(9600);
cout << "This sketch displays a barchart." << endl;
cout << "Enter the number to chart:" << endl;
}

void loop() {
if (Serial.available()) {
int num = 0;
cin >> num;
cout << num << ": ";
for (int i = 0; i < num; i++) {
cout << '*'; // print one character
}
cout << endl; // newline after the bar
}
}

copy the above code into your arduino ide and run it.

Display Variations

  • We can alternate the symbols displayed by adding an if-else statement inside the for-loop
    for (int i = 0; i < num; i++) {
      if (i % 2 == 0) {
        cout << '*';
      } else {
        cout << '+';
      }
    }
    
  • Remember that the modulus operator is written as % in C/C++
  • The expression i % 2 evaluates to 0 when i evenly divides by 2
  • When the remainder of i / 2, which is written as i % 2, is 0 then i evenly divides by 2
  • If we wanted a tick mark to show every 5 characters we would code something like:
    for (int i = 1; i <= num; i++) {
      if (i % 5 == 0) {
        cout << '+';
      } else {
        cout << '*';
      }
    }
    

Check Yourself

  1. The modulus operator used to calculate the remainder is ________.
  2. The following code snippet displays ________.
    for (int i = 0; i < 5; i++) {
      cout << '*';
    }
    cout << endl;
    
    1. ****
    2. *****
    3. ******
    4. *+*+*+
  3. The following code snippet displays ________.
    for (int i = 0; i <= 5; i++) {
      if ((i % 2) == 0) {
        cout << '+';
      } else {
        cout << '*';
      }
    }
    cout << endl;
    
    1. *+*+*
    2. *+*+*+
    3. +*+*+*
    4. +*+*+*+
  4. The following code snippet displays ________.
    for (int i = 0; i < 5; i++) {
      if (i == (num - 1)) {
        cout << '*';
      } else {
        cout << '.';
      }
    }
    cout << endl;
    
    1.     *
    2. .....*
    3. *.*.*
    4. ....*

^ top

Exercise 2.  Bar Chart

Start with this sample code that we saw earlier:

void setup() {
Serial.begin(9600);
cout << "This sketch displays a barchart." << endl;
cout << "Enter the number to chart:" << endl;
}

void loop() {
if (Serial.available()) {
int num = 0;
cin >> num;
cout << num << ": ";
for (int i = 0; i < num; i++) {
cout << '*'; // print one character
}
cout << endl; // newline after the bar
}
}

Change the code so that it prints a '+' sign every 3 characters.  Save your code as barchart.ino and upload it to Canvas.

Nested Loops

  • Some looping applications have loops nested within other loops
  • For example, we may use a nested loop to print a table of values or draw shapes
  • The following example shows a simple table created with nested loops
  • Let's follow the execution sequence before running the code

Example of Nested Loops

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void setup() {
Serial.begin(9600);
cout << "Outer Inner" << endl;
for (int outer = 1; outer < 4; outer++) {
for (int inner = 1; inner < 4; inner++) {
cout << outer << "\t" << inner << endl;
}
}
}

void loop() {
// no loop code
}

Put the above code into the Arduino IDE and run it.  What does it print out?

Tracing the Variables

  • To understand a looping application, we need to trace the loop by hand
  • To trace the loop, write the variables used in the loop as headings across a page
  • On the first line under the headings, write the initial values
  • Execute the loop 3-5 times and record the values of the variables each time through the loop
  • Pay special attention when entering the loop the first time and when ending the loop
  • We can slightly modify the computations if it helps to test the loop
  • Below is an annotated trace of the variables for the inner and outer loops
  • Note that the outer loop changes only after the inner loop is finished
Memory  Screen 
 outer   inner   
  1   1 1 1
    2 1 2
    3 1 3
    4 (end of loop)    
  2   1 2 1
    2 2 2
    3 2 3
    4 (end of loop)    
  3   1 3 1
    2 3 2
    3 3 3
    4 (end of loop)    
  4 (end of loop)       

Odometer Analogy

  • By analogy, nested loops are like an odometer on a car
  • The inner loop is like the digit to the right on an odometer
  • The numbers to the right loop completely before the number to the left increments by one 

Check Yourself

  1. True or false: a loop can be nested inside another loop.
  2. By analogy to an odometer, an inner loop is like the digits to the ________.
  3. Every time an outer loop iterates once, an inner loop runs ________.
    1. completely
    2. incrementally
    3. partially
    4. twice
  4. To trace a counting loop we need to keep track of the ________.
    1. counter variable
    2. initialization statement
    3. test condition
    4. update statement

^ top

Nested Loop Example: Graphing PWM

  • As an example of nested loops, let us add a bar chart to the PWM project
  • In the loop() section, we had coded a for-loop to pulse the LED

PWM Starter Code

// Pulse an LED using a PWM pin
const int PWM_PIN = 10; // LED in series with 560 ohm resistor

void setup() {
  // no setup needed
}

void loop() {
   for (int i = 0; i < 256; i++) {
      analogWrite(PWM_PIN, i);
      delay(10);
   }
}

Loops Inside of Loops

  • Notice that we already have a loop inside of another loop
  • The loop() section of an Arduino sketch is a built-in loop that every sketch must have
  • Inside of the loop() function we have a for-loop to pulse the LED
  • However, we want to add yet another for-loop inside the existing for-loop
  • This will give us a loop structure that is three loops deep!

Adding a PWM Bar Chart

  • The loop we want to add is to display a bar chart of the current PWM level
  • Since the counter variable i has the current PWM level, we can use it for the ending value of the loop
    int end = i;
    for (int j = 0; j < end; j++) {
      cout << '*';
    }
    cout << endl;
    
  • Notice that the new loop has a new counter variable "j"
  • Use of i, j and k are common in for-loops

Scaling the Bar Chart

  • PWM values range from 0 to 255
  • Thus adding the above loop displays a bar chart that is up to 255 characters wide
  • We can reduce the range of values to make a more displayable chart
  • A convenient value is to reduce the width of the chart by a factor of 8
  • Thus, we would print a single '*' character for every 8 values
  • Why is a factor of 8 a convenient value?
  • The following code displays a the bar chart scaled by a factor of 8

Code for a Scaled Bar Chart

if (i % 8 == 0) { // every eighth iteration
  int end = i / 8; // scale the width
  for (int j = 0; j < end; j++) {
    cout << '*';
  }
  cout << endl;
}

Check Yourself

  1. The expression i % 8 == 0 evaluates to true when the value of i is ________.
    1. 21
    2. 16
    3. 42
    4. 50
  2. The value of the expression 17 / 10 is ________.
  3. For the following code snippet, the newline is printed ________.
    for (int j = 0; j < end; j++) {
      cout << '*';
    }
    cout << endl;
    
    1. at the end of each row
    2. at the end of each column
    3. when j < end
    4. when j updates (j++)

^ top

Exercise 3: Graphing the PWM Value

In this exercise we add bar graphs to the starter code of the PWM project from the last exercise.

Parts

  • Arduino board
  • USB cable
  • Solderless breadboard
  • LED (any color)
  • 560Ω resistor
  • Jumper Wires

Breadboard Layout

Breadboard circuit to pulse an LED

  • Start with the Arduino unplugged.
  • Breadboard the circuit as shown in the image.
  • The flat edge (cathode) of the LED is connected to ground through a 560Ω resistor
  • The longer LED lead is connected to pin 10, which supplies power
  • To test the circuit use the following code

PWM Starter Code

// Pulse an LED using a PWM pin
const int PWM_PIN = 10; // LED in series with 560 ohm resistor

void setup() {
  // no setup needed
}

void loop() {
   for (int i = 0; i < 256; i++) {
      analogWrite(PWM_PIN, i);
      delay(10);
   }
}

Specifications

  1. Start with the breadboard from the last exercise (see led-pulse.fzz).
  2. Open the Arduino IDE, which should have the starter code shown above.
  3. Compile the sketch to verify the starter code is correct.

    When compiling is successful, you will see a message at the bottom of the source code window saying, "Done compiling."

  4. Add the following code inside the current for-loop
    if (i % 10 == 0) {    /*only print every 10th, so the printout isn't 255 characters wide  */
      int end = i / 10;   //have to divide end by 10 also.  
      for (int j = 0; j < end; j++) {
        cout << '*';
      }
      cout << endl;
    }
    
  5. Compile and upload your code to verify it works correctly.

    By opening the Serial Monitor, you should now be able to see the following graph.

    *
    **
    ***
    ****
    *****
    ******
    *******
    ********
    *********
    **********
    ***********
    ************
    *************
    **************
    ***************
    ****************
    *****************
    ******************
    *******************
    ********************
    *********************
    **********************
    ***********************
    ************************
    *************************
    **************************
    ***************************
    ****************************
    *****************************
    ******************************
    *******************************
    
  6. Change the code to alternate the printing of '*' and '+' like this:  *+*+*+*+*+  etc.
  7. Change the code to scale by 7 instead of 10.
  8. Answer the questions below in the Comment area of this assignment.
  9. Save your updated pulse.ino file and submit to Canvas.

Questions to answer in Canvas Comment area of this assignment:

1.  What are 3 values of i for which (i % 7 == 0) will evaluate to true?

2.   Why do we scale a bar chart? 

3.   How do you scale bar chart?  (what are the two statements that force the scaling?)

4.   What is a nested loop?  Write an example of one.

5.   In your nested loop example,  which is the outer loop and which is the inner loop?

6.   Every time the outer loop iterates once,  how has the inner loop run?  (completely?, partially?, twice?)

7.   Trace your nested loop from #4.  Make your loop limits small so you don't have to do too many iterations.

Grading Criteria(12pts):

12 points  (Header 1pt, Compiles 2 pts, Proper Formatting 1 pt,  Works as Specified 4 pts, questions answered 4)

^ top

Summary

  • We looked at how to graph a bar chart using a for-loop
    for (int i = 0; i < num; i++) {
      cout << '*'; // print one character
    }
    
  • Inside the basic loop, we can add variations using if-else statements
  • For example, t alternate characters we would add:
    for (int i = 0; i < num; i++) {
      if ((i % 2) == 0) {
        cout << '*';
      } else {
        cout << '+';
      }
    }
    
  • Some looping applications have loops nested within other loops
  • The structure of nested loops looks like:
    for (int outer = 1; outer < 4; outer++) {
      for (int inner = 1; inner < 4; inner++) {
        cout << outer << "\t" << inner << endl;
      }
    }
    
  • We added a bar chart to the PWM project with a nested for-loop

^ top

Wrap Up and Reminders

  • For the next homework, see the schedule
  • When class is over, please shut down your computer.
  • Complete unfinished exercises from today before the next class meeting
Subpages (1): pulse