Lecture: | 4 |
Objectives: | C looping structures, for and while.
|
C looping statements
Loops repeat the execution of a collection of statements (called the body)
until some condition is met. Today we will examine two of the more useful
looping structures in C, the for and while loops.
For-loops
A for-loop generally is used when you need a counting variable along with
iteration. The counting variable is often referred to as the loop variable.
The for statement itself has three components separated by
semicolons as shown in the following figure and a body.
- The initalization statement is executed only once, when
the for-loop is first entered. Embedded programmers do not
typically declare the data-type of the loop-variable in this
statement (even though you may have done this in a previous
programming class). The variable that is initialized is
usually the variable the controls the number of times that
the body of the for loop is executed. Hence, thgis variable
is refered to as the loop control variable.
- The condition is checked before the body of the
loop is executed. If the condition is true, the body is
executed, otherwise the loop is terminated. Remember that
TRUE is the equivlent of any non-zero value
- The increment statement is executed at the end of the loop,
after the body has been executed. The increment statement
typically changes the loop control variable. The term
"increment" is used here loosely because you can perform any
sort of operation in this field. For example you could have
a for loop that initializes the loop control variable to 10 and
the "increment" statement could decrement the loop control
variable. Other mathematical operations can be used as needed.
- The body is typically the whole point of having a for loop,
it's the stuff that you want to do.
The flow-chart to the right of the for-loop shown in the figure above
describes the relationship between these four statements graphically.
Hopefully you can put together these pieces to figure out that the
for-loop given at left in the figure above executes the body 10 times.
Let's explore the operation of another for-loop with the following example.
uint8_t i;
uint8_t sum = 0;
uint16_t prod = 1;
for (i=0; i<10; i++) {
sum += i;
if (i>0) prod *= i;
// now record value of i, sum and prod in the table
} // end for
Fill in the following table with the values of the three values
at the line indicated in the program above. Make sure to respect
the data type!
i | sum | prod
|
0 |   |  
|
1 |   |  
|
2 |   |  
|
3 |   |  
|
4 |   |  
|
5 |   |  
|
6 |   |  
|
7 |   |  
|
8 |   |  
|
9 |   |  
|
If your for-loop is acting strangely, make sure that you have not
inadvertently done something to the loop variable in the body
of your for-loop. A C compiler would have no problem with allowing
you to decrement the i variable (subtracting 1 from it) in the
body of the for-loop above.
Count down loops
There will be times when you need a index variable that goes from
a large value to a small value. This is especially common when
working with arrays. Let's look at an example program to see
how to make a for-loop count down.
The for loop i the following code snippet initialize the loop
counting variable i to 10. The comparision will stop the for-loop
iterating when the index variable i equals 0. The trick to making
the count down work is the decrement operation i--. This operator
decrements i, subtracts 1, on every iteration of the loop. So,
what would the value of sum equal to after the execution of the
following code snippet?
sum = 10 + 9 + … 1 = 55.
uint8_t i;
uint8_t sum;
for (i=10; i>0; i--) {
sum += i;
} // end for
Infinite loops and the superloop
Before we leave this section there is one very special for-loop that
I would like to present before we leave.
for(;;) {
body;
}
This for-loop has no initialization, condition or increment statements.
The most important in this case is that
it lacks a condition. When left blank, the condition field is
assumed to be TRUE. Hence, this for-loop never terminates.
This is an
infinite loop, meaning that once execution enters
this for-loop, the program will forever execute the body. In your
previous programming courses, you probably would avoid
a structure like this because you would want your program to end so
that the computer could do other things. Well in our environment,
our computer is embedded into an application and has nothing else to
do expect the application we are designing it into. For example, imagine
if a vending machine with an embedded processor reached the end of
its program and then just stopped running! This would not be acceptable,
so we design the main program as an infinite loop, checking for money,
dispensing beverages and then going back to check for money.
The vending machine is a good example of the structure that we will
use for most of our programs this term, the super-loop. A super-loop
is an infinite loop that contains a set of tasks that are performed
over and over again. For eample
for(;;) {
if (current_temperature > highSetPoint) {
TURN_ON_COMPRESSOR();
}
if (current_temperature < lowSetPoint) {
TURN_OFF_COMPRESSOR();
}
if (coinDeposit == TRUE) {
switch(grade) {
case NICKLE:
total += 5;
break;
case DIME:
total += 10;
break;
case QUARTER:
total += 25;
break;
} // end switch
coinDeposit = FALSE;
}
if (total >= 100) {
DISPENSE_SODA();
total = 0;
}
} // end super-loop
It's pretty easy to read through this list of tasks and figure out
what the vending machine is doing. In the case of a super-loop you
are expecting that the loop is executed quickly enough that the user
will sense that the machine acts instantously to any input, when in fact
we know that the machine is doing one thing at a time.
Later in the semester, we will add interrupts to the super-loop
software architecture so that the microcontoller can really do several
things at the same time.
While loops
While loops are structurally more simple than for-loop, having a
single condition, that while true, allows the body of the while-loop
to execute. So, for example, the following while loop produces the
same iterative behavior as the first for-loop.
uint8_t i;
uint8_t sum = 0;
uint16_t prod = 1;
i = 0;
while(i < 10) {
sum += i;
if (i > 0) prod *= i;
i += 1;
}
However, a while-loop like this is of little practical use because this
loop structure is more naturally realized using a for-loop. However,
there is one very important use of while-loop that we will use extensively
and that is to wait for some external event to happen.
Delay loops
A delay loop is a loop constructed to have the embedded processor wait
for some event. Lets look at a concrete example that we will work with
in lab 2, controlling an LED with a push button. To accomplish this task
we will need to make some assumption here that will be justified later on.
First, we will connect our push button to our PIC and that associated
with this push button we have a variable called "buttonPressed". This
variable is TRUE when the user presses on the push button and FALSE when
the user is not pressing the button.
Second, we will connect an LED to out PIC and that associated with
the LED is a variable called "LED". Assigning this variable the value of
0 will turn the LED off, assigning a 1 will turn the LED on.
Finally, we need to recognize that
the microcontroller is executing the
instructions many millions of times faster than a user can press or
release the button. With these assumptions in place lets look at a
practical delay loop that you will see many times in our course.
1. LED = 0; // turn off the LED
2. for(;;) {
3. while(buttonPressed == FALSE); // wait for a button press
4. while(buttonPressed == TRUE); // wait for a button release
5. LED ^= 1; // toggle the LED
6. }
Let's walk through the program from top to bottom. To facilitate this
discussion, I have added line numbers in the far left; please understand
that these are not actually part of the program.
Line 1 turns the LED off. While not strictly part of the problem
statement, its often a good idea to put indicators like LEDs into a
know initial state at the start of a program.
Lines 2-6 form an infinite loop. Meaning that our computer will forever
be checking the state of the button and turning the LED on and off.
Line 3 is a while-loop that executes its (empty) body while the button
is not pressed. There are two important points to make here. First,
this while loop may get stuck executing this while loop many millions
of times before the button is pressed. This is because the PIC
is running at 64 MHz, meaning that its executing 64 million (assembly)
instructions per second. Hence, it can do a lot of checks every second.
Second, while our program is executing this while loop
it is doing
absolutely nothing except checking that button. This is the
quintessential delay loop, synchronizing the execution of our program
to the user's input by waiting and doing nothing until the user performs
some task. You rarely see these types of statements in other programming
classes because variables in those classes only change under your programs
control, but in this class we will have variables that change based on
actions performed outside your program.
Line 4 is a while-loop that executes its (empty) body while the button
is pressed. Once again, the PIC is executing statements millions of times
faster than the user can release the button. Hence, our program needs to
wait until the button has been released before continuing.
Line 5 toggle the state of the LED after the button has been pressed
and then released.
Test your understanding
You can find the solutions embedded in the "source code" for this
web page by right mouse clicking on this web page and selecting
"view source". The solutions are in HTML comments.
- Write a for loop that starts at 3, counts up by 5 and ends before
reaching 105.
- Write a for loop that counts up from 1 to 4096 (inclusive) by powers of 2.
- Write a for loop that counts down from 88 to no less than 42 by 2's.
- Write a loop that counts up by one while a button is being held down.
Since the while-loop would be executing so much faster than the user
could respond this would make a reasonablly good random number generator.
The counter should be type uint8_t. I would expect that this counter variable
would roll-over many, many times while the button is pressed. This is
not a problem as again, we are expect to end up with a random number.
- Write a loop that counts up by one everytime a button is pressed.
- A linear feedback shift register (LFSR) is a general techanique
that has been used with great success in generating pseudo-random number.
A pseudo-random number is a number that looks random to someone who
does not know how they are produced, but is in fact generated by a
deterministic procedure (an algorithm).
A pseudo-random number generator starts with a seed valuye (any non-zero
number) and generates a sequence of numbers that look like they have no
relationship to one another. To generate a sequence of pseudo-random
16-bit numbers using an LFSR with current varX16. To do this:
- Step 1: xor the bits in positions 15,13,12,10 and 0 (start
indexing your bits starting at position 0),
- Step 2: shift varX16 left one bit,
- Step 3: put the xor bit into the LSB of varX16.
Write a program to generate pseudo-random numbers using a LFSR.
- Embedded C programs will let you get away with some pretty
weird stuff. Sometimes this is really helpful, but when you are
starting out, this will allow you to make some pretty horrible
mistakes. The following program will run and terminate. What
value will the count variable have when it does and explain how
it got that way.
uint8_t i, count = 0;
for(i=200; i>100; i++) {
count += 1;
}
- Here is another weird one. What does count equal when the
loop terminates?
uint8_t i, count = 0;
for(i=200; i != 100; i++) {
count += 1;
}
- Here is another weird one. Does the loop terminate and if so,
what does count equal when it does?
uint8_t i, count = 0;
for(i=200; i <= 300; i++) {
count += 1;
}
- Here is another weird one. Does the loop terminate and if so,
what does count equal when it does?
uint8_t i, count = 0;
for(i=200; i != -1; i++) {
count += 1;
}
- Here is an interesting loop. What does count equal when the loop
terminates?
uint8_t i, count = 0;
for(i=43; i != 171; i*=3) {
count += 1;
}