AN-001 New User Introduction
This application note discusses a group of small, simple programs. These programs do not do anything particularly useful except demonstrate certain language features. The goal of this application note is to act as introduction to new and novice users.
All of the programs presented here will run on Atmel's development boards or in the circuit shown in figure 1. If you are using one of the development boards make sure that your ribbon cables or shorting plugs configure the board as shown in figure 1. These programs will run on any of the supported processors. The oneChip compiler assumes you are using an AT90S1200 unless otherwise specified. To use another processor the Processor directive must be used. If, for example, you are using an AT90S8515, place the following line as the first line of your program:
Processor is AT90S8515
Every program presented is discussed at a very basic, line by line, level. The programs need to be thought of as a single collection. Statements that occur repeatedly will not be discussed repeatedly. If you jump around in this application note and come across something that you do not understand and that is not described in the specific example you are reading, you should look back to previous examples.
All of the program listings shown here are shown in colored text. The compiler's text editor colors the text while you type if the "Auto Color" option is selected, or it will process the text in the front most window if the "Format and Color" menu item is selected or the "Format and Color" button at the bottom of the window is clicked.
The format of each example presented is the same. First the program listing is displayed in its entirety. This is followed by a discussion of the program. The discussion section first lists the line or lines to be discussed followed by a paragraph explaining the program lines.
As you proceed through the examples some questions about the
syntax of a particular statement may arise that this application
note does not address directly. In this case your best option
is to use the Reference Guide in the compiler's manual for the
complete syntax of the statement.
Program 1 - Blinking Lights
'This simple program flashes the LED's on and off. The LED's are connected to port B 'with the anodes tied high. To light the LED's the port pins should be made low. 'First make all of the pins on port B outputs. SetPortDirection (DDRB, 11111111\B) 'sets the ports pins to all outputs getBack: 'create a program label write (PortB,0) 'write a 0 to Port B to light the LEDs Pause (1000000) 'pause for a million cycles or about 0.25 seconds write (PortB,11111111\B) 'write 255 (all ones) to Port B to turn them off Pause (1000000) 'pause another 0.25 seconds Goto getBack 'jump back up and do it again END
Discussion of Program 1:
'This simple program flashes the LED's on and off. The LED's are connected to port B
This line is a comment. Comments are a part of a program that do not execute. They are used to document the program so that it is more understandable. All single line comments begin with either a single quote (') or a semicolon (;). All of the text from the comment mark to the end of the line is ignored by the compiler. There is another style of commenting, called a block comment, that will be discussed later.
SetPortDirection(DDRB, 11111111\B) 'sets the ports pins to all outputs
When the processor is first powered up all of its port pins are configured as inputs. Since the desire is to light the LEDs attached to the processor, the ports pins must be configured as outputs. The command, SetPortDirection, is used to set the processor's pins as either inputs or outputs. It is a procedure (which means it does not return a value) that takes two arguments. The first tells it which port to change. In our case we want to change the pins on port B so we use DDRB. The second argument defines the input/output relationship. Each bit in the second argument that is represented by a 1 causes the corresponding bit on the port to be an output. In this example we want them all to be outputs so the value 11111111\B was used. Note that this is a binary value as indicated by the trailing "\B". The second argument could as well have been 255, FF\H, or 377\O in decimal, hexadecimal or octal and the same function would have been performed.
getBack: 'create a program label
This is not a program line that executes. It is a label. Labels are used to mark a spot in the program that you need to get back to form another location in the program. Think of it as a bookmark. Labels must be followed with a ":". Note that there is no space between the label and the colon. This label will be referred to a little later in this program.
write(PortB,0) 'write a 0 to Port B to light the LEDs
This line causes a value to appear on the port the LEDs are connected to. Write takes two arguments. The first is the port that is affected. In our case the LED's are connected to port B so the first argument, PortB, defines that as the port of interest. The second argument is the value that should be written to the port. Our schematic shows the LEDs with the anodes tied to the positive power supply (via current limiting resistors). Therefore, in order for the LEDs to light, the cathodes must be near ground. To do this a 0 is written to the port. The ports pins are used to sink current because the Atmel AVR processors are much better at sinking current than sourcing it (by a factor of nearly 6 to 1). After this line executes, the LEDs will be lit.
Pause(1000000) 'pause for a million cycles or about 0.25 seconds
Pause is used to pause the program's execution. This program's whole purpose is to cause the LEDs to visibly flash. To do this the program must sit still long enough for the human eye to see what is happening. The Pause statement is used for this. It takes one argument. That argument is the number of clock cycles for which you wish to pause the program execution. In this case 0.25 seconds was chosen as an adequate time so, at 4 million cycles per second (the crystal frequency), pausing for 1 million cycles gives us the desired time.
write(PortB,11111111\B) 'write 255 (all ones) to Port B to turn them off Pause(1000000) 'pause another 0.25 seconds
These lines are about the same as the two lines above them. The difference between them is in this case all 1s are being written to the port. Since both sides of the LED are at the same potential, there is no current flow and the LED's extinguish. After the LEDs are extinguished, the pause statement is executed causing the program to pause for about 0.25 seconds.
Goto getBack 'jump back up and do it again
This line causes the program execution to move back up to the line following the label "getback". Notice that the label referred to by Goto does not end in ":". Only the label itself should end in a colon. The program now hops back up to the first write statement causing the LEDs to light again. Program execution continues until this statement is again reached and execution hops back up again. The program is stuck in a never ending loop.
This statement must be included even if, as is the case with this program, the END statement is never executed. If the END statement is executed, the processor is put into a low power mode and all program execution halts. Any loads that were being driven prior to its execution will continue to be driven.
Program 2 - Reading Switches
This short program reads the state of some switches and lights corresponding LEDs. The entire listing is:
'This program turns the LED's on and off based on which switch is depressed. The LED's are 'connected to port B with the anodes tied high. To light the LED's the port pins should 'be made low. The switches are connected to Port D and pull the pins low when depressed. 'Port D only has 7 pins - Bit 8 will read as a 0. As a result the 8th LED will always be lit. 'A variable will be used to read the value of the switch so declare it. DIM Byte portDvalue 'Make all of the pins on port B outputs so the LEDs can be driven SetPortDirection(DDRB, 11111111\B) 'sets the ports pins to all outputs 'Make all of the pins on port D inputs so the switches can be read SetPortDirection(DDRD, 0) 'sets the ports pins to all outputs getBack: 'create a program label portDvalue = Read(PinD) 'read the value on Port D Write(PortB,portDvalue) 'now write out the value just read Goto getBack 'jump back up and do it again END
Discussion of Program 2:
The program begins with a few lines of comments describing the program's function. After the comment lines the following line is encountered:
DIM Byte portDvalue
This line establishes a variable that will be used later in the program. Any variable used in a program must be declared with a DIM before its first use. When a variable is declared with a DIM, the type of variable, either a Byte (8 bits) or a Word (16 bits), must be declared at the same time. In this particular case, one Byte type variable, named portDvalue, is being declared.
The Atmel line of processors have a total of 32 working registers that are typically referred to as r0 thru r31. These registers are available for use in your program by declaring variables with the DIM statement. When the compiler takes your program and generates processor native instructions, some of the routines it uses also need register space. By default the processor uses the four registers r28 thru r31. Although these registers can be used by your program under certain circumstances and their location can be redefined, in most cases it is best to assume that these registers are not available and have a fixed location. This leaves 28 possible registers for use. They are r0 thru r27.
This means that you can have up to 28 Byte type variables or 14 Word type variables or a mixture of the two. When you start declaring variables with a DIM statement, the compiler starts by assigning them from r0. This may not yield the optimum results. Due to the way that Atmel's AVR processors work not all registers are created equal. Some operations are more efficient with certain registers. The registers that are most efficient are those from r16 up. For that reason if you have a program that is speed critical or you are running out of program memory space, then you may wish to use the AT modifier with the DIM statement to declare certain variables in these upper registers. See the Reference Guide for syntax details.
Following the DIM statement the data direction of both ports are declared. This sets up the switches as inputs and the LED's as outputs. The first new statement in the program follows the only label in the program. It is:
portDvalue = Read(PinD) 'read the value on Port D
This statement assigns the value of the data on the processors port D to the variable portDvalue that was declared earlier. This is accomplished with the function Read. Functions are program statements that return a value.
With the value now stored in the variable portDvalue, the following write statement causes the value to be written to the LEDs. After that, program execution unconditionally branches (via the Goto) back up in the program and program execution continues indefinitely in the loop reading and writing values.
Program 3 - Simple For Loop
'This program demonstrates a simple loop. The value of the loop is "written" to the LEDs for 'each value. Since writing a low is required to light an LED (the anodes are high) the LEDs will 'display the inverse of the data 'A variable will be used as a loop variable so declare it. DIM Byte loopVar 'Make all of the pins on port B outputs so the LEDs can be driven SetPortDirection(DDRB, 11111111\B) 'sets the ports pins to all outputs getBack: 'create a program label For loopVar = 1 to 254 'establish a loop Write(PortB, loopVar) 'write out the value of the loop variable Pause(125000) 'pause for a bit to see the pattern Next loopVar 'end of the loop Goto getBack 'jump back up and do it again END
Discussion of Program 3:
This program begins like the previous two examples. First, the variable that is used later in the program is declared through the use of a DIM statement, then the pins that drive the LEDs are set to be outputs. Next a label is created to provide a way to get back to that point in the program. The first new line in the program is:
For loopVar = 1 to 254 'establish a loop
This is the beginning of a FOR loop. Loops are program structures that allow you to repeat the execution of certain parts of your program many times. In the case of this FOR loop the next two lines of the program are the ones that are repeated. The line following them (the one that starts with Next) marks the end of the loop. In this particular case the action of the For...Next loop can be described as follows:
FOR loops can work with both Byte and Word type variables. There are modifiers that can be used with a FOR loop that cause it to count backward or count with values other than 1. Another loop structure, the DO loop is similar to the FOR loop but allows you more direct control over the loop variable.
The remainder of the program simply writes the value of the loop variable to the port (therefore lighting the LEDs) and pauses for a bit for each value written. The Goto statement is used to branch back up in the program so it executes endlessly.
Program 4 - Nested IF Statements
This program demonstrates the use of IF statements.
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Multiple Nested If statement % %______________________________________________________________________________% % This program reads the value of port D and then writes a value to port B % % based on the value read. If there is no change in the value read then % % nothing is written. This program will work with the Atmel Development Board. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ 'There was no processor declaration so the default processor is a 1200. 'First dimension a variable DIM Byte at 16 oneVar, thirdVar oneVar = 11111111\B 'assign the value 255 in binary form 'Now set the port B data direction using the predefined constant DDRB SetPortDirection(DDRB, oneVar) 'sets the ports pins to all outputs 'Port D does not need to be set for input - that is the default state on powerup 'Now read the value of port D after creating a porgram label again: 'a label so we can get back here again oneVar = Read(PinD) 'oneVar now holds the value of PortD /* The ATMEL development board has the switch inputs high unless a button is pressed in which case a low is read. The LEDs anodes are high therefore a low is required to make an LED light. If no buttons are pressed PortD will read all high or 127 (PortD on the 1200 is 7 bits wide therefore the maximum value is 127). */ 'to make the logic a little more straight forward invert all the bits thirdVar = oneVar XOR 11111111\B 'exclusive ORing with one inverts all bits 'now that it is inverted the top bit is now stuck high so "unstick it" by subtracting 128 oneVar = thirdVar - 128 'Check to see if button 1 is pressed IF oneVar = 00000001\B oneVar = 11111110\B 'button one pressed so light up 1 ELSE 'Check to see if button 2 is pressed IF oneVar = 00000010\B oneVar = 11111100\B 'button two pressed so light up 2 ELSE 'Check to see if button 3 is pressed IF oneVar = 00000100\B oneVar = 11111000\B 'button three pressed so light up 3 ELSE 'Check to see if button 4 is pressed IF oneVar = 00001000\B oneVar = 11110000\B 'button four pressed so light up 4 ELSE 'Check to see if button 5 is pressed IF oneVar = 00010000\B oneVar = 11100000\B 'button five pressed so light up 5 ELSE 'Check to see if button 6 is pressed IF oneVar = 00100000\B oneVar = 11000000\B 'button six pressed so light up 6 ELSE IF oneVar = 01000000\B oneVar = 10000000\B 'button seven pressed so light up 7 ELSE oneVar = 255 'make them all high so all the LED's are off END IF END IF END IF END IF END IF END IF END IF Write(PortB,oneVar) 'now write the value that was just stored 'jump back up and doit all again goto again 'The program end - this point will never be reached END
Discussion of Program 4:
This progam could have accomplished the same goal in several different ways. The method shown was chosen to demonstrate how IF statements can be nested.
The program begins with a series of comments. The first comment (which is several lines long) is called a block comment. Any text that appears between a "/*" and a "*/" is considered a comment. This is a handy way to have many lines of comments without having a "'" leading each line. Following the block comment two variables are declared in a DIM statement for use later.
The value of the port with the switches connected to it is then read and stored in one of the variables. Following it are two lines that perform arithmetic operations.
thirdVar = oneVar XOR 11111111\B oneVar = thirdVar - 128
These two lines perform the arithmetic functions indicated. The first uses a bitwise exclusive OR function that, by the nature of a XOR, inverts all of the bits of the value stored in oneVar. The second subtracts 128 from thirdVar and stores the result in oneVar. Rather than use the XOR function, the procedure "Complement()" could also have been used. Arithmetic statements can contain more than one operator. For instance the statement:
aVar = bVar * 10 + 2 - lowByte(wordVar)
is also acceptable. There are limitations on how aritmetic statements can be written. See the Users Guide for details.
The next statment encounterd is an IF statement. It is (in abbreviated form):
IF oneVar = 00000001\B ......... ELSE ......... END IF
In this case the "........." stands for one or more additional statements. These additional statements can be any valid language statement including another IF statement. When multiple IF statements are combined in this way a nested IF structure is formed. The basic function of the IF statement can be demonstrated by:
IF condition if the condition is true then do these lines ELSE if the condition was NOT true then do these lines END IF
In this case "condition" means a conditional statement. This is any statement that can be evaluated to see if it is true or false. For instance if the variable aVar was assigned the value 15, then the conditional statement:
aVar = 10
would be tested to see if it is true. Since it is not then the lines following the IF would not be executed. If there was the optional ELSE then its statements would be executed. Note that 10 is not assigned to aVar. The value of aVar is tested to see if it is 10. Other conditional operators are: <, >, <>, <=, =<, >=, and =>. These operators can be used to test two variables or a constant and a variable.
The remainder of the program simply writes the value assigned during the nested IF statements to the port containing the LEDs and branches back up.
Where To Go Next
This Application Note introduced several basic programming concepts and some simple syntax. If you wish to continue examining other simple programs before moving on to larger projects, there are a number of other simple example programs contained in the "Examples" folder that is part of the oneChip compiler download. If you want to get a better feel for a more complex application, then you may wish to read some of the other application notes in this section of the web site. For specific questions about the languages syntax and structure consult the User's Guide.