The hardware for our project consisted of an Atmel-32 microcontroller, an STK500 development board, a TV, and a keypad. We connected the TV’s video signal to PortD of the STK500 board as shown below:
Figure #1: Schematic of the connection from STK500 to TV
To interface the keypad to the PORTC of the STK500 development board, we set it up as shown below:
Figure #2: Schematic of the connection from STK500 to keypad
where pin 1 = PORTC.0, 2 = PORTC.1, etc.
To see the schematic of the full circuit, please refer to Appendix A.
Most of our final project consisted of writing a C program to program to the microcontroller. We basically had one state machine that we will call the “Game Machine” that controlled the flow of our game. The six states in our state machine are Start, SelectLevel, GridSetup, PlayGame, EndGame, and CleanState. The flow of the program with these six states is shown below:
Figure #3: State Diagram for Battleship
At the beginning of Line 231, we always check to see if there is an input from the keypad and we debounce the keypad inputs once again using a state machine with four states. The four states are Pushed, Debounce, Detect and DebouncedEnd and the flow of these states is shown below:
Figure #4: State Diagram for Debouncing Buttons
Analysis of State Machine for Debouncing Buttons :
In the Pushed state, we simply check to see which key was pressed and store it in a variable called lastbutnum. We also set the seed for our random number in this state using the value of TCNT0 when the key is pressed and adding it to the rand function.
In the Debounce state several things happen depending on the state of the “Game Machine”. First off though, we check to see if the button being pressed at that instant is the same as the value stored in lastbutnum. If it is, we execute commands in the Debounce state, if not, we go back to Pushed state. In the Debounce state, if the “Game Machine” is in the Start state and the # key is pressed, we will move onto the SelectLevel state. If we are in the SelectLevel state and the key pressed is a 0 or 1, then the level of the game will be set to easy or difficult and we move on to the GridSetup state. If we are in the GridSetup state, then pressing a 2, 4, 6 or 8 will move the starting position of the ship in a desired direction. If a 0 or 1 is pressed in this state, then we call a function that takes in several pieces of information and places the ship horizontally or vertically on the grid. Once all the ships have been allocated, if we are still in the GridSetup state, then pressing the # key will move the “Game Machine” to the PlayGame state. If we are in the PlayGame state, then any buttons pressed between 0 and 10 will indicate the coordinates that the player wants to shoot at. This is where we also call the function that determines whether the player hit the computers ship or not. If we are in the EndGame state, and the # key is pressed, then we will go back to the SelectLevel state. At the end of the Debounce state, we go to the Detect state.
In the Detect state, if the key getting pressed is the same as lastbutnum, we stay in the Detect State. If the key being pressed is different, then we go to the DebouncedEnd state.
In the DebouncedEnd state, if the key being pressed is the same as lastbutnum, we back to the Detect state. Otherwise we go back to the Pushed state and wait for another keypad input.
Analysis of the “Game Machine” states :
If we are in the Start state, we simply display the front page of our game, which includes a digital image of a side view of a battleship. The name of the game and our names are also displayed on this front page.
If we are in the SelectLevel state, we display the 2 levels of our game, easy or medium. After the player has chosen the level he wants, we go to the GridSetup state.
In the GridSetup State, we print the 10x10 grid for the player and we also print out the ships that the player has allocated on the grid. This is where the player can move the starting position of the ship around and allocate it vertically or horizontally. Once all the ships have been allocated, we move on to the PlayGame state.
In the PlayGame state, we first draw the grid for the computer and allocate his ships on the grid using a random function. It will stay on the computer grid until the player inputs a coordinate that he wants to shoot at. Once the player has inputted his coordinate, the game will pause for about 2 seconds so the player can see if he hit a ship and then we switch back to the player’s grid to allow the computer to shoot at the player’s ships. In this state the algorithms for easy and difficult are also called depending on the level that the player selected. We also display whose grid we are displaying on the screen in this state. This cycle continues in PlayGame until all the battleships on one grid have been sunk. Once this happens, we go to the EndGame state.
In the EndGame state, we display our end game page which tells who won the battleship match and allows the player to press the # sign in order to return to the SelectLevel state.
The CleanState state is pretty much a state where we go when we need to clear our TV screen. Depending on the value of a variable called direction, we go to EndGame state, we initialize our game board, or we go to PlayGame state.
Key Variable :
The key variable in our final design project was the playerAGrid and computerGrid arrays. These arrays stored each box in our grid and each of these boxes contained information that was imperative to the success of our final project. Each box in the grid was coded as follows :
Each square in the game grid holds two values. It tells if there is any ship present at all and the type of ship.
For example: if square 1,1 contains a carrier ship then it is represented in the following way:
| B7 || B6 || B5 || B4 || B3 || B2 || B1 || B0 |
| 0 || 1 || 0 || 1 || 0 || 0 ||0 || 1 |
Where the upper order bits are used to distinguish the type of ship in the grid position.
Low order bits are used to detect presence of ship and its status
4 bits are divided into two groups: Lower 2 bits tell if a ship is present and whether it was hit or missed. The next upper two bits tell the status of the grid box (if sunk)
| B3 || B2 || B1 || B0 || Description |
| 0 || 0 || 0 || 0 || || no ship present |
| 0 || 0 || 0 || 1 || || ship present and not yet hit not sunk with horizontal orientation |
| 1 || 0 || 0 || 1 || || ship present and not yet hit not sunk with vertical orientation |
| 0 || 0 || 1 || 0 || || ship not present, hit attempted and missed |
| 0 || 0 || 1 || 1 || || ship present, hit but not yet sunk (horizontal orientation) |
| 1 || 0 || 1 || 1 || || ship present, hit but not yet sunk (vertical orientation) |
| 0 || 1 || 1 || 1 || || ship present/hit and sunk (horizontal orientation) |
| 1 || 1 || 1 || 1 || || ship present/hit and sunk (vertical orientation) |
Most Challenging Aspect of the Software Implementation :
One of the main problems we had when designing this project was that the Mega32 microprocessor only has 2K of memory and the video generation code has a screen array that is necessary and takes up 1.6K, which means we only had 400 bytes to work with. Because of this limitation, several times during the design of our project, we ran out of SRAM memory. The main problem was that we had to be able to display two different grids, one for the player and one for the computer that were 10x10 in size so both grids together took up 200 bytes. This forced us to constantly try to optimize our code so that our variables would not exceed 200 bytes of memory. To make sure our we did not run out of SRAM memory, we made sure that everyone of the bits in the char variables were used in order to save memory.
Reference Code :
The code we started out with for video generation was taken from the ECE476 website at Cornell University and was written by Professor Bruce Land.
Things we attempted :
The main limitations of using the TV as a visual output is that we are limited by the amount of time we are given to perform computations and draw a picture onto the screen. We must fit everything we want to draw out onto the TV screen in Line 231, which only gives us about 60 lines of code. We really wanted to do animation of bullets firing across the screen towards the target but our design of the basic game play had taken so much computational time that we were not able to animate our game without significant flicker on the TV screen. With more time to be able to perform computations and output images onto the screen, we would of liked to add animation to make our game more realistic. The last thing we would of liked to do is put our game on a larger TV screen, which would make the game more enjoyable.