simulation avr studio 4

56
Purdue University C Page 1 9/27/2005 AVR Simulation with the ATMEL AVR Studio 4 Updated: 8/3/2005

Upload: sudhanshu-mishra

Post on 29-Nov-2014

106 views

Category:

Documents


7 download

TRANSCRIPT

Page 1: Simulation AVR Studio 4

Purdue University C

Page 1 9/27/2005

AVR Simulation with the ATMEL AVR Studio 4

Updated: 8/3/2005

Page 2: Simulation AVR Studio 4

Purdue University C

Page 2 9/27/2005

Introduction The AVR Studio 4 is an Integrated Development Environment for debugging AVR software. The AVR Studio allows chip simulation and in-circuit emulation for the AVR family of microcontrollers. The user interface is specially designed to be easy to use and to give complete information overview. The AVR uses the same user interface for both simulation and emulation providing a fast Figure 1. AVR Studio learning curve.

Getting Started The AVR Studio uses a COF object file for simulation. This file is created with through the C compiler by selecting COF as the output file type. For more information on creating this file, see the C compiler documentation. Launch the AVR Studio by either selecting it through the Start Menu or by selecting the program icon (if available). Either method will produce the IDE shown below in figure 2. Once the IDE is running, select File Open through either the File Pull-down Menu or by clicking on the File Open Button.

Figure 2. The AVR IDE

1. File Open

Page 3: Simulation AVR Studio 4

Purdue University C

Page 3 9/27/2005

Select the desired COF file for simulation through the File Open window. Note this window uses standard Windows navigation. Either double clicking on the file or by clicking on the file and then selecting the Open Button can open the file.

Figure 3. File Open Device Selection After the source file has been opened, the device and debugging platform must be specified. When doing simulation, select the AVR Simulator option and ensure that the proper AVR target device is selected. Once the correct target AVR microcontroller and platform have been selected, click on the Finish Button.

Figure 4. Device and Debug Platform

1. Select the proper *.cof file

1. Select the AVR

Simulator

2. Ensure the Device is correct

3. Click Finish

Page 4: Simulation AVR Studio 4

Purdue University C

Page 4 9/27/2005

Output

IDE Windows The IDE has several windows that provide important information to the user. These windows may be opened automatically by the software or may need to be activated by the user. Regardless of how the windows are activated, they can be moved and resized to fit the taste of the user. The main windows of interest are the Workspace, Source Code, Output, and Watch windows. These can be seen below in figure 5.

Figure 5. IDE Windows

Workspace

Source Code

Watch

1. Watch Window

Icon

2. Workspace Window Icon

3. Output WindowIcon

Page 5: Simulation AVR Studio 4

Purdue University C

Page 5 9/27/2005

Workspace Window The Workspace window shown at the right holds important information about the microcontroller. Clicking on the expand symbols will provide detailed information about the selected item. For instance, expanding the I/O selection produces detailed information about the microcontroller ports, timers, USART, etc. These views are vital for simulating microcontroller software. They allow the user to monitor the values as well as introduce new information as inputs into the system. Additional information may be hidden from the user if the window is too narrow. Click and drag the right side of the window to re-size it and reveal possible hidden information. Double-clicking on the value of one of the PIN registers allows the user to enter or set the input value for that particular port. Likewise, the user may click on one of the boxes under the bit position to set an input.

Figure 6. Workspace

Figure 7. Expanded Workspace Figure 8. Expanded Port View

1. Click to Expand

1. Expand Additional

Layers

3. Double-Click to Change Value

2. Expand to See Additional Registers

4. Click to Set Inputs

Page 6: Simulation AVR Studio 4

Purdue University C

Page 6 9/27/2005

Watch Window The Watch Window allows the user to monitor the variables used in the software. To Add a variable to be monitored, right-click in the window and select Add from the menu. The next line or box in the Watch window is bounded by a box and has a flashing cursor present inside of it. Type the name of the variable EXACTLY as it appears in the source code. It should be noted that local variables are only valid when inside the function where they reside. Figure 9. The Watch Window

Figure 10. Watch Window Menu

Figure 11. Entering the Variable Name

2. Select Add From

the Menu

3. Type Variable Name

Here

1. Right Click in the Watch Window

Page 7: Simulation AVR Studio 4

Purdue University C

Page 7 9/27/2005

Output Window The Output window provides feedback to the user. This includes messages about the microcontroller, object file, etc.

Figure 12. The Output Window Simulator Options

Before actually starting a simulation, the Frequency of the target AVR should be set. The MegaAVR Development board from PRLLC operates at a clock frequency of 6.0MHz. This frequency happens NOT to be one of the selections from the pull-down menu. Therefore, the user must manually type this value into the program.

Figure 13. Debug Pull-Down Menu

Figure 14. Simulator Clock Frequency

3. Type the Clock Frequency

2. Select Simulator Options

1. Select the Debug Menu

Page 8: Simulation AVR Studio 4

Purdue University C

Page 8 9/27/2005

Source Code Simulation Controls IDE Toolbar Once the IDE has been configured and the windows are positioned to the satisfaction of the user, the actual simulation of the source code can begin. The yellow arrow indicates the next statement to be executed. The toolbar located in figure 14 shows a list of possible options to execute the source code. These options include Step Into (Single Step), Step Over, Step Out, Run to Cursor, Auto Step, and Run. In addition to the previous functions, the user can also Set Breakpoints, Reset, and Stop Debugging.

Figure 15. Simulator Toolbar

Next Statement The yellow arrow shown below in Figure 15 points to the next instruction to be executed. This provides the user a visual indication of the future instruction or function to be performed.

Figure 16. Source Code

Toggle Breakpoint

AutoStep

Run to Cursor

Step Out

Step Over

Step Into Reset Break

Run

Stop

Page 9: Simulation AVR Studio 4

Purdue University C

Page 9 9/27/2005

Step Into

Perhaps the most commonly used operation when simulating software is the Step Into operation. The operation can also be referred to as Single Stepping. This command

allows a single instruction to be executed at a time. This includes instructions that are located inside of a function call and thus the name Step Into. Executing a Step Into command is accomplished by either clicking on the icon or by pressing the F11 key. Performing this command on the sample program shown in Figure 17 causes the next instruction to be performed.

Figure 17. Step Into Function

In this example, the next instruction is a function call to a function named init_hardware( ) that will initialize the hardware for the microcontroller. Figure 18 shows the results of executing the Step Into command. The yellow cursor is now pointing to the first statement of the function. Performing an additional Step Into executes the current statement and moves to the next statement in the function. This process can be repeated throughout the software. Figure 19 shows the value of the PORTA data register prior to and immediately after execution of the instruction shown in Figure 17.

Figure 18. First Line in Function

Figure 20 shows the cursor pointing to the last line in the function. Executing a single step again Figure 19. PORTA Values takes the cursor and thus the program back to the next statement in the main function shown in Figure 21.

Figure 20. Last Line of Function Figure 21. Return to Main Function

Page 10: Simulation AVR Studio 4

Purdue University C

Page 10 9/27/2005

Step Over

The Step Over command causes the simulator to give the illusion that it skipped over the function without executing the individual statements located inside of it. For example,

revisiting the same sequence from the Step Into discussion, this time, instead of using the Step Into command, a Step Over command will be used. Figure 22 shows the main function just prior to the execution of the init_hardware( ) function. Figure 23 shows the status of the I/O configuration registers prior to the execution of the function. Executing the function using the Step Over command produces the results shown in Figures 24 and 25. Figure 24 shows the status of the I/O configuration registers proving that all the instructions were executed from a

Figure 22. Main Prior to Function Call

Figure 23. I/O Status Prior Figure 24. I/O Status After

Figure 25. Main After Function Call

single command. This technique is extremely useful when the user isn’t interested or concerned with watching each and every instruction in a function being executed. This command can also be used as a time saving technique while performing a simulation. The Step Over command can be executed by clicking on the Step Over icon or by pressing the F10 key.

Page 11: Simulation AVR Studio 4

Purdue University C

Page 11 9/27/2005

Step Out

The Step Out command is executed inside a function when the user wants to return back to the calling function without having to execute each individual step of the function. For

instance, the user may be interested in single stepping through the first several instructions inside a function. Once through the area of interest, the user wants to return to the function from which the current function was called in a single command. Figure 26 shows the cursor located in the middle of the init_hardware( ) function. Assuming that the user has already executed the

Figure 26. Inside the Function

instructions of interest, executing a Step Out command finishes the remainder of the instructions inside the function and places the cursor at the next instruction in the calling function as shown in Figure 27. This command can also be used to save time while simulating software. This command is executed by clicking on the Step Out icon or by pressing the F11 key while holding down the SHIFT key.

Figure 27. Returning to the Calling Function Auto Step

The Auto Step function can be viewed as the PC executing a series of Step Into commands automatically. This command can be executed by either clicking on the Auto

Step icon or by pressing the F5 key while holding down the ALT key. Once this command is started, each statement will be executed in order. The cursor and yellow arrow will still indicate the next statement to be executed. However, since the PC is executing single steps continuously, the yellow arrow and cursor are also moving constantly. The views inside of the Workspace window are also updated after each instruction is executed allowing the user to actually see the changing values in registers. The ability to view the changing value is a very important feature associated with this command. It must be noted that the simulator is capable of changing the values located inside the Workspace but the user is not. The simulation must be stopped prior to the user manipulating these values.

Page 12: Simulation AVR Studio 4

Purdue University C

Page 12 9/27/2005

Break

The Break function allows the user to stop a simulation that is under the control of the PC. This command allows a user a stop or pause a simulation that is using the Auto Step

function, for example, to enter new data into the Workspace or to modify a variable located in the Watch window. Once stopped, a simulation can be re-started by choosing any of the methods previously described. Reset

The Reset command will perform the same function as a Real reset on the actual hardware would produce. The cursor and thus the next statement to be executed will be set as the

very first instruction as if the file was just opened. In addition, the values of the registers will also be set to the reset state. The values of variables used in the software will not be affected by this command. The variables will retain their values until a process overwrites them. A Reset can be executed by either clicking on the Reset icon or by pressing the F5 key while holding down the SHIFT key. Breakpoints

