Interactive Tic-Tac-Toe

Final Project for Applications of Embedded Systems

MSP432p401R Launchpad Tic-Tac-Toe Project

MSP432P401R LaunchPad Kit

MKII Educational BoosterPack

Link to MSP432P401R LaunchPad Datasheet Link to MKII Educational BoosterPack Datasheet

Project Objective:

This project was a final project for an Embedded Systems course. My group (consisting of Kristina Brunsgaard, Frederick Norwood, and myself) decided to combine the basic embedded systems concepts covered in the course, which included learning how to to efficiently design embedded systems, program in C effectively, gain a conceptual understanding of microcontroller architecture and how to interact and configure input and output devices such as timers, analog-to-digital conversion, communication protocol, and sensors.

Our project was a simple game of Tic-Tac-Toe utilizing button and joystick interrupts, UART, LCD Display utilizing a SPI library,  and LEDs.

Non-Technical Overview of Implementation: Please view the block diagram with a high-level view of each module here.

  1.  Configurations: Block to configure ADC, UART, Buttons and to Enable Interrupts and Initialize Display.
  2.  _sleep() mode:  Condition that the microcontroller returns to when waiting for an interrupt flag.
  3.  Button interrupts: Handles anytime a user pushes a button. The button that is pressed is directed to the Case Statement Module.
  4.  Joystick Interrupts/Analog-to-Digital Conversion: Handles anytime a user moves the joystick. The ADC values recorded here are sent to the ADC module that correlates 1, 2, 3, or 4 for each of the respective directions. This data is sent forward to the Case Statement Module.
  5.  Case Statements: Based off of inputs sent to this module, this module is responsible for directing the next action to be taken. For example, if the input to this block is the initialize flag, it will send a signal to the Display Board Module to keep going through the initialization menu. Once the menu is complete, it will start taking joystick movements and adjusting the position on the LCD Screen.
  6.  Button A: Used in combination with the joystick movements, as a button push is needed to confirm a spot.
  7.  Player Won?: Checks for 3-in-a-row and diagonals. If no one wins, it sends the selected spot to the Display Board Module.
  8.  Button B: At any time during the game, a player can reset the board.
  9.  Display Board: Displays everything sent to the board.
  10.  Logging: Logs everything on a Realterm Screen.

Technical Overview of Implementation

Configurations: This block includes all of our configurations as completed in main. The configureserialport() function configures the UART pins to primary mode and sets a 115200 BAUD rate. The configureADC() function configures the ADC with reference voltage of 1.2V, 14-bit resolution, and single-conversion. It also maps the two joystick axes to the ADC. The configurebuttons() enables button interrupts, sets edge triggering, and sets it to pull-up resistors. Each one of these functions also enables the device-specific interrupt in the NVIC interrupt controller. Lastly, the setdisplay() function utilizes the graphics library to initialize the display on the LCD screen, set the default screen orientation as up, initialize the graphs foreground, background, and font, and write out initialization messages on the screen.

Sleep Mode: This block on the diagram represents a central "check-in" point, where after each individual process undergoes its function, it returns back to the main() loop. After the configurations are complete, main() enters a while loop, where sampling and conversion for the ADC begins, and the controller is put into sleep mode until an interrupt occurs. Note that each ISR returns back to this exact point in the Sleep Mode block.

Joystick and Button Interrupts, Analog-to-Digital (ADC) Immediately after a joystick interrupt occurs, the ADC outputs the discrete ADC values, stores each value for up and down movement in ADC14MEM[0], and stores each right and left movement in ADC14MEM[1]. Each one of these outputs is inputted to the ISRs, where depending on each one of these values, a different switch statement is called. There is also an ISR for when buttons are pressed on the Boosterpack, which similarly call a switch statement.

Switch Statements: As mentioned, each ADC value or button press serve as an input to each case statement, where each different case leads to different parts of the game being displayed on the screen. As the physical tic-tac-toe values on the board were created using a global array with spaces in the spots of the X's and O's, the board itself needed to created independent of array, which is incorporated into the function calling the switch statement. However, each of the case statements are divided into their own functions. The left, right, up, and down case statements change the "row" or "col" variables to be values 0-2 depending on the direction the joystick was moved. These statements also briefly display a small circle at specific locations on the screen depending on the current value of the row and column variables. The Init case statement does exactly the same as these other case statements, the only difference that the board is not displayed here; this was put in so the user would know that the game was started.

Further, after a user was able to actually choose their spot, the Button A case statement allowed a user to actually confirm their position, which really meant storing this "X" or "O" in the global array. If the spot has already been selected, a player will be allowed to try again to find another spot. Once either player won, the board would be reset allowing the two players to have a rematch. If either player wants to reset the board during the game without starting from all the introductory screens, a user can use the Button B case statement to do this.

__sleep() mode: Note that after when the board is reset, a player chooses a spot, or a player simply hovers over a spot, each part goes back to the Sleep Mode block, which waits for another interrupt to occur. In fact, once the game is initialized, almost each process goes back to sleep mode until a winner is determined.

Player Won?: This block essentially denotes the part of our code that checks if a row or column has three X's or O's, as well as the diagonals. If a player won, a green LED lights up, and if it's a tie then the red LED lights up. However, whether the game is over or if one party has won, either the controller goes back to the sleep() mode in main, or it goes to the "Play Again?" block that resets the board.

Logging: Although not physically connected to each specific block in Figure 1, our project also includes a logging portion that monitors each and every significant detail and sends it to the UART. The following is a snippet of what was displayed on RealTerm.

NOT PICTURED: Easter Eggs (literally): Although not included on the block diagram, press up 9 times when playing the game. You will encounter an "easter egg" in the most literal sense. Below is a picture of the easter-egg that pops up on the screen.

Libraries Used:

  1. Crystalfrontz128x128ST7735.h
  2. grlib.h
  3. driverlib.h
For more Details, Please View full project documentation Here.