If you
are interested in learning how to write a very simple computer program in
Interactive C (IC), you have come to the right place. You’re going to learn
how to write small sample programs which will get the robot computer's attention,
move the robot forward for a few seconds, reverse its direction, and stop.
Once you learn a few basic details, learning more sophisticated applications
in IC depends upon how much time you want to spend on learning the two languages.
As most of you are aware, communication between
other humans can be quite a challenge. Speaking the same language doesn't
necessary mean you will communicate your point. For example, a few common
phrases that often are garbled in the translation include, "Will you
please clean your room?", "Do you mind putting the dishes away tonight?",
and "Please do your homework." When these phrases don't work, parents
may add a few words like, "grounded", "no car keys", and
"your allowance." These words usually solve the problem and whomever
is on the receiving end of the conversation will get the message. Communicating
with computers, such as the HandyBoard and the RCX processor, offers similar
challenges.
One thing to keep in mind is that computers do
exactly what you tell them to do. If a
computer does not do what you think it should be doing, there are two possiblities:
you have given faulty instructions, or someone else has given faulty instructions
(perhaps the person who wrote your programming language). These faults in
the program are called bugs.
In the world of computer programming, there are a number of languages to chose from. One of the most commonly used computer languages is C. IC is a hybrid of C designed to run on small, self-contained robot controllers, namely the HandyBoard and the LEGO RCX brick. IC has the ability to accomplish certain tasks interactively with the user.
Previously, users of the RCX who wanted to program
in C had to use NQC, which is short for Not
Quite C. NQC has some drawbacks that make more advanced programming difficult.
In addition, the differences between the two languages confuse beginning programmers.
As a result version 4.0 of IC is compatible with both the HandyBoard and the
RCX; however, code written for the HandyBoard is not 100 per cent compatible
with the RCX because of differences between the two controllers.
The HandyBoard is more capable than the RCX. The
HandyBoard has four motor outputs numbered from 0 through 3, while the RCX
has three motor outpus which are physically lettered A, B, and C, but referred
to as 1,2, and 3 in software. The HandyBoard also seperates analog inputs,
which range from 2 through 6, from the digital inputs, which range from 7
through 15. An expansion board exists that adds additional analog inputs on
ports 16 through 23, along with support for six servos. The RCX, which has
three general purpose inputs (either digital or analog), cannot deal with
servos at all. The HandyBoard also has a pretty snazzy LCD screen which can
display up to 31 ASCII characters—in other words, up to 31 letters, numbers,
or punctuation marks.
Where example code designed to run on the RCX is
different than example code designed to run on the HandyBoard, two versions
of the code are included. The RCX code will always come second. Because both
controllers are now programmed in the same language, the syntax, or grammar, of the code will not change. However, some commands
may not exist, or will have different names under the RCX.
C is a popular programming language. In recent
years it has replaced Pascal and Fortran as the language of choice among students,
hobbyists, scientists, and professional software developers. C itself is being
replaced with C++, an object oriented language, for developing desktop computer
programs; however, C++ is a bit too bulky and complicated for simple robotic
applications. C’s advantages include fast execution speed and high degrees
of flexibility, power, and control.
At the heart of any computer, be it is a robotic
controller or the latest desktop personal computer, is a CPU or central processing
unit. The CPU can operate on data values using numeric instruction codes stored
in memory. Each code tells the processor to do one simple task, such as additon
or multiplication, or retrieving or storing data. Whether you write in C,
Assembler, or BASIC, the processor only understands this simple numeric language,
which is called machine code.
In a compiled language like C, a program is a text
file containing source code which
is then translated to machine code by a compiler.
In other words, you type your program, then tell the computer to compile it
(convert it to machine code). The computer doesn’t understand the program
until then, so it will not run. If the program contains an error, the computer
won’t tell you about it until you try to compile. This can be confusing because
you may not remember making the error. To make matters worse, errors often
confuse the compiler, so the error message that the compiler issues may not
have anything to do with the error you made. Remember: only a program free
of errors will compile, so type all example code exactly
as it appears here.
When communicating with another person, the first
thing you want to do is get their attention. Thus, the first words out of
your mouth are very important. Here are some good ones:
Hello
Excuse
me
Hey!
Watch
out!
Wake up
All these words are good for getting someone's attention in one way or another. Computers are much the same way: they are idle until you do something to get their attention . Let’s say you want to get the attention of an RCX or HandyBoard in IC.
void main()
Every C program must contain a function named main() that is run when the program is begun. What you’re really
saying to the computer when you type void main () is that this is where the program starts. Be careful, much
of the text in IC is case sensitive. Notice that all the letters are lowercase.
You now need to tell the computer what you want
it to do. All instructions to the computer, known as statements, exist inside statement
blocks. Blocks begin with an { and end with an }. These are collectively
known as curly braces. Like parenthesis,
the one which marks the beginning of the block is said to be the opening
curly brace, while the one which marks the end of a block is said to be
the closing curly brace.
A statement block contains a group of statements. What is a statement? A statement can be a variable declaration,
int an_integer_variable;
an assignment,
an_integer_variable = 2;
a function call,
motor(1,50);
an mathematical expression,
foo = 2+(3/6)^5;
or a combination of function calls, expressions, and assignments.
foo = sqrt((a^2)+(b^2));
Important: All statements end with a semicolon (;).
The reason for this is that the C compiler cannot distinguish between
spaces, returns, or tabs (this is done intentionally for statements that won’t
fit on a single line). These characters are all collectively referred to as
white space. The semicolon is the computer's
way of determining where one statement ends and another begins. It’s kind
of like a period at the end of a sentence. Just as you can have more than
one sentence on a line of English text, you can have more than one statement
on a line of C code. You can even write a program that is all one line! However,
it is not generally considered good programming practice to do so, because
such code is hard for humans to read.
Each statement in the program instructs the computer to do something. For example
motor(1,50)
instructs the controller to turn on motor port
1 at fifty per cent power in the forward direction.
Computers are never asked questions: they are given
commands given which are abreviations of English. So if you wanted to know
what the value of sensor port 1 was, you would not say (conceptually), "What
is the value of sensor 1?". You would say, "Tell me the value of
sensor port 1". A computer cannot think; it can only try do what it is
told.
To some, a human-readable C program might sound
like an oxymoron, but programmers should go out of their way to make their
code easier to understand.
One way to do this is through indentation. In the
programing examples given in this document, notice how the statements are
indented. Each new statement block is indented one more level to the right,
usually with the tab key. When the block ends, the indentation is returned
to the previous level. While some compilers will do this automatically, indenting
code is an important part of programming, so you should get into a habit of
doing it.
Another way to improve human readability is to
add comments to help explain what
certain parts of the code do. A comment is enclosed between /* and */. Everything
inside those characters is completely ignored by the compiler. You can type
whatever you want to help explain your code. Commenting is another very good
practice. It helps you and other people understand what you wrote.
The following program will run a motor in the forward direction. The function
fd() will leave the motor running after it finishes
executing. In other words, once you activate the motors in your program, they
remain active until you deactivate them. This code will work on both the HandyBoard
and the RCX.
/* program to run motor on port 1 forward */
/* get the computer’s attention */
void main()
{
/* turn motor port 1 on forward at full power */
fd(1);
}
Now, I will walk you through the code. Take a look
at the first four lines.
The first line is a comment explaining the purpose
of the program. While this is not strictly necessary, it is a good idea to
include a few comments at the top of your program explaining who made it,
what it does, when it was done, and why. The second line was left blank in
order to visually separate the first few comments.
The third line is a comment describing the line below it. You should
recognize the fourth from earlier in this document.
{
/* turn motor port 1 on forward at full power*/
fd(1);
}
Next is the opening curly brace of the function,
main(). The function main() contains a single statement consisting of a single function
call to fd().
The fd() function is passed the
parameter 1, which means that fd() performs it’s action on motor port 1. The last line is the
closing curly brace of the function main(). The program ends when the function main() ends.
Now it’s time for you to try this program yourself.
Under IC, make a new document. Type the program, compile the program, and
download the program. If you don’t know how to do this, see the IC 4 user’s
manual. If any errors occur, don’t get discouraged! Just look at the above
example, and make sure that you typed it exactly as it appears.
Let’s recap:
·
Programs start with “void main ()”.
· Instructions to the computer are called statements
· All statements exist inside { and }.
· All statements end with a semicolon.
· Comments start with /* and end with */. They exist to explain the code.
· Indentation is an important part of programming. Usually, Every time a new statement block is begun, the code is indented.
· The program is over when the main function is finished.
At this point you should have a couple of robots that you can program. Assuming that you have never put a robot together, here is an example that is structurally sound. Click here for instructions on building a RCX or Handy Board demonstration robot.
![]() |
![]() |
| Click here to see larger pictures. | |
Now that you have your robots built, let's make
them move. To do this, we'll write a very simple program that tells the robot
to go forward for 2 seconds, pause, reverse direction for 2 seconds and stop.
In the previous code you were introduced to the fd() function:
fd(motor);
Now, we’ll introduce you to some more vocabulary.
bk(n); /* full reverse power to port n */
off(n); /* turn off motor port n (and leave the port connection
open)*/
sleep(n); /* waits for specified number of seconds. Must be a
floating point ( decimal ) number */
Here’s the program. This program will also work on both the HandyBoard or RCX.
/* program to go forwards and then backwards */
void main()
{
/* start motors forward */
fd(1);
fd(2);
/*wait for 2 seconds */
sleep(2.0);
/* back motors */
bk(1);
bk(2);
/*wait for 2 seconds */
sleep(2.0);
/* stop motors */
off(1);
off(2);
}
Take a look at this:
/* turn on motor ports 1 and 2 forward */
fd(1);
fd(2);
It’s the same fd() from the first example. Again, once the motors are on, they
stay on.
sleep(2.0);
The sleep() function causes the program to stop executing for a given
period of time. Once the computer reaches this function nothing else happens
until it exits. Note the decimal point. This is necessary because the input
parameter is a floating point number.
Even if you want to specify a whole number value, you must include a decimal
point or the compiler will generate an error. More on this later.
bk(1);
bk(2);
The function bk() works just like the fd() statement, except that the power is applied in reverse.
/* turn off the motors */
off(1);
off(2);
}
On the RCX and the RCX only, there is another function called brake(). It not only cuts power to the motors but also shorts the power terminals together. The result is that the motors stop rotating much more quickly, as if by brake. To use it, just put the number of the motor you want to break inside the parenthesis.
The combined effect of all this is that the motors are turned on in the forward
direction, the processor waits for 2.0 seconds and then reverses the motors.
Two seconds later, the motors stop. If you didn’t put in a wait, it would
appear as though there never was a fd()
in there because the motors would be powered in the forward direction for
only a few milliseconds. If you leave out the fd(),
the robot doesn’t do anything at all for exactly 2 seconds, and then takes
off in the reverse direction. If you leave out the off()
statements, the motors continue to move backwards until you turn off the RCX. Still with me? Let’s recap:
· The functions fd() and bk() all leave the motor ports in a particular state. Like light switches, they stay on until you switch them off using off().
· The sleep() statement stops program execution for a given period of time.
· sleep() requires a decimal point, even for whole number values.
Even though we are still in the basics of programming, you can have your robot accomplish a wide variety of tasks using just these functions. You might want to experiment with some of your own variations of this program for a while before moving on, by changing the order of statements, or the values passed to the different commands.
In a desktop computer, displaying data on the screen
is an essential part of any program.
The HandyBoard has a 31 character LCD display which
can display one line of ASCII text (either letters, numbers, or punctuation)
in two rows of 16 characters each. The RCX has a screen too, but it isn’t
as nice. It is much smaller (it can display a maximum of 5 characters, plus
some special symbols), and text looks funny because the screen is only designed
to display numbers.
To display information on the screen, IC is provided
with a stripped down version of the C function printf(). This function is quite
complex, and deserves a chapter of it’s own. The following is a very brief
description of how to use it so that you will understand upcoming examples.
To print text on the screen, put it inside the
parenthesis, enclosed in double quotes. The text must come before any other
parameters.
printf("your text here");
Like the decimal point for the sleep() function,
the quotes for printf() are mandatory. In the same maner that the decmal point
tells the comiler to read a floating point number, the quotes tell the compiler
to interpret the text between them as a string
variable.
To print the value of an integer, include a %d somewhere inside those quotes. For example to print two numbers,
you would start out by typing something like
printf("variable #1 %d variable #2 %d"
Next, specify the variables in the order you wish
them to be printed, outside the quotes. Be sure to separate all the arguments
with commas.
printf("variable #1 %d variable#2 %d",255,-100);
The above code will display this message on the
screen:
variable #1 255 variable#2 -100
When you have filled up the LCD screen with text,
you can clear it by typing.
printf("\n");
Note that the “\” in “\n” is a backslash not a
forward slash (“/”). The sequence “\n” really tells the computer to begin
a new line of text, but since the HandyBoard and RCX screens can only display
one line at a time, it has the effect of clearing the screen.
If the value you are printing is a floating point,
then use %f instead
of %d.
printf("Floating %f, Integer %d",4.215,105);
This would print:
Floating 4.215, Integer 105
You may be wondering why you couldn’t just type
Printf(“Floating 4.215, Integer 105”);
You can, and for numbers that don’t change, you should. This funny notation allows you to print variables, which will be covered in the next section.
This is printf() in a nutshell. If you would like to learn more about printf(), and why it works the way it does, pick up a book on C, find it in the IC help files, or check out some of the programming resources on the Internet.
We mentioned variables earlier, but this is where
we really explain them in depth. A variable is a container for information
that has a name. If you’ve taken algebra, then you should be familiar with
variables that have single letter names like a,
x, and n. These are letters
which stand for numerical values that are unknown. In computer programs variables
do much the same thing. When a variable contains a value, its name is replaced
by this value when evaluating an expression. Variables are one way for computers
to "remember" numbers. For example,
foo = 10*2;
would put the result of 10 * 2 (or 20) into the
variable named foo. You can then use foo in your code:
motor(1,foo);
foo will be replaced with 20 during execution. It would be like saying:
motor(1,20);
Except that the value of foo can change during the course of the program—that’s why it’s called a variable.
Before you can use a variable, you must tell the
computer that you need one. In C you do this with a variable declaration at the beginning of each block
of statements. You declare to the
compiler that you want a variable with a certain name. Take a look at the
following declaration.
int foo;
This tells the compiler that foo is a variable
of type int. In C int means integer. We can now use foo in our code in place of any integer value.
In IC there are other types of variables besides
int. The four types we are concerned with are integers, long
integers, floating-points, and characters. Each is suited to one particular
kind of information.
Integers hold whole numbers. Each integer (declared
by int) is 2 bytes in size and it can hold values that range from
–32768 to +32767. For most purposes this is quite large enough, however, for
holding a time in milliseconds a ‘long’ 4 byte-integer is needed. The term long is
used to declare long integer variables.
Characters are special values for holding single
letters. They are only one byte in size, and are thus perfectly suited to
the ASCII character set, which defines some 220 possible characters. Arrays
of characters form strings of text which can be displayed by the computer.
Sometimes characters are used to hold numbers instead of letters, because
characters are half the size of an int (one byte). When a character holds
a number, that number can range from -128 to +127. Characters are declared
with type char.
Floating points hold decimal or fractional values. The number of places past the decimal point is not fixed, but it can "float" based on the number of significant figures. Significant figures are difficult to explain, and are beyond the scope of this document. If you do not understand them you should look either on the web, or in a chemistry or physics text book. Floating point values are used in IC for the sleep() and the seconds() functions. This is why the sleep function requires a decimal point in it’s parameter. To the compiler, a constant value without decimal point is an integer. Floating point variables are declared with type specifier float.
foo = analog(6); /* store the value of sensor port 6 */
This code assigns the result of the function analog() to the variable foo. The value has been "remembered". When you want to assign a value to a variable, you use the = sign. The = sign is known in C as the assignment operator.
Generally, ints and floats and chars are incompatible.
A value from one type cannot be assigned to another. You can force the compiler
to put values from one variable into another by including a type specifier
enclosed in parenthesis followed by the variable to be changed.
MyInteger = (int) MyFloat;
This is
called typecasting. The value of one variable is cast into
the type of another. If MyFloat had been equal to 6.6, My Integer would now
be equal to 6. If you now type
MyFloat = (float) MyInteger;
MyFloat will be equal to 6.0. One use of typecasting
on the HandyBoard is to put the integer knob value into a floating point function
such as sleep().
Here’s the example code for this section. It is long, but most of the length is in comments.
This program will compile and run on the RCX, but due to the limitations of its screen, you will not be able to view any output.
/* program to demonstrate use of variables */
void main (){
/* declare two variables */
/* an integer, myint, and */
/* a floating point, myfloat */
int myint=35;
float myfloat;
/* the result of this expression will be thrown
away because it is not assigned to any variable */
5+6-45*1/3;
/* assign 5.6 to myfloat */
myfloat = 5.6;
/* add 1000 to myint */
myint = myint + 1000;
/* add myfloat to myint */
myint = myint + (int) myfloat;
/* beep to alert user */
beep();
/* printf statement is spaced to print on two lines */
/* \n is used to clear screen before printing */
printf("\nSleeping for %f seconds",myfloat);
/* sleep */
sleep(myfloat);
/* multiply myfloat by .02 */
myfloat = myfloat * 0.02;
/* beep to alert user */
beep();
/* print out variables */
printf("\nmyint: %d, myfloat:%f",myint,myfloat);
}
The ability of the microprocessor to make decisions
is what makes computers so usefull. So far, all the programs we have written
are linear. They always execute the same statements in the same order, no
matter what. In this next section, I will introduce you to conditional statements
and how you can use them to control the flow of your program.
The real secret to programming lies in two words:
"if" and "then". Now you’re saying, "Don’t give me
that. Give me the real dirt!"—but it’s true! If and then are all you
need to know to write programs that make decisions. You may remember discussing
algorithms in math. When you describe conditionals following pattern is used:
If some condition is true, then do one action,
otherwise do another. In C the word if represents if, and then
is replaced by an opening curly brace. The following is an example conditional
statement.
if ( start_button()==1){
fd(1);
fd(2);
}
else {
ao();
}
This translates out to "If the start button is pressed, then set motors
one and two to full power, otherwise turn off all the motors.". If this
statement were in a program, it would be activated if the start button were
down when the program reached this statement.
The conditional consists of an if keyword, followed
by an expression in parenthesis, followed by one or more statements inside
a statement block. If the expression in the parenthesis evaluates to anything
other than zero, then the statements after the if are executed. If the expression evaluates to zero, then the
statements after the else
statement are executed. Here’s another example.
Handy Board
if ( analog(2) > 12) {
tone( 880.0,1.0);
}
else {
tone( 440.0,1.0);
}
RCX
if ( light(1) > 12) {
tone( 880.0,1.0);
}
else {
tone( 440.0,1.0);
}
When the program reaches this statement, if the
value of the sensor attached to port 2 (one on the RCX) is greater than 12,
it beeps a high A tone (880 Hz), otherwise, it beeps an A one octave lower.
(440 Hz). Notice the curly braces after each if statement. These are only
necessary when you have more than one statement to perform for each case.
If you only have one statement, as above, the curly braces can be omitted;
however, it is still considered good practice to indent the lines of each
separate case, regardless of whether curly braces are used. Take a look at
this example:
Handy Board:
if ( !digital(15)){
if ( digital(16))
bk(1);
else
beep();
}
}
RCX:
if (!digital(1)){
if ( digital (2)){
bk(1);
}
else {
beep();
}
}
This is an example of nested if statements.
One if statement is placed inside another. This code first checks to see if
the touch sensor on port 15 (1) isn't pressed, if this is true, then it checks
to see if the touch sensor on port 16 (2) is pressed. If this sensor is pressed,
then motor one is powered full reverse (what will the robot shown above do?),
but if the sensor isn't, it will just beep. Notice that none of this will
happen if the first sensor is pressed. You can nest to any level that you
wish, but be sure to indent one more level for each statement (for better
readability).
In the HandyBoard example above, the nested conditional
statement do not use curly braces, because there is only one statement to
execute for each case. In the RCX example, these curly braces are left in
the code. This should not be taken to mean that the curly braces are necessary
only for the RCX, as the syntax for the two languages is identical. The examples
are written this way to show that you can do it either way.
Here are some of the logical operators you can
use inside the parenthesis.
> greater than
< less than
== is equal to
>= greater than or equal to
<= less than or equal to
!= is not equal to
Note that =, the assignment operator, is perfectly
legal inside an expression, but it is NOT “is equal to”. The assignment operator
is commonly used inside these parenthesis to combine two statements into one.
If you forget to type the double equal sign, you will not test for equality. Instead you will
assign the value on the right to the variable on the left.
If ( var1 = var2)
is the same as
var1 = var2;
if ( var1)
This brings up another point: In IC, one need not
use an operator at all! Since any expression that evaluates to zero or nonzero
will work, one can test for truth (non zero) by simply using the variable
name in parenthesis. One can test for falsehood by inverting the answer first
with the 'not' operator ( !). So assuming
var1 holds a positive integer:
if ( var1)
is the same as
if ( var1 == 1)
and
if ( !var1)
is the same as
if ( var1 == 0)
The implications of this are that you can write efficient and compact conditionals, but also that the compiler will not generate any errors should you confuse the = and == operators.
The following example requires a touch sensor to be attached to port 9 on the HandyBoard or port 1 on the RCX. The program uses an if statement to determine whether the touch sensor is pressed. If it is pressed, a motor will be activated. If it isn’t, the program will beep once and deactivate the motor. In order for the motor to be activated, you must have the switch held down before you turn on the robot, or select “run main” from the tool bar.
/* program to demonstrate use of a conditional statement. The sensor must be pushed in advance of running main. Why? */
void main () {
/* if the start button is pressed */
/* turn on a motor */
if ( digital(9)==1){
fd(1);
}
/* otherwise, beep */
else {
beep();
off(1);
}
}
/* For the RCX substitute digital(1) for digital(9) */
Program
loops are pieces of code that execute repeatedly. They are used for performing
a group of operations more than once. There are different kinds of loops,
each of which has its own use.
Suppose
you wanted to print something 3 times:
printf(“Hi! “);
printf(“Hi! “);
printf(“Hi! “);
That’s
all well and good, but what if you wanted to print something fifty times? That would be one long program!
Loops allow you to perform the same code without having copy the code over
and over again.
The simplest
and most common loop in C is the while loop. While loops express the idea
that while a condition is true,
a certain action should continue to take place.
In C, while loops look like this.
while ( expression) {
statements
}
When the program reaches this code, it firsts checks to see wether the condition in the parenthesis is true. This condition is written as a numerical expression, which evaluates true (non-zero) or false (zero). If the condition is false, the program will continue after the closing curly brace. If it is true, the program will continue inside the curly brace, executing each statement inside until it reaches the end. When it reaches the end, the program goes back up to the top, and the process is repeated.
Here is a program that will print the word “Hi” three times, using a loop.
HandyBoard:
/* program to print “hi” three times */
void main ( )
{
int i;
i = 0;
while ( i <3){
/* note trailing space to separate words*/
printf("Hi ");
i=i+1;
}
}
RCX:
/* the rcx screen isn’t large enough to hold 3 hi’s*/
/* this program beeps three times */
void main ( ){
int i;
i = 0;
while ( i < 3){
beep();
i=i+1;
}
}
Let’s examine this code. First, a variable, i, is declared. Then it is assigned the value of zero. We could use any number, but computers generally start counting at zero. In this case, I will follow convention. Then the program jumps into a while loop, the condition for which is that i be less than three (i<3). Inside the loop, the program prints “Hi” (or beeps), and then one is added to i. If we didn’t add one to i, the program would loop forever, because i would remain at zero, which is less than three. If you want, you can try omitting this and see what happens. Note how the code is indented after the opening curly brace.
Here is another, more useful example with a while loop. This program allows you to control the speed of a motor using the knob as a throttle. This is an example of an intentional infinite loop. The value of the knob is also printed on the screen so you can see it. Because this example uses the knob, it will not run on the RCX.
void main ( )
{
/* program to control the speed of a motor */
/* we never exit this loop, because one is always nonzero */
while (1) {
/* the motor function allows you to set*/
/* the speed of the specified motor */
/* the second parameter is the power of */
/* the motor, which is the result of the */
/* knob function */
motor(1,knob());
/* clear the screen, and print the value */
/* of the knob */
printf("\n%d",knob());
}
}
How would
you write a while loop to perform an action 10 times? Here’s one example
/* execute a while loop for 10 iterations */
int I=0;
/* loop will beep 10 times in a row */
while ( I < 10 ){
beep();
/* the ++ operator increments the value of a variable by 1 */
I++;
}
The for
loop makes this simpler. A for loop can be explained in a sentence as for
a variable within a given range, do these actions and count (increment) until
the number is out of range. A for loop looks like this in C.
for ( I = 0; I < 10; I++){
beep();
}
A for
loop consists of 3 parts: The initialization part, the test part, and the
increment part. In this example, the initialization is the "I = 0"
part. The test is the "I < 10", and the increment is the "I++".
You can also make a for or while loop count backwards. To count backwards
from 20, set the initialization to "I = 20", the test to "I
> 0", and the increment to "I--" (the -- operator decrements
a variable).
You can
nest loops to any depth you’d like. The following HandyBoard example shows
a for loop nested inside a while loop:
/* program to print all the sensors with resampling until the stop button is pushed. This example uses a for loop nested inside a while loop */
void main () {
int I;
while ( !stop_button() ){
for ( I = 2; I <=6; I++){
/* variable I is used as the parameter for analog()*/
printf ( " %d", analog(I));
/* slow to see sample displayed */
sleep(.1);
}
printf("\n");
}
}
The RCX example also features a for loop inside a while loop, which displays the value of three touch sensors repeatedly. Keep in mind that the only reason these two examples are different is because of the limitations of the RCX screen.
/* program to print up to three touch sensors in sequence until the prgm (==stop) button is pushed; the for loop is inside a while loop */
void main () {
int I;
while ( !stop_button() ){
for ( I = 1; I <=3; I++){
printf ( " %d", touch(I));
sleep(.3); // slow to see each sample displayed
}
printf("\n");
}
}
Hopefully,
you see the power of program loops, and how they can be used to perform otherwise
tedious tasks, or impossible tasks.
Here we will explore C functions in more detail. Functions are one
of C’s most important features. Functions are pieces of self-contained program
code that can be called by name. You have already seen how functions are used.
Most of the commands in C are functions, like stop_button(), start_button(),
fd(), bk(), etc. In this next section we will see how functions are put together,
by examining a function called get_knob().
The term function is borrowed from algebra. A function
is used to express a relationship between two variables with an equation.
In math, a function has a given output value for each input value. The same
is true in C. C functions have the
option of directly returning a value.
In this respect, functions act a bit like variables. When the function is
called in an expression, the function’s name is replaced by its return value.
For example:
if ( start_button())
In this conditional, the function start_button()
is called, and the name is effectively replaced by either a zero or a one,
which is the status of the start button on the Handy Board. When you call
the knob function, the name of the knob function is replaced by the value
of the knob at that point in time. Functions can return any type of data supported
by C. For us this means that functions may return ints, longs, floats, and
chars. Some functions, like fd() do not return a value. In C, these functions
have type of ‘void’. You already know about one function with type void. This
is the function you define or, write,
every time you create a C program. It is called main.
This is why programs start with
void main(
because the function main returns no value.
When you wish to have a function return a value,
you type return
followed by the value. This causes the function to exit (end its operation),
and the function’s name is replaced by this value wherever it is called. For
functions of type void, simply type return.
A function of type void will automatically exit
when all its statemens have finished executing.
Return values are essentially outputs for a function.
Parameters, also known as arguments, are inputs for a function. Parameters
are the values that go inside a function’s parenthesis. Some functions, like
fd(), bk(),sleep(),digital(),analog(), etc. take one parameter. Others take
multiple parameters, like tone(), and motor(). Still other’s, like printf() take a variable
number of parameters. When you write your own functions, they will all take
a fixed number of parameters. Special magic is used on functions like printf.
Since you define main every time you write a program,
you already know a little bit about defining functions. You start by declaring
the type of the return value, then you state the function’s name, followed
by the parameter list inside parenthesis. When you define a function that
returns no value, you use void as the return type. When you define functions
that take no arguments, you simply put nothing inside the parenthesis. Then
you list all the statements in the function inside { and }. The following
example demonstrates one such function.
Suppose you are getting a little tired of writing fd(1) and fd(2) every time you want to move both motors. Here’s a function called go() that will do this for you.
/* function to move both motors */
void go (){
fd(1);
fd(2);
}
I can now use this function in my code. Whenever
I call go() the computer will jump
to the go function,
execute all the code inside and return to the place just after where the function
was called.
Now let’s suppose I want a function to return a
value. This function will make it simpler to check the light level from a
sensor on port 2.
HandyBoard
int light_on() {
/* analog() returns a low value for high light */
if(analog(2)<100)
return 1;
else
return 0;
}
RCX
int light_on() {
/* light_passive() returns a low value for high light */
if (light_passive(2)<100)
return 1;
else
return 0;
}
Now let’s write a function that accepts a parameter.
Here is a function that waits for the specified touch sensor to be pushed.
wait_digital( int port) {
while ( !digital(port) ) {
sleep(.1);
}
}
Did you notice how the parameter is used like a
variable? The parameters you declare inside the parenthesis are variables
inside your function. They can be referenced by name, and their value is whatever
the person who called the function put into them. This is how functions get
information in and out. Now we will define a function which you may find useful
in your code. It simplifies the process of getting information from the knob
by using a while loop. It assumes the user will adjust the knob when they
see the prompt and then push the stop button. All you as a programmer have to do to get useable
information from the knob will be to call get_knob() with the appropriate parameter and use the return value in
your program. Because there is no knob on the RCX, the following code is for
the HandyBoard only.
There is some special notation used inside this
function. The parameter prompt
is defined like this:
int get_knob(char prompt[]) {
Those brackets indicate that prompt is not merely a single character, but a string of characters
of unknown length. Don’t worry about what this really means at this point.
The full meaning will become clear once you understand arrays.
/* function to simplify knob input*/
/* this function takes one argument, which is */
/* a text string to printed along with the value */
/* of the knob. The brackets ‘[]’ indicate that the */
/* variable prompt is not a single character but a */
/* string (an array of characters) of text */
int get_knob( char prompt[]) {
/* this variable stores the value of the knob */
int value;
/* while the stop button is not pushed */
while ( !stop_button()){
/* print the prompt */
printf(prompt);
/* remember the knob and display it */
value = knob();
/*note initial space to keep separation
between the prompt and the value*/
printf(" %d",value);
/* refresh the screen */
sleep(.1);
printf("\n");
}
sleep(.3);
return value;
}
This function can be used like this:
int power;
…
power = get_knob ("Power:");
The program will wait until the stop button is pushed and then the variable ‘power’ will contain the value of the knob. Try using this function in a program you write yourself. The quotes can contain any text you’d like, but they should say something about the information you want from the user. While this function is quite usefull, it has some limitations. Follow the link to see how it can be expanded.
Now that you have had a brief and simple explanation
of the IC computer language, you should explore more advanced topics and see
how the code can be applied to sensors and other components. For more advanced
programming applications,you'll want to learn about Processes, Globals, Multi-Tasking,
and how to use #define. Newton Labs provides an outstanding introduction to IC programming.
You can also download an Interactive C Manual hard copy.
2. Interactive C Users Guide Manual
Dave Baum (the creator or NQC) has a page with all the NQC documentation you can digest. He also wrote a good instructional book called Definitive Guide to LEGO Mindstorms.