Breakpoints allow the user to start a simulation free running and have the simulation stop when a certain instruction or place in the program is reached. Breakpoints can be set by

placing the cursor at a specific line in the software and then selecting the breakpoint icon or by pressing the F9 key. The breakpoint can be cleared by pressing the breakpoint icon again or by pressing the F9 key (a second time) while the cursor is located on the line that the breakpoint is located. A Red Dot indicates that the line has a breakpoint.

Figure 28. Breakpoints

Run The Run option allows the software to be simulated as quickly as possible. The downside of this option is that none of the registers or variables will be updated (visually to the user)

while the simulation is in process. The user must manually stop the simulation by using the break command. Alternatively, the user can set a breakpoint on a particular line of code that will stop the simulation when encountered.

1. Cursor Indicates the Selected Line 2. Red Dot Indicates Breakpoint

Page 13: Simulation AVR Studio 4

Purdue University C

Page 13 9/27/2005

Source Code Simulation of ATMEGA 16 Functions Now that the AVR Studio Software has been discussed in detail, simulating individual functions of the ATMEGA 16 will be explored. In order to walk through the steps necessary to simulate the functions of the ATMEGA 16, one entire software project has been developed. The project will be broken down into the individual functions and discussed. But before the discussion of the functions begins, a description of the project is needed. The project chosen for this tutorial was a version of the Simon Game. However, this version of the Simon Game is a bit more complicated than the original. There are eight lights and pushbuttons, a buzzer and two output displays involved in this game. Also included is an on/off button. The basic operation of the game is as follows:

1st round – randomly one of the eight lights blinks. The game then waits for the corresponding pushbutton to be pressed. Once the correct pushbutton is pressed then the second round begins.

2nd round - the first light blinks and then a random second light blinks. The game then waits for the two corresponding pushbuttons to be pressed. Once the correct pushbuttons are pressed, the third round begins.

3rd – 20th round - the game keeps going in this vain with the sequence increasing by one each round until the user completes the game or makes a mistake.

That describes the basic operation of the game but does not touch on the details. For instance, at the end of each sequence, a short beep will be produced to indicate that the sequence pressed by the user was indeed correct. The user must respond within 2 seconds by pressing one of the pushbuttons. If a pushbutton is not pressed within that time frame the game ends. The game will also end if the correct pushbutton is not pressed in the correct sequence. Two output displays are involved in this game. One is an LCD and the other is a terminal window in the PC connected to the system. There is nothing special about the LCD being used for this project. Also the terminal window used with this project and discussed in this tutorial is assumed to be the terminal that comes standard with the CodeVisionAVR software package, see AVR documentation for details. A toggle switch will be used to determine which display will be selected for use during any point of the game. The two displays will show the exact same data. The list of things shown to the user includes the number of lights in the current sequence, the state of the game, and the result of the game when the game is complete. The result contains a message for the user dependent on how well the user was able to keep up with the sequence of lights. The message identifies the player as a ‘loser’ for getting 5 or less correct responses, a ‘nerd’ for getting more than 5 but less than 12 correct responses, a ‘winner’ for getting more than 12 but less than 20 correct responses, or as ‘Simon the Conqueror’ for completing the game’s 20 rounds successfully. For example below are a couple of sample displays. Sample Display: Playing 1, 2, 3 (example for a game in progress on the 3rd round) Done. You are a loser!!!! (example of a completed game) So now that the project has been described, the tutorial will take the user step-by-step through some of the ATMEGA16 functions included in this project. Those functions will be basic input/output, timers, and serial communication functions. In order to make the process of simulation as simple as possible only segments of the code will be used for each section of the tutorial. However, once the tutorial is finished, the user will be able to simulate the entire project successfully by using the knowledge gained by each step of the tutorial.

Page 14: Simulation AVR Studio 4

Purdue University C

Page 14 9/27/2005

Basic I/O Functions The basic I/O functions of the ATMEGA16 consist of the ability to bring information into the controller or send information from the controller. These functions are the simplest way the controller has to communicate with the outside world. The ATMEGA16 contains 4 ports which can be bit configured as either input ports or output ports. Both the input operation and the output operation will be discussed. In order to step the user through the process of input and output operations, a section of code from the project must be created and loaded into the AVR Studio software. The code to load into the Studio software is attached in Appendix A. There will be two separate procedures discussed in this section of the tutorial. The first procedure will walk through the steps necessary to simulate the output of a “light” on PortC. The code being simulated assumes that PortC will be connected to eight individual LEDs. This requires that a high (5 V) be placed on a bit to “light” the LED or a low (0 V) be placed on a bit to “extinguish” the LED. The second procedure will walk through the steps necessary to simulator the input of a “pressed” pushbutton on PortA. The code assumes that PortA will be connected to eight individual pushbuttons. The pushbuttons will output a high (5 V) when “pressed” or a low (0 V) when not “pressed”. One more thing must be discussed before the procedures can begin. One aspect of this project is the random light generation. That is not within the scope of this tutorial. So for the procedures described in this section, the random number generation will not be completely functional. The number used in this section of code will start with 5. So the first time through the simulation, the first light displayed is the 6th LED from the right or the LED “connected” to bit 5 of PortC. After the first iteration the random generation will be functioning as intended. Also in the complete project attached the random generation will be completely functional. Studio Setup for Output or Input Simulation Step 1 Load the code from Appendix A into the Studio software. Follow the instruction discussed

earlier in the tutorial to load the simulator. Step 2 Once the code has been loaded and is ready to simulate the operation, expand the I/O

ATMEGA16 option in the Workspace Window. After that has expanded, also expand the PORTA and PORTC options.

With both PORTA and PORTC expanded, the user will see three registers listed under

each port. The registers are PORTX, DDRX, and PINX, where X is the port designation, A, B, C, or D.

Figure 29. Port registers

PORTX - The register associated with outputting information on the port if configured as an output.

DDRX - The register associated with setting the direction (in or out) the data will flow through the microcontroller. This register is also known as the data direction register.

PINX - The register associated with reading (inputting) information from the port if configured as an input.

Page 15: Simulation AVR Studio 4

Purdue University C

Page 15 9/27/2005

Step 3 To make it easier to follow what is happening in the during the simulation, it may be necessary to add a number of variables to the Watch Window. The main variables recommended for addition to the Watch Window are state, random, game_index, press, x, LED_seq[], and PB_seq[].

Figure 30. Watch Window variables

Output Function Procedures This section will step the user through the process of simulating an output from the microcontroller. Each step in this procedure signifies the user pressing the Step Into option once. Step Into This will configure the register DDRA as an input or the DDRA will now contain

0x00. The simulator shows zeros as an empty box. Therefore, you will not see anything really change in the Workspace Window. Notice that the yellow arrow is now pointing at the next line of code to be executed.

Figure 31. Status after first Step Into

DDRA is now 0x00. Cursor on next line.

Page 16: Simulation AVR Studio 4

Purdue University C

Page 16 9/27/2005

Step Into Now the PORTA register has been configured with an internal pull-up resister on each bit. A solid check box signifies a 1 or high in that bit position.

Figure 32. Status after second Step Into

Step Into Now the DDRC register has been configured for output. A solid check box signifies

a 1 in that bit position.

Figure 33. Status after third Step Into

Step Into The next Step Into will configure the PORTC register to output all zeros. Therefore

the PORTC boxes will be empty.

Page 17: Simulation AVR Studio 4

Purdue University C

Page 17 9/27/2005

Step Into This step will place the value ‘5’ into the variable random. This can be viewed in the Watch Window.

Figure 34. Watch window update Step Into The cursor will move down the code to the first case statement. Step Into Again the only thing that really happened visually was that the cursor moved. But

the next line of code to be executed will actually do something this next time. So why not get ready for it.

The first step is to look at what the line of code will be doing. This line of code will

be placing the value from random into the element designated by game_index of array LED_seq[]. It might be beneficial to look at the variables of interest. The array LED_seq[] has already been placed in the Watch Window. But all of the elements are not visible. To make those elements visible, it is necessary to expand the array by clicking on the + symbol in front of the array. Figure 35. Arrays in Watch window

Now the array should look more like the picture below.

Figure 36. Expanded Array in Watch window

Step Into Now with the completion of the line of code, the array element 0 or array LED_seq[]

should contain a 5. Element 0 was used because the contents of game_index at this point in the code is 0.

Figure 37. Array element filled in Watch window

NOTE: One thing that the Studio software does for the user that is very handy is to make any changes appear in red. For instance, in the picture above, the ‘5’ showing in the first element of the LED_seq[] array is in red. This means that this was the last change that occurred in the simulator.

Page 18: Simulation AVR Studio 4

Purdue University C

Page 18 9/27/2005

Step Into The variable game_index will now be equal to 1. Step Into Now the simulator will have entered a FOR loop. This line simply setup the FOR

loop elements for use. This FOR loop takes care of outputting the sequence of lights on the LEDs connected to PORTC. This will be the first time through the sequence so there will only be one output to “light”. The next time through this FOR loop there will be two outputs to lights.

Step Into Here is the first time the program has communicated in any way with the outside

world. This is where the output of the light actually takes place. The LED to be turned on will be the LED connected to bit 5 of PortC. The software shows this by selecting or filling in the box in the

Figure 38. Output of a high on Bit 5 position of bit 5 on PortC. The register shown for this

is PORTC because that is the register that handles actually sending out the high (5 V) on the physical port bit.

Now an output on one of the port bit has occurred. The next process in this game

will be to read the game user’s response. Input Function Procedures This section will step the user through the process of simulating an input into the microcontroller. This procedure will follow the same rules as the previous procedure. Every step will include the user clicking on the Step Into button. The procedure will pick up where the last procedure left off or with the cursor pointing to the end of the FOR loop in case 1 of the code in Appendix A. Step Into This step will also display the output from the PORTC register in the PINC register.

Remember that the PINC register is for reading information from the external world. However, whether the port is configured as an input or

Figure 39. PINC register still connected to hardware output, both registers, PORTC and PINC, are connected to the physical hardware pins. This means that anything showing up on the physical pins will be placed in the PINC register. Although the PINC register now contains information, because PortC is configured as an output port it means nothing to the controller.

