Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C Programming for microcontrollers (Joe Pardue, 2005).pdf
Скачиваний:
277
Добавлен:
12.08.2013
Размер:
4.55 Mб
Скачать

Chapter 5: C Control Flow

Chapter 5: C Control Flow

We specify the order in which computations are performed with control statements. We’ve already peeked at some of these concepts, now Let’s jerk open the kimono and take a good hard look.

Statements and Blocks

Expressions such as PORTD = ~i or _delay_loop_2(30000) or i -= 128 become statements when they are followed by a semicolon:

PORTD = ~i; _delay_loop_2(30000); i -= 128;

The semicolon terminates the statement.

Compound statements are made by enclosing a group of statements or declarations in block delimited by braces ‘{‘ and ‘}’. This causes the compiler to handle the block as a unit.

Tale of a bug:

I wrote the following statement:

while(QuarterSecondCount < 17600); QuarterSecondCount = 0;

Then decided that the 17600 wait count was too long so I changed it to 2200:

while(QuarterSecondCount < 2200)//17600); QuarterSecondCount = 0;

But I wanted to leave the 17600 in case I ever needed it again, so I commented it out. Do you see a problem here?

Well, what I meant to say was:

while(QuarterSecondCount < 2200); QuarterSecondCount = 0;

73

Chapter 5: C Control Flow

Which is two statements, the first waits while an interrupt increments QuarterSecondCount in the background, and once that is finished the QuarterSecondCount is set to zero. What the compiler saw was:

while(QuarterSecondCount < 2200) QuarterSecondCount = 0;

because the compiler doesn’t see the comments – the \\17600;. See the problem yet?

Well how about he equivalent statement:

while(QuarterSecondCount < 2200) QuarterSecondCount = 0;

The compiler also doesn’t know about the line break, all it sees is the last statement, which says that while QuarterSecondCount is less than 2200, set QuarterSecondCount to 0. So each time the interrupt incremented QuarterSecondCount, this statement set it back to zero.

This is the kind of bug, that after spending X amount of time locating, you carefully hide it from your boss lest she think you are stupid or careless or both. Fortunately, I am my own boss, so I’ve learned to live with my stupid and careless employee. (I fired myself once, but that just didn’t work out.)

If-Else and Else-If

We can make decisions using the if-else statement:

if (expression) statement1

else

statement2

If the expression has a non-zero result (it is true), then we do statement 1, if the expression has a 0 result (it is false) we do statement 2. We can make a list of related decisions using else if:

74

Chapter 5: C Control Flow

if (expression1) statement1

else if (expression2) statement2

else if (expression3) statement3

else

statement4

In this case each expression will be evaluated sequentially looking for the first non-zero (true) expression and if they all equal 0 (false) we do statement 4. You can omit the final else statement if you want to do nothing if all the expressions are 0 (false). We will use an example of this construction later when we write an example program for using the joystick interrupts:

if(input == KEY_PLUS)PORTD= ~0x01;

else if(input == KEY_NEXT)PORTD = ~0x02; else if(input == KEY_PREV)PORTD = ~0x04; else if(input == KEY_MINUS)PORTD = ~0x08; else if(input == KEY_ENTER)PORTD = ~0x10;

Which may be read as: if the input is equal to KEY_PLUS then set port D equal to the inverse of a byte equal to 1 (a byte of 1 is binary 00000001, the inverse is 11111110 and since we output a 0 to a pin to light and LED, this statement lights the LED). If the first line is true then the rest of the statements are skipped. If the first line isn’t true, then each line is evaluated sequentially until a true expression is found or it drops out the bottom and does nothing.

Switch

The ‘if else’ construction limits us to expressions that are either true or false. If we want to make decisions using expressions that can have any numeric result we use the switch statement that selects an expression with results equal to a specified constant.

75

Chapter 5: C Control Flow

switch (expression) {

case constant expression1 : statements case constant expression2 : statements case constant expression31 : statements default: statements

}

We can redo the if else if block used in the joystick interrupt example using a switch statement as follows:

switch(input){

case KEY_PLUS : PORTD = ~0x01; break:

case KEY_NEXT : PORTD = ~0x02; break;

case KEY_PREV : PORTD = ~0x04; break;

case KEY_MINUS : PORTD = ~0x08; break;

case KEY_ENTER : PORTD = ~0x10; break;

default:

}

So if the ‘input’ == KEY_NEXT, then PORTD = ~0x01. The ‘break’ statement causes an immediate exit from the switch block. If you want to continue evaluating cases against the input, leave out the break and the subsequent statements will be looked at.

You can let cases fall through, which can be handy in circumstances such as evaluating character input where you don’t care if the character is a capital or lower case letter, or perhaps you want the same response for a range of integers:

switch( input){ case ‘a’ : case ‘A’ :

DoaA();

break; case ‘b’ :

76

Chapter 5: C Control Flow

case ‘B’ : DobB(); break;

case ‘0’ : case ‘1’ : case ‘2’ : case ‘3’ :

Gofer0123();

break; case ‘4’ : case ‘5’ : case ‘6’ : case ‘7’ :

Gofer4567();

break;

default:

DoDefault();

break;

}

This can be compacted as:

switch( input){

case ‘a’ : case ‘A’ : DoaA();

break;

case ‘b’ : case ‘B’ : DobB();

break;

case ‘0’ : case ‘1’ : case ‘2’ : case ‘3’ : Gofer0123();

break;

case ‘4’ : case ‘5’ : case ‘6’ : case ‘7’ : Gofer4567();

break;

default:

DoDefault();

break;

}

Switch statements are error prone and a frequent source of head boinking bugs (one where you boink your head for being dumb enough to leave out a break

77