Software Design
For the computer player, an edge-triggered interrupt is generated any time the ball crosses a laser. For the human player, only the goal throws an interrupt, the rest of the sensors are masked out. In the interrupt service routine for the computer player, each laser has a specific position associated with it. The routine reads in the current state of the sensors, and then goes through a series of comparisons to determine which beam is broken. Once the routine finds which beam is broken, it writes the corresponding step position to the stepper motor. This causes the paddle to move to the location centered on that laser beam. Once the paddle is moved, the ISR clears the interrupt. This way, the paddle will follow the ball along the playing field. For the goal laser, the ISR updates the character display with the new score, centers the paddle on the playing field, and waits for the START button on the controller to be pressed before the paddle can be moved again.To keep track of time, we used the processor timer to generate an interrupt approximately once every second. In this ISR, the character display was updated with the new time, and then the interrupt was cleared.
The initialization portion of our code initializes all the registers needed for interrupts and timers, initializes the stepper motor position, and also initializes the character display. The main program loop is either constantly reading in the Nintendo controller values if a human player was selected, or sits in an infinite loop if the computer is playing, since the computer control is handled by interrupts. All of our code was written in assembly, since most of our control was done at the register level through interrupt routines, and we did not feel that any sections of the code really needed to be written in C.
The character display required a certain set of initialization values to be written to it with a specific delay between instructions during initialization. This was done by having the program loop for a specific amount of instructions before allowing another write to the LCD. The display also required a minimum time between normal writes, and we accounted for this delay in the same way. We wrote a specific function with arguments that were passed through specified registers and contained the character to be written and the position it would be written to on the display. This function included the loops to delay the processor between writes to the LCD.
The Nintendo controller was constantly read from and masked to compare for the specific button presses that were relevant at that point in the program. A delay was included between reads to allow for a smooth, more intuitive control. For the human controlled moving of the stepper motor, we found that the motor moved fluidly when each button press resulted in the motor moving five steps. This prevents the motor from stepping along slowly, and also allows for it to stop relatively quickly once the controller button is released.