Step Into The case that the state machine will execute next is changed to 2. This will show up in the Watch Window if a watch was placed on state.

Step Into The index for the array PB_seq[] is cleared to start at 0. Step Into The break command is executed. The flow of the controller has now jumped out of

the state machine and back into just the while(1) statement. Step Into The variable random is incremented here. Every time the controller drops out of

the state machine the random number generator will be incremented.

Page 19: Simulation AVR Studio 4

Purdue University C

Page 19 9/27/2005

Step Into The simulator has again entered the state machine. Step Into Case 1 will be skipped in this line code because the state variable was changed to

the next state in the state machine. Step Into The program will now enter Case 2. Case 2 will read PortA to see if any

pushbuttons have been pressed. Step Into This line of code will look to see if anything has been pressed. But how will it do

that? Remember when the PINC register updated because a high was present on the output pin? If a pushbutton is pressed, a high will appear on that bit’s pin. This will be stored in the PINA register. Note the pushbuttons reside on PortA, not PortC. So which ever pushbutton is “pressed” will be “displayed” in that bit position in the PINA register. But there is no actual hardware connected to the simulator. So the user must make the selection as to which pushbutton has been “pressed” by simply clicking on the bit that the user wishes to store.

Figure 40. An input is selected for PortA The value of the bit read will be

placed in the variable press. This can be checked in the Watch window.

Figure 41. Value read into variable Step Into State is changed to 3. This will take the state machine to the next state when the

program comes back again. Step Into The program breaks out of the state machine. Step Into Random is again incremented. Step Into The state machine is reentered. Step Into The first case is checked against the state variable. If state is equal to 1, this case

will be executed. According to the Watch window, state now equals 3.

The cursor is placed over the bit which should be high and then the cursor is clicked. This will select of darken the box.

Page 20: Simulation AVR Studio 4

Purdue University C

Page 20 9/27/2005

Figure 42. State variable contents Step Into The second case is now evaluated the same as the first case. Step Into Since state is equal to 3, case 3 will be executed. This case will determine which

pushbutton was “pressed”. Step Into The variable x is now ready to help in the process of determining which pushbutton

was “pressed”. Step Into The program will enter this WHILE statement as long as the pushbutton “pressed”

was not the first one or bit 0. Since the pushbutton “pressed” in this instance was bit 5, the program will enter the while loop.

Step Into The contents of the variable press are shifted

to the right by one and then placed back into the variable. The current status of press is 32 in the Watch Window.

Figure 43. Current state was press

Step Into Now that the press variable has been shifted (Figure 44), the x variable is incremented. This is done to keep track of how many times the variable press has been shifted. The total number of times press has been shifted will tell you which bit position read the Figure 44. press after shift “press” of the pushbutton.

Step Into until the cursor is sitting on line of code after the end bracket or } of the while loop as in

Figure 44 below. The value of press will continue to decrease until it is equal to 1. Each time press is decreased, x will be increased by 1 as shown in Figure 45.

Figure 44. While loop ended

Figure 45. Final values of variables

The variable x contains ‘5’ a the end of the shifting WHILE loop.

Page 21: Simulation AVR Studio 4

Purdue University C

Page 21 9/27/2005

Again the next line of code does something to watch closely. The variables used in

this statement are x, pb_index, and the array PB_seq[]. So expand the Watch to be able to see all of these variables. You may need to reduce the previous array by click on the – in front of it.

Figure 46. Expanded array Step Into The value of x, also the bit position of the pushbutton “pressed”, is stored in the first

element of the array PB_seq[]. Why was it stored in the first element? Remember a few lines above this the variable pb_index was set to 0. But why? Because the program is storing the first pushbutton “pressed”. So the first pushbutton will be stored in the first element of the PB_seq[] array. This

Figure 47. Pushbutton “press” captured element also corresponds directly to the first light from the array LED_seq[]. Step Into The case that the state machine will execute next is changed to 4. This will show

up in the Watch window if a watch was placed on state. Step Into The break command is executed. The flow of the controller has now jumped out of

the state machine and back into just the while(1) statement. Step Into The variable random is incremented. Step Into The simulator has again entered the state machine. Step Into Case 1, case 2, and case 3 will be skipped in this line code because the state

variable was changed to the next state in the state machine. Step Into The program will now enter Case 4. Case 4 will hold the program is this state until

the pushbutton is “released”. This will stop multiple readings of the same pushbutton from happening while the key is still pressed. If the pushbutton is still “pressed”, the program will simply increment the random variable and then proceed back to case 4 to check the pushbutton again.

Step Into In order to “release” the

pushbutton, simply follow the instructions for “pressing” the pushbutton. Place the cursor over the previously “pressed” pushbutton and click on the Figure 48. Pushbutton “released”

filled box. The box should now be empty which signifies a low or no pushbutton “pressed”.

Page 22: Simulation AVR Studio 4

Purdue University C

Page 22 9/27/2005

Well, the process of simulating the output and input of information has been explained. However, there is still more to the code that has not been explained yet. Using the techniques discussed above, step through the rest of the code. Try to determine what is taking place in each line of code. To help here is a small breakdown of what is left to the code:

Case 5 – This case will check to see if there are any more pushbutton “presses” to capture. If there are more pushbuttons to read, then the program is sent back to capture those. If there are not any more pushbuttons to read, the program will proceed to the next case.

Case 6 - This case will determine if the pushbuttons pressed were the correct

pushbuttons for the lights. If the pushbuttons were correct, then the program moves forward to case 7. However, if the pushbuttons were not correct, then program starts over from the beginning.

Case 7 - This case simple checks to see if the game is over. If the game has reached

the 20th round, then the game is over and starts over. If the 20th round has not been reach yet, the game continues.

Timer Functions The timer functions of the ATMEGA16 allow for a variety of options. The options that will be discussed in this tutorial will be the ability to create variable time delays using the timer interrupt and to create waveforms using the output compare function. The ATMEGA16 has three timer units - Timer0, Timer1, and Timer2. Timer0 and Timer2 are 8 bit timers and Timer1 is a 16 bit timer. What this means to the user and the simulator is that the 8 bit timers can count up to 255 and the 16 bit timer can count up to 65,535. The tutorial will describe two separate timer procedures. The first procedure is the creation of the variable time delay using the timer interrupt. Once that is completed, the tutorial will move on to the procedure to create a waveform using the output compare operation. The first procedure discussed in this tutorial will be the time delay. A time delay can be created by changing how fast the timer counts and how many counts the timer makes. A variable time delay is created by setting the speed of the counts and then varying the total number of counts used. The timer interrupt will be used to create a time delay. A timer interrupt contains a block of code that is executed whenever the timer reaches its maximum count, as mention earlier, and then starts counting at zero again. The tutorial will examine the process of executing the interrupt code, also called the interrupt service routine. The output compare functionality will be discussed following the time delay. The ATMEGA16 has incorporated the ability to manipulated specific port bits by using the output compare functionality. The port bit connected to the specific timer being used will change its state (high or low) based on the status of the Output Compare and Timer registers. For instance, in this program the bit is set to toggle (go from high-to-low or from low-to-high) when the timer reaches a set value. By toggling the port bit, the program has created a square waveform. The frequency of the square wave is determined by the total number of counts the timer executes and the speed with which each count occurs. For this program, the intention is to have a speaker connected to the output bit so that the output compare operation creates a tone at a set frequency.

Page 23: Simulation AVR Studio 4

Purdue University C

Page 23 9/27/2005

In order to step the user through the timer procedures, a section of code from the project must be created and loaded into the AVR Studio software. The code to load into the Studio software is attached in Appendix B. Studio Setup for Timer Simulation Step 1 Load the code from Appendix B into the Studio software. Follow the instruction discussed

earlier in the tutorial to load the simulator. Step 2 Once the code has been loaded and is ready to simulate the operation, expand the I/O

ATMEGA16 option in the Workspace window. After that has expanded, also expand the PORTA, PORTC, PORTD, TIMER_COUNTER_0, and TIMER_COUNTER_1. By expanding this many options, not everything will be visible in the Workspace Window. It will be necessary to use the scroll function to see what is needed.

For a description of the registers visible with PORTA, PORTC, and PORTD refer to the

section in this tutorial on Basic I/O Functions. Once the timer sections are expanded, the user will see a number of registers and also a few flag registers.

Figure 49. Workspace with expanded timers

The timer registers are designated by the symbol and the flag registers are designated by . The timer flag registers are also expandable. When the flag registers are expanded, the individual flags contained in that register are listed. Figure 50. Expanded Flag register

Page 24: Simulation AVR Studio 4

Purdue University C

Page 24 9/27/2005

There a lot of registers to monitor when dealing with the timers. But most of the registers

have to same functionality in each timer. Just as with PORTX and PINX from the I/O function, the timer registers with the same functionality in the different timers can be discussed as TCCRX, where X is the specific timer being discussed.

One thing for the user to notice is that there are some registers that show up exactly the same in each timer. These registers are shown in that manner because the registers are general timer registers. There is only one of these registers; not one for each Timer. Here is a quick description of the main Timer registers:

TCCRX – Timer/Counter control register. This register sets up the operating mode of the timer. It defines the speed that counter will count at along with other functions. See the data sheet for more detail.

TCNTX - Timer/Counter register. This register contains the current count of the timer.

OCRX - Output Compare register. This register holds the value that is being compared with the Timer/Counter register value. If the two values match, then the interrupt flag is set.

ICRX - Input Compare register. This register is used with input compare functions. This register is not within the scope of this tutorial.

TIFR - Timer Interrupt Flag register. This register holds the status of the timer interrupt flags.

TIMSK - Timer Interrupt Mask register. This register enables the timer interrupts.

Step 3 To make it easier to follow what is happening

during the simulation, it may be necessary to add a number of variables to the Watch Window. The main variables recommended for addition to the Watch Window are state, random, game_index, press, x, LED_seq[], PB_seq[], delay_time, beep_off, beep, and total.

Figure 51. Watch Window variables

Page 25: Simulation AVR Studio 4

Purdue University C

Page 25 9/27/2005

