phillip_bourdon234

diceGame_Main.c

Apr 6th, 2020 (edited)
666
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 15.43 KB | None | 0 0
  1. // A video demonstration of this project can be found here: https://bit.ly/3gY4HGI
  2.  
  3. /*
  4.  This rules of this dice game can be found on the wiki page titled
  5.  "Pigs Dice Game." The following parts were used in the making of this project:
  6.  
  7.  [1] PIC18F4520
  8.  [7] 20mA red LEDs
  9.  [7] 220 Ohm resistors
  10.  [2] Standard push buttons
  11.  [2] 10k Ohm resistors
  12.  [1] 10k potentiometer
  13.  [1] 5v regulator (L7805CV)
  14.  [2] 10 microfarad capacitors
  15.  [1] 9v battery
  16.  [1] LCD display (HD44780U)
  17.  [3] breadboards
  18.  */
  19.  
  20.  
  21. #include <xc.h>
  22. #include <pic18f4520.h>
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <stdbool.h>
  26. #include <stdint.h>
  27. #include "DiceGameConfig.h"
  28.  
  29. #define CLEAR 0x01
  30. #define SET_FUNCTION 0x3C
  31. #define DISPLAY_OFF 0x08 //note that this also sets the cursor off as well
  32. #define INCREMENT 0x06 //note that this also sets Shift to 0
  33. #define DISPLAY_ON 0x0C // note that the cursor is still off
  34. #define SET_8BITS 0x30
  35.  
  36. #define LCD_DATA_PINS LATD
  37. #define LCD_RS LATEbits.LE0
  38. #define LCD_RW LATEbits.LE1
  39. #define LCD_E LATEbits.LE2
  40. #define ROLL_BUTTON PORTCbits.RC2
  41. #define PASS_BUTTON PORTCbits.RC1
  42.  
  43. void bitSetupADC(void);
  44. void bitSetupOscillator(void);
  45. void bitSetupLEDs(void);
  46. void bitSetupButtons(void);
  47. void bitSetupLCD(void);
  48.  
  49. void initLCD(void);
  50. void LCDClock(void);
  51. void handleLCDCommands(uint8_t);
  52. void LCDPrintChar(uint8_t);
  53. void LCDPrintString();
  54. uint8_t intToLCDCharacters(int num);
  55.  
  56. void delay(int milliseconds);
  57. void updateScoreBoard(int num);
  58. void handleGame(int landedDiceVal);
  59. void handlePreGame(void);
  60. void runLEDs(void);
  61. void rollDice(int *pLandedDiceVal);
  62. void displayDice(int num);
  63. void changePlayersTurn(void);
  64. int makeRandomNumber(void);
  65. void playWinningGraphics(int winningPlayer);
  66. void handleButtonPresses(void);
  67. void resetGame(void);
  68.  
  69. bool playerOnesTurn = false;
  70. bool playerTwosTurn = false;
  71. bool combineScore = false;
  72. bool changingTurn = false;
  73. bool startOfGame = true;
  74. bool rollButtonPressed = false;
  75. bool passButtonPressed = false;
  76.  
  77. int playerOnesScore = 0;
  78. int playerTwosScore = 0;
  79. int playerOnesPotentialScore = 0;
  80. int playerTwosPotentialScore = 0;
  81.  
  82. void main(void)
  83. {
  84.     int landedDiceVal;
  85.     int *pLandedDiceVal;
  86.    
  87.     pLandedDiceVal = &landedDiceVal;
  88.    
  89.     bitSetupADC();
  90.     bitSetupOscillator();
  91.     bitSetupLEDs();
  92.     bitSetupButtons();
  93.     bitSetupLCD();
  94.    
  95.     initLCD();
  96.      
  97.     while(1)
  98.     {
  99.         while(startOfGame == true)
  100.         {
  101.           handlePreGame();  
  102.         }
  103.        
  104.         handleButtonPresses();
  105.        
  106.         if(ROLL_BUTTON == 1 && rollButtonPressed == true)
  107.         {
  108.             rollDice(pLandedDiceVal);
  109.             displayDice(landedDiceVal);
  110.             handleGame(landedDiceVal);
  111.             rollButtonPressed = false;
  112.         }
  113.         else if(PASS_BUTTON == 1 && passButtonPressed == true)
  114.         {
  115.             changingTurn = true;
  116.             changePlayersTurn();
  117.             delay(500);
  118.             passButtonPressed = false;
  119.         }
  120.     }
  121.      
  122. }
  123.  
  124. void bitSetupADC()
  125. {
  126.     TRISBbits.RB0 = 1;
  127.     ADCON0bits.CHS = 0b1100;
  128.     ADCON0bits.ADON = 1;
  129.     ADCON1bits.VCFG0 = 0;
  130.     ADCON1bits.VCFG1 = 0;
  131.     ADCON1bits.PCFG = 0b0001;
  132.     ADCON2bits.ADFM = 1;
  133.     ADCON2bits.ACQT = 0x04;
  134.     ADCON2bits.ADCS = 0x04;
  135. }
  136.  
  137. void bitSetupOscillator()
  138. {
  139.     OSCCONbits.IRCF = 0b111; //set internal oscillator to 8MHz
  140.     OSCCONbits.SCS = 0b10;
  141.     while(OSCCONbits.IOFS != 1);// wait until the oscillator is stable
  142. }
  143.  
  144. void bitSetupLEDs()
  145. {
  146.     TRISA = 0x00;
  147.     LATA = 0x00;
  148. }
  149.  
  150. void bitSetupButtons()
  151. {
  152.     TRISCbits.RC3 = 1;
  153.     TRISCbits.RC2 = 1;
  154. }
  155.  
  156. void bitSetupLCD()
  157. {
  158.     TRISD = 0x00; //sets LCD_DATA_PINS to output
  159.     TRISEbits.RE0 = 0; //sets LCD_RS to output
  160.     TRISEbits.RE1 = 0; // sets LCD_RW to output
  161.     TRISEbits.RE2 = 0; // sets LCD_E to output
  162.    
  163.    
  164.     //init RS, RW, E, and the data pins to low
  165.     LCD_RS = 0;
  166.     LCD_RW = 0;
  167.     LCD_E = 0;
  168.     LCD_DATA_PINS = 0x00;
  169. }
  170.  
  171. /*
  172.  LCDClock is called whenever data is sent to the LCD screen. In the data sheet,
  173.  it is shown that the data is transfered on the falling edge of the E pin.
  174.  Therefore, the function enables the E pin to 1, and then shortly after, to 0.
  175.  */
  176. void LCDClock()
  177. {
  178.     LCD_E = 1;
  179.     __delay_ms(1);
  180.     LCD_E = 0;
  181.     __delay_ms(1);
  182. }
  183.  
  184.  
  185. /*
  186.  handleLCDCommands is called whenever you want to send a specific command
  187.  to the LCD, such as CLEAR or SET_FUNCTION. Note that this function is
  188.  not writing to the LCD, which is why the RS pin is low;
  189.  */
  190. void handleLCDCommands(uint8_t command)
  191. {
  192.     LCD_RS = 0;
  193.     LCD_RW = 0;
  194.    
  195.     LCD_DATA_PINS = command;
  196.     LCDClock();
  197.     __delay_ms(10);
  198. }
  199.  
  200. /*
  201.  initLCD initializes the LCD. In the data sheet, there is a very specific way
  202.  to do it, so make sure that if you are using a different LCD, you must adjust
  203.  accordingly.
  204.  */
  205. void initLCD()
  206. {
  207.     LCD_RS = 0;
  208.     LCD_RW = 0;
  209.    
  210.     __delay_ms(50);
  211.     handleLCDCommands(SET_8BITS);
  212.     __delay_ms(10);
  213.     handleLCDCommands(SET_8BITS);
  214.     __delay_ms(1);
  215.     handleLCDCommands(SET_8BITS);
  216.    
  217.     handleLCDCommands(SET_FUNCTION);
  218.    
  219.     handleLCDCommands(DISPLAY_OFF);
  220.    
  221.     handleLCDCommands(CLEAR);
  222.    
  223.     handleLCDCommands(INCREMENT);
  224.    
  225.     handleLCDCommands(DISPLAY_ON);
  226. }
  227.  
  228.  
  229. /*
  230.  LCDSetCursor allows you to set a specific place on the LCD screen to write too.
  231.  for example, if you would like a character to show up on the first row on the
  232.  second column, you would pass in 0 and 1 to the function.
  233.  */
  234. uint8_t LCDSetCursor(uint8_t xPos, uint8_t yPos)
  235. {
  236.     if(yPos == 1)
  237.     {
  238.         xPos += 0x40;
  239.     }
  240.     handleLCDCommands(0x80 | xPos);
  241.     return xPos;
  242. }
  243.  
  244.  
  245. /*
  246.  LCDPrintChar allows you to write one uint8_t to the LCD screen. Note that you
  247.  cant simply pass in an 8 (LCDPrintChat(8)) as this is considered 8 in binary
  248.  and spits out a funky character. I have made a function, however, to convert
  249.  the integer into your desired character. That function is located on line 278.
  250.  */
  251. void LCDPrintChar(uint8_t x)
  252. {
  253.     LCD_RS = 1;
  254.     LCD_RW = 0;
  255.    
  256.     LCD_DATA_PINS = x;
  257.     LCDClock();
  258. }
  259.  
  260. /*
  261.  LCDPrintString allows you to write a string, such as "hello world" to the LCD screen.
  262.  */
  263. void LCDPrintString(const char *str)
  264. {
  265.     uint16_t i = 0;
  266.    
  267.     do
  268.     {
  269.         LCDPrintChar(str[i]);
  270.         i++;
  271.     }while(str[i] != '\0');
  272. }
  273.  
  274. /*
  275.  the makeRandomNumber function returns a random number based on an
  276.  analog signal from a floating pin.
  277.  */
  278.  
  279. int makeRandomNumber()
  280. {
  281.     int randomNumber;
  282.    
  283.     ADCON0bits.GODONE = 1;
  284.     while(ADCON0bits.GODONE);
  285.        
  286.     randomNumber = (ADRESH << 8) | (ADRESL);
  287.        
  288.     while(randomNumber >= 6)
  289.     {
  290.         randomNumber = randomNumber - 6;
  291.     }// maps the value of the ADC (0-1024) to (0-6)
  292.    
  293.     return randomNumber;
  294. }
  295.  
  296. /*
  297.  delay allows you to pass in high values, such as 60000 (1 minute) without
  298.  having any bugs with the __delay_ms function.
  299.  */
  300. void delay(int milliseconds)
  301. {
  302.     for(int i = 0; i < milliseconds/50; i++)
  303.          __delay_ms(50);
  304. }
  305.  
  306.  
  307. /*
  308.  intToLCDCharacter's purpose is to turn an integer into a byte that displays
  309.  the integer's value onto the LCD screen. For example, in the data sheet, to display
  310.  the number 0, you must send following byte: 0b00110000
  311.  this turns out to be 48 in decimal, and the numbers increment by 1 from there,
  312.  which explains the num + 48.
  313.  */
  314. uint8_t intToLCDCharacters(int num)
  315. {
  316.     num = num + 48;
  317.     return num;
  318. }
  319.  
  320.  
  321. /*
  322.  This function allows you to display any dice number you want by
  323.  passing in a number between 0-5.
  324.  */
  325. void displayDice(int num)
  326. {
  327.     int diceNumbers[6] = {0b00010000, 0b00100010, 0b00110010,
  328.                           0b01100011, 0b01110011, 0b01101111};
  329.    
  330.     LATA = diceNumbers[num];
  331.     delay(2500);
  332.     LATA = 0;
  333. }
  334.  
  335. /*
  336.  runLEDs displays the waiting animation on the LED dice.
  337.  */
  338. void runLEDs()
  339. {
  340.     int specificLED = 1;
  341.    
  342.     for(int i = 0; i < 21; i++)
  343.     {
  344.         LATA = specificLED;
  345.    
  346.         delay(100);
  347.    
  348.         specificLED = specificLED * 2;
  349.    
  350.         if(specificLED > 64)
  351.         {
  352.             specificLED = 1;
  353.         }
  354.     }
  355.     LATA = 0;
  356. }
  357.  
  358. /*
  359.  rollDice puts all the functions to use and handles everything that is needed
  360.  to roll and display the dice.
  361.  */
  362. void rollDice(int *pLandedDiceVal)
  363. {
  364.     runLEDs();
  365.        
  366.     *pLandedDiceVal = makeRandomNumber();
  367. }
  368.  
  369.  
  370. /*
  371.  the handlePreGame function handles who goes first.
  372.  */
  373. void handlePreGame()
  374. {
  375.     bool rollingDice;
  376.     bool tie = true;
  377.     int playerOnesRoll;
  378.     int playerTwosRoll;
  379.     int landedDiceVal;
  380.     int *pLandedDiceVal;
  381.    
  382.     pLandedDiceVal = &landedDiceVal;
  383.    
  384.     do
  385.     {
  386.         LCDSetCursor(0,0);
  387.         LCDPrintString("Player one");
  388.         LCDSetCursor(0,1);
  389.         LCDPrintString("please roll");
  390.    
  391.         while(ROLL_BUTTON != 0);
  392.    
  393.         rollingDice = true;
  394.         rollDice(pLandedDiceVal);
  395.         displayDice(landedDiceVal);
  396.         playerOnesRoll = landedDiceVal;
  397.    
  398.         LCDSetCursor(0,0);
  399.         LCDPrintString("Player two");
  400.         LCDSetCursor(0,1);
  401.         LCDPrintString("please roll");
  402.    
  403.         while(ROLL_BUTTON != 0);
  404.    
  405.         rollingDice = true;
  406.         rollDice(pLandedDiceVal);
  407.         displayDice(landedDiceVal);
  408.         playerTwosRoll = landedDiceVal;
  409.    
  410.         if(playerTwosRoll > playerOnesRoll)
  411.         {
  412.             handleLCDCommands(CLEAR);
  413.             LCDSetCursor(0,0);
  414.             LCDPrintString("Player two goes");
  415.             LCDSetCursor(0,1);
  416.             LCDPrintString("first");
  417.             delay(2500);
  418.             handleLCDCommands(CLEAR);
  419.             tie = false;
  420.             LCDSetCursor(0,0);
  421.             LCDPrintString("Player 1:  00");
  422.             LCDSetCursor(0,1);
  423.             LCDPrintString("Player 2:->00+00");
  424.             playerTwosTurn = true;
  425.             startOfGame = false;
  426.         }
  427.         else if(playerOnesRoll > playerTwosRoll)
  428.         {
  429.             handleLCDCommands(CLEAR);
  430.             LCDSetCursor(0,0);
  431.             LCDPrintString("Player one goes");
  432.             LCDSetCursor(0,1);
  433.             LCDPrintString("first");
  434.             delay(2500);
  435.             handleLCDCommands(CLEAR);
  436.             tie = false;
  437.             LCDSetCursor(0,0);
  438.             LCDPrintString("Player 1:->00+00");
  439.             LCDSetCursor(0,1);
  440.             LCDPrintString("Player 2:  00");
  441.             playerOnesTurn = true;
  442.             startOfGame = false;
  443.         }
  444.         else
  445.         {
  446.             handleLCDCommands(CLEAR);
  447.             LCDSetCursor(0,0);
  448.             LCDPrintString("Y'all tied");
  449.             delay(2000);
  450.             handleLCDCommands(CLEAR);
  451.         }
  452.     }while(tie);
  453. }
  454.  
  455. /*
  456.  the updateScoareBoard function updates the current players score.
  457.  */
  458. void updateScoreBoard(int num)
  459. {
  460.     int firstDigit;
  461.     int secondDigit;
  462.     //this first if/else statement creates two integers that can be passed
  463.     //into the intToLCDCharacters function, which is then passed in the
  464.     //LCDPrintChar function.
  465.     if(num > 9)
  466.     {          
  467.         firstDigit = num/10;
  468.         secondDigit = num-(firstDigit*10);
  469.     }
  470.     else
  471.     {
  472.         firstDigit = 0;
  473.         secondDigit = num;
  474.     }
  475.     if(playerOnesTurn)
  476.     {
  477.         if(combineScore == true)
  478.         {
  479.             LCDSetCursor(11,0);
  480.             combineScore = false;
  481.         }
  482.         else
  483.         {
  484.             LCDSetCursor(14,0);
  485.         }
  486.     }
  487.     else
  488.     {
  489.         if(combineScore == true)
  490.         {
  491.             LCDSetCursor(11,1);
  492.             combineScore = false;
  493.         }
  494.         else
  495.         {
  496.             LCDSetCursor(14,1);
  497.         }
  498.     }
  499.     LCDPrintChar(intToLCDCharacters(firstDigit));
  500.     LCDPrintChar(intToLCDCharacters(secondDigit));
  501. }
  502.  
  503. /*
  504.  The handleGame function runs the rules of the game and makes sure that
  505.  when the play rolls a one or the player reaches a score of 100, then the
  506.  game responds accordingly. This function also increments the players
  507.  potential score for that turn.
  508.  */
  509. void handleGame(int landedDiceVal)
  510. {
  511.     if(playerOnesTurn)
  512.     {  
  513.         if(landedDiceVal == 0) //if they player rolls a one, then their score
  514.         {                      //resets and it becomes the other players turn.
  515.             playerOnesPotentialScore = 0;
  516.             changingTurn = true;
  517.             changePlayersTurn();
  518.         }
  519.         else
  520.         {
  521.             playerOnesPotentialScore = playerOnesPotentialScore + landedDiceVal + 1;
  522.             updateScoreBoard(playerOnesPotentialScore);
  523.         }
  524.        
  525.         if((playerOnesPotentialScore + playerOnesScore) >= 100)
  526.         {
  527.             playWinningGraphics(1);
  528.             resetGame();
  529.         }
  530.     }
  531.     else
  532.     {  
  533.         if(landedDiceVal == 0)
  534.         {
  535.             playerTwosPotentialScore = 0;
  536.             changingTurn = true;
  537.             changePlayersTurn();
  538.         }
  539.         else
  540.         {
  541.             playerTwosPotentialScore = playerTwosPotentialScore + landedDiceVal + 1;
  542.             updateScoreBoard(playerTwosPotentialScore);
  543.         }
  544.          
  545.         if((playerTwosPotentialScore + playerTwosScore) >= 100)
  546.         {
  547.             playWinningGraphics(2);
  548.             resetGame();
  549.         }
  550.     }
  551. }
  552.  
  553. /*
  554.  The changePlayersTurn function changes the display to show the correct scores
  555.  of the players and indicates who's turn it is.
  556.  */
  557. void changePlayersTurn()
  558. {
  559.     while(changingTurn)
  560.     {
  561.         if(playerOnesTurn)
  562.         {
  563.             playerOnesScore = playerOnesScore + playerOnesPotentialScore;
  564.             combineScore = true;
  565.             LCDSetCursor(9,0);
  566.             LCDPrintString("  ");
  567.             LCDSetCursor(13,0);
  568.             LCDPrintString("   ");
  569.             LCDSetCursor(9,1);
  570.             LCDPrintString("->");
  571.             LCDSetCursor(13,1);
  572.             LCDPrintString("+00");
  573.             updateScoreBoard(playerOnesScore);
  574.         }
  575.         else
  576.         {
  577.             playerTwosScore = playerTwosScore + playerTwosPotentialScore;
  578.             combineScore = true;
  579.             LCDSetCursor(9,1);
  580.             LCDPrintString("  ");
  581.             LCDSetCursor(13,1);
  582.             LCDPrintString("   ");
  583.             LCDSetCursor(9,0);
  584.             LCDPrintString("->");
  585.             LCDSetCursor(13,0);
  586.             LCDPrintString("+00");
  587.             updateScoreBoard(playerTwosScore);
  588.         }
  589.         playerOnesPotentialScore = 0;
  590.         playerTwosPotentialScore = 0;
  591.         playerOnesTurn = !playerOnesTurn;
  592.         playerTwosTurn = !playerTwosTurn;
  593.         changingTurn = false;
  594.     }
  595. }
  596.  
  597. /*
  598.  the playWinningGraphics function displays the winning player on the LCD screen
  599.  and animates the LEDs before restarting the entire game.
  600.  */
  601. void playWinningGraphics(int winningPlayer)
  602. {
  603.     handleLCDCommands(CLEAR);
  604.    
  605.     if(winningPlayer == 1)
  606.     {
  607.         LCDPrintString("PLAYER ONE WINS!");
  608.     }
  609.     else
  610.     {
  611.         LCDPrintString("PLAYER TWO WINS!");
  612.     }
  613.     for(int i = 0; i < 3; i++)
  614.     {
  615.         runLEDs();
  616.     }
  617.     handleLCDCommands(CLEAR);
  618.     startOfGame = true;
  619. }
  620.  
  621. void handleButtonPresses()
  622. {
  623.     if(ROLL_BUTTON == 0)
  624.     {
  625.         rollButtonPressed = true;
  626.         passButtonPressed = false;
  627.     }
  628.     else if(PASS_BUTTON == 0)
  629.     {
  630.         rollButtonPressed = false;
  631.         passButtonPressed = true;
  632.     }
  633. }
  634.  
  635. void resetGame()
  636. {
  637.     playerOnesScore = 0;
  638.     playerTwosScore = 0;
  639.     playerOnesPotentialScore = 0;
  640.     playerTwosPotentialScore = 0;
  641. }
Add Comment
Please, Sign In to add comment