Time Delay Function Procedures This section will step the user through the process of simulating a time delay. Each step in this procedure signifies the user pressing the Step Into option once unless told otherwise in the procedure. There will some operations occurring while this procedure is executing the functioning of the timer delay operation that will not be discussed in this procedure. These operations will be pointed out when one occurs. The time delay operation in this program is used to provide a start up time frame or to blink the lights used in the previous section of the tutorial. A light will be turned on, a small delay will occur, and then the light is turned back on. Thus a blink has been created for the game user. NOTE: Step Into(x2) says that the next description is for the next two Step Into presses Step Into(x6) The first few of the Step Into processes will be configuring the ports for operation

with the circuit. Refer to the I/O function portion of the tutorial for an indepth description.

Step Into This command loads the TCCR0 register with a three which sets the clock divide

by to 64. This sets the timer to run at a 93.75 kHz rate. This is only for Timer0. Step Into The counter is started at zero. So the count will transverse the entire 8 bit range,

unless changed later. Step Into The Output Compare for Timer0 is configured here. This Output Compare unit will

not be used in this program. NOTE: The next registers are doubled. This is because Timer1 is a 16 bit timer. However, the

ATMEGA16 is an 8 bit microcontroller. So the 16 bit registers for Timer1 must be split into two 8 bit registers.

Step Into(x2) The speed of Timer1 and the operation of the Output Compare unit is now defined.

Timer1 will operate at 750 kHz and Output Compare unit B is to be used. Step Into(x2) This timer will also start counting at zero. Step Into(x2) If the Input Compare operations were going to be used in this program, the two

Input Compare register would be defined here. Step Into(x2) Timer1 contains two Output Compare units, A and B. These two registers control

the compare value for Output Compare unit A. Step Into(x2) Output Compare unit B compare value is set to zero. The operation of Output

Compare unit B will be further investigated in the next procedure. Step Into The Timer0 overflow interrupt is enabled and the Timer1 Output Compare unit B

interrupt is enable in this line of code. Step Into This is an assembly command which simply enables all interrupts that have been

configured.

Page 26: Simulation AVR Studio 4

Purdue University C

Page 26 9/27/2005

At this point the timers have been configured. But remember that as soon as the TCCRX register is no longer set to zero, that timer starts counting. So if the TCNTX registers have a value at this point, don’t worry. The timer had already starting counting. One other thing the user may notice while stepping through the program is that the two timers don’t count at the same speed. This is because the timers were configured to count at a different time interval. Timer0 was set to 93.75 kHz and Timer1 was set to 750 kHz.

Figure 52. Timer register configurations Step Into The variable random is now preset to a 5. This is only for the procedures. In the

complete code the random number generator will start with zero and function normally.

Step Into(x2) As in the previous section in this tutorial the program has just entered the state

machine. Step Into Because the state variable is a 1, the first case statement is entered. Step Into(x2) The first light to be shown to the user is selected and the round is set. Step Into Delay_time has now been set to

provide a 2 second time delay before the game starts.

Step Into This line of code will keep the

program from progressing until 2 seconds have elapsed. But to understand how a 2 second time delay is created, the Timer0 Workspace registers must be watched closely and the Timer0 Figure 53. delay_time set for 2 seconds Overflow Interrupt must occur.

NOTE: There is one disadvantage to the simulator timers. There is no way to run the simulator in “real time”. In other words, the timers will not run at the speed that would normally occur. This allows the user to see the internal working of the timer. But the user can’t attempt to verify actual time frames easily. Everything must be checked via clock cycles.

Page 27: Simulation AVR Studio 4

Purdue University C

Page 27 9/27/2005

Step Into The cursor will not move now until delay_time is equal to zero. So to examine what

is happening inside the microcontroller, the user needs to watch the Workspace window, TIMER_COUNTER_0.

Specifically the user needs to watch the TCNT0 register closely.

Figure 54. TCNT0 at the start of a delay As the Step Into button is

pressed, clock cycles are occurring within the microcontroller. As the clock Figure 55. TCNT0 during the counting process

cycles proceed and based on the configured speed of the timer, the count will increment. The user will see the

contents of TCNT0 increment by seeing the number of filled in boxes changing. Step Into(x?) Continue to press Step Into until TCNT0 is at its maximum value. This can take a

while; so be patient. There are, however, a few ways around having to repeatedly click on Step Into. Two of those procedures will be described here.

1) Remember, when the pushbutton “press” was created by clicking in the box of PINX where the button was “connected”? By clicking on a box in the Workspace, the user Figure 56. Timer0 count maxed is able to change the contents of that register. To shorten the time frame needed to make Timer0 rollover or hit the maximum and start over, click on each of the boxes that are empty in the TCNT0 register. This should end with all the boxes being filled. In this situation, the user may not see the Timer 0 Overflow Flag go high. The next procedure will discuss the Timer Overflow Flag 0 or TOV0.

At this point, the cursor should still be sitting on the while loop we entered earlier. Figure 57. Cursor waiting in while loop 2) This procedure for speeding up the time consuming process of stepping through a time delay will use the Timer0 Overflow Flag or TOV0 bit. The TOV0 bit can be

found in the TIFR register. The TOV0 bit signifies that an interrupt has occurred because the timer counter has rolled from the maximum of its count back

Figure 58. TOV0 bit in the TIFR register to zero. In the case of Timer0,

Page 28: Simulation AVR Studio 4

Purdue University C

Page 28 9/27/2005

that means that the timer has reached 255 and started counting at zero again. The user can utilize this operation to speed up the counting. Since the variable time_delay is manipulated in the interrupt service routine for Timer0 Overflow, the user simply needs to get the program into that service routine faster. To do this using TOV0, the user simply needs to select the TOV0 bit in the TIFR register by clicking on the TOV0. Once this bit is filled in, the next Step Into Figure 59. TOV0 manually selected for interrupt will cause the program to jump to the Timer0 OVF (overflow) interrupt service routine. When using this procedure, the user should watch for when the TOV0 bit is cleared by the microcontroller.

Step Into(x?) until the cursor has moved out of the main program. It should now be pointing to

the first line of the Timer0 Overflow interrupt service routine. Also TCNT0 is now set back to zero.

Figure 58. Timer0 interrupt service routine has been entered

Step Into The Timer0 overflow interrupt service routine has now been entered. Step Into Timer0 TCNT0 register has just been reloaded to start counting at 162. By setting

the timer to run from a 750 kHz clock and setting the start count to 162, the program will provide a 1 ms time between Timer0 interrupts.

Figure 59. Reload of TCNT0 Step Into The IF statement that the program enters here controls whether there is a beep or

not. This will be discussed in further detail in the Output Compare section of the tutorial. So skip this IF structure for now.

Step Into The cursor should now be

pointed at the IF statement containing delay_time.

This statement will check Figure 60. delay_time checked to see if the variable delay_time is nonzero. In other words, if the variable contains a value greater than zero, the IF statement will be evaluated as TRUE. If the IF statement is TRUE, then the variable delay_time will be decremented by 1.

Page 29: Simulation AVR Studio 4

Purdue University C

Page 29 9/27/2005

Step Into Now that the IF statement has been evaluated; the contents of delay_time have been decremented. This can be seen in the Watch window. Delay_time is now 1999. This means that as long as delay_time is greater than zero, the IF statement will be

Figure 61. Decremented delay_time entered. So how long will it take for the IF statement to evaluate as FALSE? A total of 2000 interrupts. How long does it take for interrupt to occur? 1 ms. So what it the total length of time the time delay will take? Time _ interrupt intervalTime = 2000 1 ms = 2 seconds

delay time= ××

Step Into(x?) So again the program has entered a position where pressing Step Into will take a

considerable amount of time before the program can move on through the while(1) loop. Again there are a few ways around having to repeatedly click on Step Into. Only one of those procedures will be described here.

Earlier in this tutorial a description was given for how to change the contents of a

variable within the Watch window. This will come in handy here. Instead of having to step through each iteration of the interrupt to make delay_time decrement to zero, the user will make the variable contents change to a more desirable value. However, before changing the variable, step through the complete process a couple of times until comfortable with the workings of the program.

Now to change the contents of the

variable, double click on the contents of the variable in the Watch Window. Studio will highlight the contents of the variable and place a blinking insert cursor beside the contents. Figure 62. Changing the contents of delay_time

All the user needs to do the change the contents is type in the new value. To speed along the 2 second time delay, change delay_time from its current value to zero. But the user Figure 63. delay_time changed to 0 must hit the ENTER key after making the change or the change will not register in the software. The user knows that the change took place because the new value will be displayed in red.

Step Into The program will move past the delay_time while statement because the variable is now 0. The cursor moving onto the next statement in the code signifies Figure 64. The delay is complete that the 2 second delay has elapsed.

The user has now stepped through the entire process to simulate a time delay using the Studio software. There are numerous time delays in this piece of code. The steps are the same for each of these time delays. The only difference is the amount of time the delay is designed to complete.

Page 30: Simulation AVR Studio 4

Purdue University C

Page 30 9/27/2005

Output Compare Procedures This section will step the user through the process of simulating the creation of a waveform using the Output Compare function. This procedure will follow the same rules as the previous procedures. Every step will include the user clicking on the Step Into button once or the number of times designated by the number in the parenthesis after the command. The procedure will pick up where the last procedure left off or with the cursor pointing to the beginning of the FOR loop in case 1 of the code in Appendix B. However, the configuration used to set up the Output Compare function must be described first. During the initialization of the timers, Timer1 was setup to utilize the Output Compare operation. Timer1 contains two Output Compare units – A and B. One of those units must be chosen. In this case, Timer1 was initialized to operate at 750 kHz using Output Compare B. The Output Compare operation requires that the timer count from 0 to maximum and rollover every time. So the user will not see the timer loaded to a start number. The Output Compare unit operates by comparing the Output Compare register, in this program - OCR1B, to the timer/counter register, TCNT1X. When ever those two registers match the output pin of the Output Compare unit will be exercised as configured. The output pin of the Output Compare unit is hardwired into the hardware. The datasheet should be visited to determine which bit is being used. In this case, the program will be using the port bit Port D bit 4. How the bit is exercised must be determined and configured by the user. The port bit can be configured to toggle (high-to-low or low-to-high) on the compare match, clear (set to low) on the compare match, or set (set to high) on the compare match. This program toggles the bit on a compare match. The program is running the Output Compare operation continuously throughout the operation of the program. How does the program then create just a beep instead of a continuous tone? The answer to that question is by manipulating the status of the Output Compare bit. If the Output Compare bit, PortD bit 4, was set as an output at all times during the program then a continuous tone would be created. However, if the bit is changed to an input when the user does not want a tone to be heard, then the tone is effectively turned off. But the user needs to remember that the creating of the tone is continuous, the program simply just turns the output bit on and off when necessary. The user needs to remember here that the TCNT1 and OCR1B registers that the procedure is referring to are actually the concatenation of the TCNT1H and TCNT1L registers and OCR1BH and OCR1BL registers. Studio prefers that the registers be used and manipulated in their un- concatenated form. One last thing to remember is that this is not like the time delay process. The main program will not stop and wait for the Output Compare to happen. The code within the while(1) will continue to be execute throughout the program. However, this procedure is only looking at the operation of the Output Compare process.

Page 31: Simulation AVR Studio 4

Purdue University C

Page 31 9/27/2005

Step Into(x?) The FOR loop used here will output the first light or the sequence of lights for the game user. During this FOR loop the light will be blinked. In other words, the light will be turned on then a short delay will occur. When the delay is over, the light will be turned off and another delay will occur. This will cause the game user to see the light blink. So this FOR loop will utilize two time delays. Time delays were discussed in the previous section and will not be Figure 65. End of FOR loop covered here. Step past this to the ending bracket of the FOR loop.

Step Into Through the previous step, the timer/counter for Timer1 will have been counting. Notice that Timer1 counts at a faster pace than Timer0 did. That is because it is set to a faster timer frequency.

Figure 66. Timer1 in operation The line of code that will execute next is important for the Output Compare

operation. This line of code sets the Output Compare register for a value to be compared against the timer/counter register, TCNT1L. This means that for every 187 counts of Timer1 the output (if enabled) will toggle its state.

Figure 67. Set the Output Compare register

Step Into If a watch was placed on beep_off, the user will be able to see that the variable has

been set to 187. If the user continues to simply step through the program, the program will continue to execute the code in the while(1) until TCNT1X rolls from its maximum to zero. This is true only the first time through the program. Why is that? Didn’t the program just set beep_off to 187? Yes, beep_off has been set to 187. But beep_off is not utilized by the program until the Output Compare B interrupt has occurred. What was the event that caused the interrupt to occur? The match of TCNT1 and OCR1B is what causes the interrupt to occur. When the program first initialized the registers, OCR1B was set to 0x00. That setting required the TCNT1 to count through the entire sequence and rollover before the first Output Compare interrupt occurs.

Why would this work? Hasn’t the program stepped through almost all of case 1

already? Yes, but remember that using the procedures from the time delay section actually speed up the natural operation of the program artificially. So in the actual program TCNT1 would be moving through its sequence much faster.

This is due to the fact that during the simulation of the Timer0 time delays, the user skipped a large number of clock cycles by changing the TCNT0 register contents or by setting the TOV0 flag. Timer1 would have been using those clock cycles to step through its own count. If the clock cycles had run at their normal pace with

Page 32: Simulation AVR Studio 4

Purdue University C

Page 32 9/27/2005

everything happening at the exact same time it would have in the “real” world, Timer1’s Output Compare interrupt would have occurred more quickly.

Step Into The variable beep has now been set to 100. This variable controls how long the

tone will be allowed to be heard by the game user. This process operates just as the time_delay variable did. Every 1 ms the Timer0 OVF interrupt will occur and check if the tone should be heard or not. This will be discussed in more detail when the program gets into the Timer0 OVF interrupt.

Step Into(x?) Continue to press Step Into until TCNT1 is at its maximum value. This can take a

while; so be patient. There are, however, a few ways around having to repeatedly click on Step Into. Two of those procedures will be described here.

1) The first way that will be discussed is to use the knowledge the tutorial has already given to the user about the match of TCNT1 and OCR1B registers triggering an interrupt. Because the TCNT1 and OCR1B registers have to match in order to create an Figure 68. Manual match interrupt, the simplest step is for the user to set the OCR1B registers to match the next count of the TCNT1 registers. On the next step the two registers will match and the interrupt will happen. 2) Just as in the time delay section, the Output Compare operation has an interrupt flag. This flag, OCF1B, is also in the TIFR register. So the other option in this situation is to simply enable this flag. The next step will take the cursor into the Output Compare interrupt service routine for Output Compare unit B. When using this procedure, the Figure 69. OCF1B located in TIFR user should watch for when the OCF1B bit is cleared by the microcontroller. Figure 70. OCF1B manually activated

Step Into The Output Compare B interrupt service routine is being entered. This routine will take care of setting the OCR1B registers for the next trigger point. Each point will be 187 counts past the current count. This will create a solid tone.

One thing for the user to remember is that the tone is being created using this

interrupt service routine. This interrupt will occur roughly every 250 µs. This means that the Output Compare interrupt will happen multiple times between the Timer0 OVF interrupt of 1 ms.

Page 33: Simulation AVR Studio 4

Purdue University C

Page 33 9/27/2005

This is important because while the Output Compare process is operating, the user needs to be watching the variable beep. Remember, beep controls how long the output pin for the tone is creating the tone for the game user. As of entering the Output Compare interrupt, beep still contains 100 as shown in the Watch window.

Step Into The current contents of OCR1BH is loaded into the variable total. This can be seen

in the Watch Window. Step Into The current contents of OCR1BL is added to the contents of total. This creates a

16 bit concatenated value of the current contents of OCR1B. This can also be seen in the Watch window.

Step Into The 187 is now added to the current contents

of the Output Compare register. This sets up the next match point.

Figure 71. Next match point set

Step Into(x2) The concatenated value of

the next match point is split back into two 8 bit values and placed into the correct Output Compare Registers. Figure 72. OCR1B registers set The value loaded in the OCR1B registers will change every time the Output Compare interrupt happens.

Step Into(x?) Now that the trip point has been set, the user just needs to step through the

program until the Timer0 1 ms interrupt occurs. Use the procedures detailed in the time delay section to speed this process up. Stop when the cursor is positioned on the first line of the Timer0 OVF interrupt.

Figure 73. First line of code in Timer0 interrupt Step Into This line reloads TCNT0 to the correct value for the 1 ms interrupt interval. Step Into If the variable beep is anything other than zero, then the program will keep the

Output Compare port bit enabled for output to allow the game user to hear the tone. In this case beep should be 100 which will cause the program to fall into the IF statement.

Step Into Once in the IF statement, the program will

decrement beep by one. Figure 74. Decrement beep Step Into This line of code enables PortD bit 4, the Output Compare B output bit, as an

output. In this configuration, the game user will be able to hear the tone that is being created by Timer1’s Output Compare B unit.

Figure 75. PortD bit 4 configured as output Now, the next time TCNT1 and OCR1B match, the output bit

PortD bit 4 will toggle its state.

Page 34: Simulation AVR Studio 4

Purdue University C

Page 34 9/27/2005

Step Into(x?) The next order of business is to create the Output Compare match again. In this situation to get the proper operation from the simulator, the user will need to make the TCNT1 and OCR1B registers match. When they match, the output bit will automatically toggle its state before entering the Output Compare interrupt service routine.

Figure 76. Bit toggled high. (Not shown in PORTD register for unknown reason) The user simply needs to keep using the steps covered in this section in order to see the output bit toggle on and off when the variable beep is not zero. At this point, the user will be able to simulate basic input/outputs functions and timer functions. The next function of the ATMEGA16 to be covered in this tutorial is the serial communication or USART functions. Serial Communication Functions Serial communication allows the microcontroller another avenue for communicating with the outside world. The unit that allows for serial communication in the ATMEGA16 is the USART or Universal Synchronous-Asynchronous Receiver/Transmitter. This unit uses three lines to connect to other devices. The lines are ground, send (transmit), and receive. In this program, the microcontroller will be communicating with a Terminal program. The Terminal program allows characters sent to it by the microcontroller to be displayed for the user, generally on a computer screen. There is a draw back of using Studio to simulate USART communications. If the program uses the STDIO.H header/library functions to exercise the USART, Studio will not simulate the communication correctly. In other words, if the simulator is to be used, the user must create the functions to communicate serially. Do not use printf, scanf, etc. This is because the simulator does not have the ability to bring in functions include in the program via the #include or #define commands. There is a way around this limitation. There is another program that will connect to Studio in order to show the user what would be sent or received via the USART unit. This program is called HAPSIM. HAPSIM has functions other than the USART but those will not be discussed in this tutorial. This program works with the STDIO.H library file and its functions – printf, scanf, etc. Due this limitation this section of the tutorial will be split into two sections. One section will discuss simulating the USART operations using programmer created communication functions. The other section will discuss HAPSIM and its use with the STDIO.H functions. Studio Setup for USART Simulation Step 1 Load the code from Appendix C into the Studio software. Follow the instruction discussed

earlier in the tutorial to load the simulator.

Page 35: Simulation AVR Studio 4

Purdue University C

Page 35 9/27/2005

Step 2 Once the code has been loaded and is ready to simulate the operation, expand the I/O ATMEGA16 option in the Workspace window. After that has expanded, also expand the USART section.

Figure 77. Workspace with expanded USART

Here is a quick description of the main Timer registers:

UDR – USART I/O Data register. This register contains the current

information being received by or sent from the USART. UCSRX - USART Control Status registers A, B and C. These registers contain

the different flag bit necessary to operate different types of communication via the USART. The main register of interest for this tutorial is UCSRA.

UBRRX -This is a 16 bit register (UBRRH and UBRRL) that controls the format and speed of the data communication.

There is one other detail the users needs to be aware of when using the USART. The USART contains a buffer for the input and output of information. This buffer is two 8 bit registers deep. In other words, two 8 bit characters can be held in this buffer. This buffer will come into play as the user steps through the tutorial. Step 3 To make it easier to follow what is happening in the during the simulation, it may be

necessary to add a number of variables to the Watch Window. The main variables recommended for addition to the Watch Window are ptr and msg. However, these variables will only contain a value when the cursor is within the function that contains that variable. Otherwise the variable contents will read “Not in scope”.

Figure 78. Watch Window variables User created USART Procedures This section will step the user through the process of simulating serial communication when using program created communication functions. Each step in this procedure signifies the user pressing the Step Into option once unless told otherwise in the procedure. Step Into(x6) The I/O ports A, C, and D are configured for operation with the program. Step Into The register UCSRA is configured as 0x00. Step Into The register UCSRB is configure to enable the transmit and receive functions of

the USART. Step Into UCSRC is configured to provide and receive a data stream of 8 data bits and 1

stop bit with no parity bit. The communication is also set to be in asynchronous mode.

Page 36: Simulation AVR Studio 4

Purdue University C

Page 36 9/27/2005

Step Into(x2) These lines of code configure the Baud rate (speed of communication) to 9600 baud.

Step Into The state machine is entered. Step Into The first case is entered. Step Into The next case is set to be executed. Step Into The function show_message() is called with a 2 passed to the function. Step Into The cursor should now have moved

to the show_message() function. The first line of code to be executed will call another function, write_serial(), in order to move the display on the Terminal program to the next line down. This character, 0xa, will be the first character sent out the USART to the Terminal program.

Figure 79. Cursor ready to send first character

Step Into The program will now wait until the USART Data Register is Empty which is signified by the UDRE flag of the UCSRA register being a high.

Figure 80. Waiting to transmit

The UDRE flag will start the program in the high state. This bit is set high whenever the processor resets. It will stay high until either the buffer (two 8 bit registers deep) is full or the UDRE flag is cleared by the program. Once the buffer is full, the UDRE flag should be in its low state. It will stay in that state until the information in the buffer has had at least one of its registers emptied. The user should note that the UDRE flag will stay high until the first two characters have been sent to the USART. After this each character sent to the USART will cause the flag to change states to low signifying that the buffer is full and the first character in the buffer will be sent through the USART. This then moves the previous character into the buffer register to be sent next and the current character into the buffer register waiting to be sent.

Step Into Once this bit goes high it tells the microcontroller that at least one register in the

buffer has been sent and that it is ready to hold the next data. But before the data can be sent to the USART, the UDRE bit must be cleared by writing a high into that bit of the UCSRA register.

Page 37: Simulation AVR Studio 4

Purdue University C

Page 37 9/27/2005

Step Into The next line of code simply writes the 8 bits of data to be sent to the Terminal program into the UDR register. The UDR register is the store place for information

to be sent out prior to the being put in the buffer or information that was received through the buffer by

Figure 81. Data is ready to be sent the microcontroller. Step Into The next step will send one

character from the buffer out of the USART to the Terminal program that is connected to the microcontroller. Figure 82. Data has been sent

Step Into(x2) The next character to be sent is the command to move the cursor on the Terminal

program back to the beginning of the new line it is sitting on. Also notice here that the variable msg is in scope and contains information that

tells this program which message will be sent to the Terminal program in the next couple of statements in the show_message() function.

Figure 83. Message to display is shown Step Into(x5) Step through the process described above to send the return command character.

If the UDRE bit is not set, the program will wait until it has become set. The user simply needs to click on that bit Figure 84. Manually setting UDRE position in the UCSRA register to cause that bit to be toggled high. This process is that same as setting a port bit high.

Step Into The cursor should now be pointing to the line of code that sets up the pointer to the first character of the message to be displayed on the Terminal program.

Figure 85. Ready to start sending the message This pointer will allow the program to send one character (8 bits) of the message at

a time to the USART to be sent to the Terminal program. Step Into The message this pointer is pointing to is “Playing “. This

means that the first character of the message to be sent should be ‘P’. In the Watch window, the user will be able to see the character that the pointer will be sending to the UDR register and the buffer.

Figure 86. First letter to be sent

Page 38: Simulation AVR Studio 4

Purdue University C

Page 38 9/27/2005

Step Into This line sets up a While loop to continually send one character at a time of the message to be displayed to the write_serial() function. Each character will be Figure 87. The declaration of the structure of messages sent until the pointer is pointing to the last character in that message or the last element in the structure containing the messages. This last character will be a null character or zero when the structure or array is declared in this fashion.

Step Into(x5) Again step through the write_serial() function. Notice that the ‘P’ or the ASCII value 0x50 was sent to the UDR. And again it may be necessary to manually set the UDRE flag in the UCSRA Figure 89. ‘P’ is being sent from the USART Register, if the user doesn’t want to wait through the buffer loading and unloading.

Step Into(x?) Continue to step through the show_message() function until the complete message has been sent through the USART.

This process will continue every time something in the program is updating the display on the Terminal program. But for each of the updates or changes in the display, the principles and operations are the same when using the USART. STDIO USART Procedures This section will describe how to simulate the USART when using the functions provided in the STDIO header file. Those functions include printf() and scanf(). Unfortunately, as mentioned earlier in this section, those functions can not be simulated through the previous procedure. But before the Studio procedures can be discussed, another software program needs to be downloaded and installed. This program will allow the user to see the characters displayed to the Terminal program as the Studio simulator is running. The program is HAPSIM. This program contains a simulator for the USART functionality along with other functions such as toggle switches, LEDs, and LCDs. This procedure will only describe the operations of the USART simulator. HAPSIM and Studio Setup for USART Simulation Step 1 Download and unzip HAPSIM and the USART<->TWI Converter from

www.helmix.at/hapsim.htm. Step 2 Load the code from Appendix D into Studio.

Page 39: Simulation AVR Studio 4

Purdue University C

Page 39 9/27/2005

Step 3 The next step will be to run the HAPSIM.exe file.

Figure 90. HAPSIM program upon open

Step 4 Now that HAPSIM is up and running, open

USART2TWI.xml from the HAPSIM program.

Figure 91. Open a file using HAPSIM

The HAPSIM workspace window will change from the LCD configuration to the USART configuration. This new configuration contains two windows. The user will only be using the USART window with the tutorial. So the user may close the other window if desired. Otherwise, the user simply needs to click on the USART window to make it the active window. The user will know which window is active by the label on the top of the HAPSIM

window. In this case, the HAPSIM window reads .

Page 40: Simulation AVR Studio 4

Purdue University C

Page 40 9/27/2005

Figure 92. USART window for HAPSIM open

Step 5 Configure the options on HAPSIM to work correctly with Sudio

a. Select Options on HAPSIM-USART. AVRStudio Hook and Stay on Top must be selected.

Figure 93. Options for USART HAPSIM b. Select the USART Terminal.

Then select Terminal Settings from Options. From the pull down menu for Serial Interface select USART. Then click OK when ready.

Figure 94. Terminal Settings window from HAPSIM

Page 41: Simulation AVR Studio 4

Purdue University C

Page 41 9/27/2005

c. Select ATmega16 from the pull down on the

main window.

Figure 95. Selecting the correct microcontroller

Now you can run or step through your program in the AVRStudio. The user should remember that Studio must be opened first for HAPSIM to run correctly. Otherwise, HAPSIM will give error messages. Also if Studio is shut down before HAPSIM, HAPSIM will give error messages. The user should also look closely at the differences between the code from Appendix C and Appendix D. There are quite a number of changes in the USART operation. The user should try to understand the differences. One thing the user needs to be aware of through this portion of the tutorial is that the USART registers and flags in the Studio Workspace will NOT work as before. The configuration will be visible. But the user will not be able to see the workings of the UDRE flag or the UDR register. The user must just understand how those two items are working together in the background.

Step Into(x6) The I/O ports A, C, and D are configured for operation with the program. Step Into The register UCSRA is configured as 0x00. Step Into The register UCSRB is configure to enable the transmit and receive functions of

the USART. Step Into UCSRC is configured to provide and receive a data stream of 8 data bits, 1 stop bit

with no parity bit. The communication is also set to be in asynchronous mode. Step Into(x2) These lines of code configure the Baud rate (speed of communication) to 9600

baud. Step Into The state machine is entered. Step Into The first case is entered. Step Into The next case is set to be executed. Step Into The character for the ASCII command to move to a new line is sent from the

USART. The user will not see anything happen in the HAPSIM here. It is invisible to the viewer.

Step Into Again the user will not see anything happen here. The character for the ASCII

command to return the cursor to the home position is sent from the USART. It is invisible to the viewer.

Page 42: Simulation AVR Studio 4

Purdue University C

Page 42 9/27/2005

Step Into The line of code sends the string contained in the array message2[] to the Terminal program. The user should be looking at HAPSIM when this line is executed.

Figure 96. The first line is shown in the Terminal simulator – HAPSIM Step Into(x?) The user should step through the rest of the program, exercising the skills learned

throughout this tutorial, to see the program functioning. References:

Images are taken from AVR Studio 4 and HAPSIM V2.05 using SNAGIT software AVR Studio 4 is available for free from the Atmel web site, http://www.atmel.com. HAPSIM is a free AVR periphery simulator from the Helmi web site, www.helmix.at/hapsim.htm

Appendix:

Page 43: Simulation AVR Studio 4

Purdue University C

Page 43 9/27/2005

Appendix A #include <mega16.h> unsigned char state = 1; //set entry case unsigned char random,game_index,pb_index,x,press,y; unsigned char LED_seq[22]; //storage for LED output sequence unsigned char PB_seq[22]; //storage for PB input sequence unsigned char show[]={1,2,4,8,16,32,64,128}; //display bits void main(void) { DDRA=0x00; //portA configured for input operation PORTA=0xFF; //portA configured for internal pullup resistors DDRC=0xFF; //portC configured for output operation PORTC=0x00; //portC configured for initial state of off (low) random=5; //initial condition for random while (1) { switch (state) { case 1: LED_seq[game_index] = random; //store new LED number ++game_index; for (x=0; x<game_index;x++) { PORTC = show[LED_seq[x]]; //show LED } state = 2; pb_index = 0; //clear pb index for next response string break; case 2: if(press = PINA) { state = 3; //go to debounce } break; case 3: x = 0; //prepare to detect key while (!(press & 0x01)) { press = press >> 1; //shift to find bit ++x; //count shifts } PB_seq[pb_index++] = x; //store number of pb pressed state = 4; //go to await release break; case 4: if (PINA == 0) //all released { state = 5; } break; case 5: if (pb_index != game_index) state = 2; //go back for more else state = 6; break; case 6: y = 0; //clear error flag for (x=0;x<game_index;x++) if (LED_seq[x] != PB_seq[x]) ++y;

//increment y if wrong if (y) { state = 1; //exit if sequences don't match game_index = 0; //start game over } else state = 7; //check for 20 sequence done break; case 7: if (game_index == 20) state = 1; //game done if 20 right else state = 1; //add one and do a new sequence break;

Page 44: Simulation AVR Studio 4

Purdue University C

Page 44 9/27/2005

default: break; } random = (++random & 0x7); //mod 8 random counter }; }

Page 45: Simulation AVR Studio 4

Purdue University C

Page 45 9/27/2005

Appendix B #include <mega16.h> unsigned int delay_time; unsigned int beep,beep_off; unsigned char state = 1; //set entry case unsigned char random,game_index,pb_index,x,press,y; unsigned char LED_seq[22]; //storage for LED output sequence unsigned char PB_seq[22]; //storage for PB input sequence unsigned char show[]={1,2,4,8,16,32,64,128}; //display bits unsigned int total; interrupt [TIM0_OVF] void timer0_ovf_isr(void) { TCNT0 = 256 - 94; //reload for 1 ms if (beep) { --beep; //decr beep counter DDRD = DDRD | 0x10; //set pd4 for output } else DDRD = DDRD & 0xEF; //set PD4 for input if (delay_time) --delay_time; //count down delay } interrupt [TIM1_COMPB] void timer1_compb_isr(void) { total = OCR1BH; total = (total << 8) + OCR1BL; total = total + beep_off; OCR1BH = (total & 0xFF00)>>8; OCR1BL = total & 0x00FF; } void main(void) { PORTA=0xFF; DDRA=0x00; PORTC=0x00; DDRC=0xFF; PORTD=0x00; DDRD=0x00; TCCR0=0x03; TCNT0=0x00; OCR0=0x00; TCCR1A=0x10; TCCR1B=0x02; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; TIMSK=0x09; #asm("sei") random = 5; while (1) { switch (state) { case 1: LED_seq[game_index] = random; //store new LED number ++game_index; delay_time = 2000; //wait to start sequence while(delay_time | delay_time); for (x=0; x<game_index;x++) { PORTC = show[LED_seq[x]]; //show LED delay_time = 500; //show LED for 1/2 second while(delay_time | delay_time);

Page 46: Simulation AVR Studio 4

Purdue University C

Page 46 9/27/2005

PORTC = 0x00; //clear LEDs for .3 second delay_time = 300; while(delay_time | delay_time); } beep_off = 187; //set for pleasing beep beep = 100; //longer beep to show end of sequence state = 2; pb_index = 0; //clear pb index for next response string break; case 2: if(press = PINA) { state = 3; //go to debounce beep = 15; //make a key beep } break; case 3: x = 0; //prepare to detect key while (!(press & 0x01)) { press = press >> 1; //shift to find bit ++x; //count shifts } PB_seq[pb_index++] = x; //store number of pb pressed delay_time = 100; //debounce input while(delay_time); //wait it out state = 4; //go to await release break; case 4: if (PINA == 0) //all released { state = 5; } break; case 5: if (pb_index != game_index) state = 2; //go back for more else state = 6; break; case 6: y = 0; //clear error flag for (x=0;x<game_index;x++) if (LED_seq[x] != PB_seq[x]) ++y; //increment y if wrong if (y) state = 8; //exit if sequences don't match else state = 7; //check for 20 sequence done break; case 7: if (game_index == 20) state = 8; //game done if 20 right else state = 1; //add one and do a new sequence break; case 8: if(y) beep_off = 20000; //set for rude sound beep = 500; //1/2 second tone state = 1; delay_time = 2000; //2 seconds game result display while(delay_time | delay_time); game_index=0; break; default: break; } random = (++random & 0x7); //mod 8 random counter }; }

Page 47: Simulation AVR Studio 4

Purdue University C

Page 47 9/27/2005

Appendix C #include <mega16.h> unsigned char state = 0; //set entry case unsigned char random,previous_msg,game_index,pb_index,x,press,y; unsigned char LED_seq[22]; //storage for LED output sequence unsigned char PB_seq[22]; //storage for PB input sequence unsigned char show[]={1,2,4,8,16,32,64,128}; //display bits void write_serial(unsigned char chs) { while (!(UCSRA & 0x20)) ; //wait for UDRE UCSRA = 0x20; //clear UDRE UDR =chs; //output character } void show_message(unsigned char msg) { unsigned char message[7][25] = {" ", //clear a line "Press a button to play. ", //start message "Playing ", //playing "Done. You are a loser!!!", "Done. You are a nerd!! ", "Done. You are a winner! ", "Done Simon Conqueror! "}; //big winner unsigned char *ptr; write_serial (0xa); //linefeed if serial write_serial(0xd); //cr ptr = &message[msg][0]; //point to message while (*ptr > 0) { write_serial(*ptr++); //send if serial } previous_msg = msg; //retain information on previous message } void add_seq(unsigned char seq) { if (seq > 1) write_serial(','); //send a comma if needed write_serial(' '); //send a space if (seq > 19) write_serial(0x32) ; // write the 2 if needed else if (seq > 9) write_serial(0x31); //write the 1 if needed write_serial((seq%10)+0x30); //and the sequence number } void main(void) { PORTA=0xFF; DDRA=0x00; PORTC=0xFF; DDRC=0xFF; PORTD=0x00; DDRD=0x00; UCSRA=0x00; UCSRB=0x18; UCSRC=0x86; UBRRH=0x00; UBRRL=0x26; while (1) { switch (state) { case 0: state = 1; //go to display sequence show_message(2); //playing game_index = 0; //restart sequence at 0 break; //get outta here

Page 48: Simulation AVR Studio 4

Purdue University C

Page 48 9/27/2005

case 1: LED_seq[game_index] = random; //store new LED number add_seq(++game_index); //add & display index for (x=0; x<game_index;x++) { PORTC = show[LED_seq[x]]; //show LED } state = 2; pb_index = 0; //clear pb index for next response string break; case 2: if(press = PINA) { state = 3; //go to debounce } break; case 3: x = 0; //prepare to detect key while (!(press & 0x01)) { press = press >> 1; //shift to find bit ++x; //count shifts } PB_seq[pb_index++] = x; //store number of pb pressed state = 4; //go to await release break; case 4: if (PINA == 0) //all released { state = 5; } break; case 5: if (pb_index != game_index) state = 2; //go back for more else state = 6; break; case 6: y = 0; //clear error flag for (x=0;x<game_index;x++) if (LED_seq[x] != PB_seq[x]) ++y; //increment y if wrong if (y) state = 8; //exit if sequences don't match else state = 7; //check for 20 sequence done break; case 7: if (game_index == 20) state = 8; //game done if 20 right else state = 1; //add one and do a new sequence break; case 8: if (game_index == 20) show_message(6); //Simon Conqueror else if (game_index > 12) show_message(5); //winner else if (game_index > 5) show_message(4); //nerd else show_message(3); //loser state = 0; show_message(0); //clear the screen for new game break; default: break; } random = (++random & 0x7); //mod 8 random counter }; }

Page 49: Simulation AVR Studio 4

Purdue University C

Page 49 9/27/2005

Appendix D #include <mega16.h> #include <stdio.h> unsigned char state = 0; //set entry case unsigned char random,game_index,pb_index,x,press,y; unsigned char LED_seq[22]; //storage for LED output sequence unsigned char PB_seq[22]; //storage for PB input sequence unsigned char show[]={1,2,4,8,16,32,64,128}; //display bits unsigned char message0[]= {" "}; //clear a line unsigned char message1[]= {"Press a button to play. "}; //start message unsigned char message2[]= {"Playing "}; //playing unsigned char message3[]= {"Done. You are a loser!!!"}; unsigned char message4[]= {"Done. You are a nerd!! "}; unsigned char message5[]= {"Done. You are a winner! "}; unsigned char message6[]= {"Done Simon Conqueror! "}; //big winner void add_seq(unsigned char seq) { if (seq > 1) printf("%c", 0x2c); //send a comma if needed printf("%c", 0x20); //send a space if (seq > 19) printf("%c", 0x32) ; // write the 2 if needed else if (seq > 9) printf("%c", 0x31); //write the 1 if needed printf("%c",((seq%10)+0x30)); //and the sequence number } void main(void) { PORTA=0xFF; DDRA=0x00; PORTC=0xFF; DDRC=0xFF; PORTD=0x00; DDRD=0x00; UCSRA=0x00; UCSRB=0x18; UCSRC=0x86; UBRRH=0x00; UBRRL=0x26; while (1) { switch (state) { case 0: state = 1; //go to display sequence printf("%c",0xa); //linefeed if serial printf("%c",0xd); //cr printf("%s", message2); //playing game_index = 0; //restart sequence at 0 break; //get outta here case 1: LED_seq[game_index] = random; //store new LED number add_seq(++game_index); //add & display index for (x=0; x<game_index;x++) { PORTC = show[LED_seq[x]]; //show LED } state = 2; pb_index = 0; //clear pb index for next response string break; case 2: if(press = PINA) { state = 3; //go to debounce } break; case 3: x = 0; //prepare to detect key while (!(press & 0x01))

Page 50: Simulation AVR Studio 4

Purdue University C

Page 50 9/27/2005

{ press = press >> 1; //shift to find bit ++x; //count shifts } PB_seq[pb_index++] = x; //store number of pb pressed state = 4; //go to await release break; case 4: if (PINA == 0) //all released { state = 5; } break; case 5: if (pb_index != game_index) state = 2; //go back for more else state = 6; break; case 6: y = 0; //clear error flag for (x=0;x<game_index;x++) if (LED_seq[x] != PB_seq[x]) ++y; //increment y if wrong if (y) state = 8; //exit if sequences don't match else state = 7; //check for 20 sequence done break; case 7: if (game_index == 20) state = 8; //game done if 20 right else state = 1; //add one and do a new sequence break; case 8: if (game_index == 20) { printf("%c",0xa); //linefeed if serial printf("%c",0xd); //cr printf("%s", message6); //playing //printf("Done Simon Conqueror! "); //Simon Conqueror } else if (game_index > 12) { printf("%c",0xa); //linefeed if serial printf("%c",0xd); //cr printf("%s", message5); //playing //printf("Done. You are a winner! "); //winner } else if (game_index > 5) { printf("%c",0xa); //linefeed if serial printf("%c",0xd); //cr printf("%s", message4); //playing //printf("Done. You are a nerd!! "); //nerd } else { printf("%c",0xa); //linefeed if serial printf("%c",0xd); //cr printf("%s", message3); //playing //printf("Done. You are a loser!!!"); //loser } state = 0; printf("%c",0xa); //linefeed if serial printf("%c",0xd); //cr printf("%s", message0); //playing //printf(" "); //clear the screen for new game break; default: break; } random = (++random & 0x7); //mod 8 random counter }; }

Page 51: Simulation AVR Studio 4

Purdue University C

Page 51 9/27/2005

Appendix E NOTE: The user should remember that this code can not be completely simulated as is. The user must remove the #defines and #includes for Studio to simulate the program properly. /***************************************************** This program was produced by the CodeWizardAVR V1.24.2c Standard Automatic Program Generator © Copyright 1998-2004 Pavel Haiduc, HP InfoTech s.r.l. http://www.hpinfotech.ro e-mail:[email protected] Project : Version : Date : 9/30/2004 Author : Dick Barnett Company : Purdue University Comments: Chip type : ATmega16 Program type : Application Clock frequency : 6.000000 MHz Memory model : Small External SRAM size : 0 Data Stack size : 256 *****************************************************/ #include <mega16.h> // Standard Input/Output functions #include <stdio.h> #include <delay.h> //define states for state machine #define wait_pb 0 #define add_disp_seq 1 #define press_detect 2 #define press_debounce 3 #define release_detect 4 #define all_in_check 5 #define check_response 6 #define twenty_yet 7 #define game_over 8 #define start_up 9 #define beep_tone 187 #define rude_tone 20000 #define RS PORTD.7 #define RW PORTD.5 #define E PORTD.6 unsigned int delay_time, time_out_delay_time; unsigned int beep,beep_off; unsigned char state = 9; //set entry case unsigned char random,previous_msg,game_index,pb_index,x,press,y; unsigned char LED_seq[22]; //storage for LED output sequence unsigned char PB_seq[22]; //storage for PB input sequence unsigned char show[]={1,2,4,8,16,32,64,128}; //display bits // Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { TCNT0 = 256 - 94; //reload for 1 ms if (beep) { --beep; //decr beep counter DDRD = DDRD | 0x10; //set pd4 for output } else DDRD = DDRD & 0xEF; //set PD4 for input if (delay_time) --delay_time; //count down delay if (time_out_delay_time) --time_out_delay_time; //count down delay

Page 52: Simulation AVR Studio 4

Purdue University C

Page 52 9/27/2005

} // Timer 1 output compare B interrupt service routine interrupt [TIM1_COMPB] void timer1_compb_isr(void) { OCR1B = OCR1B + beep_off; //increment for next tone toggle } void write_lcd (unsigned char ch, unsigned char dat) { if (dat) RS = 1; //must be data else RS = 0; //must be command RW = 0; //read write = write delay_time = 2; //delay at least 1 ms while (delay_time); E = 1; //enable high PORTB = ch; //data to output delay_time = 2; //delay a bit while (delay_time); E = 0; //drop enable delay_time = 3; //delay at least 2 ms while(delay_time); } void write_serial(unsigned char chs) { while (!(UCSRA & 0x20)) ; //wait for UDRE UCSRA = 0x20; //clear UDRE UDR =chs; //output character } void init_lcd (void) { unsigned char init[] = {0x38,0x38,0x38,0xc,0x1,0x6}; //init bytes unsigned char x; for (x=0;x<6;x++) write_lcd(init[x],0); //init lcd } void show_message(unsigned char msg) { unsigned char message[7][25] = {" ", //clear a line "Press a button to play. ", //start message "Playing ", //playing "Done. You are a loser!!!", "Done. You are a nerd!! ", "Done. You are a winner! ", "Done Simon Conqueror! "}; //big winner unsigned char *ptr; if (PIND.3) { write_lcd(0x1,0); //clear and home if LCD ptr = &message[previous_msg][0]; //point to previous message while (*ptr) write_lcd(*ptr++,1); //show previous message in line 1 write_lcd(0xc0,0); //point to beginning of line 2 } else { write_serial (0xa); //linefeed if serial write_serial(0xd); //cr } ptr = &message[msg][0]; //point to message while (*ptr > 0) { if (PIND.3) write_lcd(*ptr++,1); //send character if LCD else write_serial(*ptr++); //send if serial } previous_msg = msg; //retain information on previous message }

Page 53: Simulation AVR Studio 4

Purdue University C

Page 53 9/27/2005

void lcd_add_seq(unsigned char seq) { if (PIND.3) { write_lcd(0xc9,0); //place the cursor after 'playing' if (seq > 19) write_lcd(0x32,1) ; // write the 2 if needed else if (seq > 9) write_lcd(0x31,1); //write the 1 if needed write_lcd((seq%10)+0x30,1); //and the sequence number } else { if (seq > 1) write_serial(','); //send a comma if needed write_serial(' '); //send a space if (seq > 19) write_serial(0x32) ; // write the 2 if needed else if (seq > 9) write_serial(0x31); //write the 1 if needed write_serial((seq%10)+0x30); //and the sequence number } } // Declare your global variables here void main(void) { // Declare your local variables here // Input/Output Ports initialization // Port A initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=P State6=P State5=P State4=P State3=P State2=P State1=P State0=P PORTA=0xFF; DDRA=0x00; // Port B initialization // Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out // State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0 PORTB=0x00; DDRB=0xFF; // Port C initialization // Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out // State7=1 State6=1 State5=1 State4=1 State3=1 State2=1 State1=1 State0=1 PORTC=0xFF; DDRC=0xFF; // Port D initialization // Func7=Out Func6=Out Func5=Out Func4=In Func3=In Func2=In Func1=In Func0=In // State7=0 State6=0 State5=0 State4=T State3=T State2=T State1=T State0=T PORTD=0x00; DDRD=0xE0; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 93.750 kHz // Mode: Normal top=FFh // OC0 output: Disconnected TCCR0=0x03; TCNT0=0x00; OCR0=0x00; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 750.000 kHz // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Toggle // Noise Canceler: Off // Input Capture on Falling Edge TCCR1A=0x10; TCCR1B=0x02; TCNT1H=0x00; TCNT1L=0x00;

Page 54: Simulation AVR Studio 4

Purdue University C

Page 54 9/27/2005

ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer/Counter 2 initialization // Clock source: System Clock // Clock value: Timer 2 Stopped // Mode: Normal top=FFh // OC2 output: Disconnected ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // External Interrupt(s) initialization // INT0: Off // INT1: Off // INT2: Off MCUCR=0x00; MCUCSR=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x09; // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity // USART Receiver: On // USART Transmitter: On // USART Mode: Asynchronous // USART Baud rate: 9600 UCSRA=0x00; UCSRB=0x18; UCSRC=0x86; UBRRH=0x00; UBRRL=0x26; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off // Analog Comparator Output: Off ACSR=0x80; SFIOR=0x00; // Global enable interrupts #asm("sei") while (1) { switch (state) { case start_up: init_lcd(); show_message(1); //first message PORTC=0x00; //LEDs off beep_off = beep_tone; //set for pleasing beep state = wait_pb; break; case wait_pb: if (PINA) //wait any key pressed { state = add_disp_seq; //go to display sequence beep = 15; //short beep to acknowledge button press show_message(2); //playing game_index = 0; //restart sequence at 0 } break; //get outta here case add_disp_seq: LED_seq[game_index] = random; //store new LED number

Page 55: Simulation AVR Studio 4

Purdue University C

Page 55 9/27/2005

lcd_add_seq(++game_index); //add & display index delay_time = 2000; //wait to start sequence while(delay_time | delay_time); for (x=0; x<game_index;x++) { PORTC = show[LED_seq[x]]; //show LED delay_time = 500; //show LED for 1/2 second while(delay_time | delay_time); PORTC = 0x00; //clear LEDs for .3 second delay_time = 300; while(delay_time | delay_time); } beep = 100; //longer beep to show end of sequence state = press_detect; time_out_delay_time = 4000; //set for 4 second time-out of key press pb_index = 0; //clear pb index for next response string break; case press_detect: if(press = PINA) { state = press_debounce; //go to debounce beep = 15; //make a key beep time_out_delay_time = 4000; //set for 4 second time out on key press } if (!time_out_delay_time) { PB_seq[pb_index++] = 0xff; //put a known wrong value into PB sequence state = check_response; //exit to check responses } break; case press_debounce: x = 0; //prepare to detect key while (!(press & 0x01)) { press = press >> 1; //shift to find bit ++x; //count shifts } PB_seq[pb_index++] = x; //store number of pb pressed delay_time = 100; //debounce input while(delay_time); //wait it out state = release_detect; //go to await release break; case release_detect: if (PINA == 0) //all released { state = all_in_check; } break; case all_in_check: if (pb_index != game_index) state = press_detect; //go back for more else state = check_response; break; case check_response: y = 0; //clear error flag for (x=0;x<game_index;x++) if (LED_seq[x] != PB_seq[x]) ++y;

//increment y if wrong if (y) state = game_over; //exit if sequences don't match else state = twenty_yet; //check for 20 sequence done break; case twenty_yet: if (game_index == 20) state = game_over; //game done if 20 right else state = add_disp_seq; //add one and do a new sequence break; case game_over: if(y) beep_off = rude_tone; //set for rude sound beep = 500; //1/2 second tone if (game_index == 20) show_message(6); //Simon Conqueror else if (game_index > 12) show_message(5); //winner else if (game_index > 5) show_message(4); //nerd else show_message(3); //loser state = start_up;

Page 56: Simulation AVR Studio 4

Purdue University C

Page 56 9/27/2005

delay_time = 2000; //2 seconds game result display while(delay_time | delay_time); show_message(0); //clear the screen for new game break; default: break; } random = (++random & 0x7); //mod 8 random counter }; }