Dependencies:   MCP23S17 RPG SDFileSystem TextLCD mbed wave_player

Fork of MCP23S17_Basic_IO_Demo by jim hamblen

Committer:
rpere
Date:
Mon Mar 04 20:00:26 2013 +0000
Revision:
3:accf08e39ba0
Parent:
2:934a0500abde
Child:
4:9ea6afd40e7e
Finished it!;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
4180_1 2:934a0500abde 1 // See http://mbed.org/users/romilly/notebook/mcp23s17-addressable-16-bit-io-expander-with-spi/
4180_1 2:934a0500abde 2 // MCP23S17 datasheet http://ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf
4180_1 2:934a0500abde 3 // uses MCP23S17 library version 0.4
4180_1 0:12f4911d7ba0 4
4180_1 0:12f4911d7ba0 5 #include "mbed.h"
4180_1 0:12f4911d7ba0 6 #include "MCP23S17.h"
rpere 3:accf08e39ba0 7 #include "TextLCD.h"
rpere 3:accf08e39ba0 8 #include "RPG.h"
rpere 3:accf08e39ba0 9 #include "wave_player.h"
rpere 3:accf08e39ba0 10 #include "SDFileSystem.h"
rpere 3:accf08e39ba0 11
rpere 3:accf08e39ba0 12 #define S_BEGIN 0
rpere 3:accf08e39ba0 13 #define S_PLAY 1
rpere 3:accf08e39ba0 14 #define S_VICTORY 2
rpere 3:accf08e39ba0 15 #define S_DEFEAT 3
rpere 3:accf08e39ba0 16
rpere 3:accf08e39ba0 17 // Creates an initializes all necessary objects
rpere 3:accf08e39ba0 18 void init();
rpere 3:accf08e39ba0 19 // Obstains menu input and updates LCD text accordingly
rpere 3:accf08e39ba0 20 int handleMenu();
rpere 3:accf08e39ba0 21 // Plays the current sequence so far using timing appropriate to the chosen difficulty
rpere 3:accf08e39ba0 22 void playSequence();
rpere 3:accf08e39ba0 23 // Listens for the player move and returns a value indicating success or failure
rpere 3:accf08e39ba0 24 int listenSequence();
rpere 3:accf08e39ba0 25 // Re-initializes the game
rpere 3:accf08e39ba0 26 void restart();
rpere 3:accf08e39ba0 27
rpere 3:accf08e39ba0 28
4180_1 2:934a0500abde 29 // Create SPI bus
4180_1 0:12f4911d7ba0 30 SPI spi(p5, p6, p7);
rpere 3:accf08e39ba0 31 // Create Text LCD Controller
rpere 3:accf08e39ba0 32 TextLCD lcd(p21, p22, p23, p24, p25, p26);
rpere 3:accf08e39ba0 33 // Create RPG interface
rpere 3:accf08e39ba0 34 RPG rpg(p16,p17,p20);
rpere 3:accf08e39ba0 35 // Create SD interface
rpere 3:accf08e39ba0 36 SDFileSystem sd(p11, p12, p13, p14, "sd");
rpere 3:accf08e39ba0 37 // Sound output
rpere 3:accf08e39ba0 38 AnalogOut DACout(p18);
rpere 3:accf08e39ba0 39 // Wave file player
rpere 3:accf08e39ba0 40 wave_player waver(&DACout);
rpere 3:accf08e39ba0 41 // Sound files
rpere 3:accf08e39ba0 42 FILE *Sounds[11];
rpere 3:accf08e39ba0 43
4180_1 2:934a0500abde 44 // Wiring Connections:
4180_1 0:12f4911d7ba0 45 // mbed p5,p6,p7 are tied to MCP23S17 SI, SO, SCK pins
rpere 3:accf08e39ba0 46 // mbed p8 to MCP23S17 CS
4180_1 2:934a0500abde 47 // MCP23S17 reset pin pulled high
rpere 3:accf08e39ba0 48
rpere 3:accf08e39ba0 49 // Chip addresses (opcodes)
rpere 3:accf08e39ba0 50 char opcodes[3];
rpere 3:accf08e39ba0 51 // Chip objects
rpere 3:accf08e39ba0 52 MCP23S17* chips[3];
rpere 3:accf08e39ba0 53
4180_1 0:12f4911d7ba0 54
rpere 3:accf08e39ba0 55 // Menu variables
rpere 3:accf08e39ba0 56 char* menuOptions[] = {
rpere 3:accf08e39ba0 57 " Easy >",
rpere 3:accf08e39ba0 58 "< Medium >",
rpere 3:accf08e39ba0 59 "< Hard "
rpere 3:accf08e39ba0 60 };
rpere 3:accf08e39ba0 61 short menuState = 0;
rpere 3:accf08e39ba0 62 short oldMenuState = -1;
rpere 3:accf08e39ba0 63 short menuBuffer = 0;
4180_1 0:12f4911d7ba0 64
rpere 3:accf08e39ba0 65 // Difficulty settings
rpere 3:accf08e39ba0 66 double timeoutVals[3] = { 2, 1.5, 1 };
rpere 3:accf08e39ba0 67 double delayVals[3] = { 0.5, 0.3, 0.1};
rpere 3:accf08e39ba0 68 short victoryVals[3] = {4 , 6, 8};
4180_1 0:12f4911d7ba0 69
rpere 3:accf08e39ba0 70 // Game variables
rpere 3:accf08e39ba0 71 short sequence[15];
rpere 3:accf08e39ba0 72 short current = 0;
rpere 3:accf08e39ba0 73 short gameState = 0;
rpere 3:accf08e39ba0 74 short victory;
rpere 3:accf08e39ba0 75 double timeout;
rpere 3:accf08e39ba0 76 double delay;
rpere 3:accf08e39ba0 77 char input = 0; // Push button input
rpere 3:accf08e39ba0 78 int main()
rpere 3:accf08e39ba0 79 {
rpere 3:accf08e39ba0 80
rpere 3:accf08e39ba0 81 init();
4180_1 0:12f4911d7ba0 82 while (1) {
rpere 3:accf08e39ba0 83 int menuSelection;
rpere 3:accf08e39ba0 84 switch(gameState)
rpere 3:accf08e39ba0 85 {
rpere 3:accf08e39ba0 86 case S_BEGIN:
rpere 3:accf08e39ba0 87 menuSelection = handleMenu();
rpere 3:accf08e39ba0 88 if(menuSelection > -1)
rpere 3:accf08e39ba0 89 {
rpere 3:accf08e39ba0 90 gameState = S_PLAY;
rpere 3:accf08e39ba0 91 timeout = timeoutVals[menuSelection];
rpere 3:accf08e39ba0 92 delay = delayVals[menuSelection];
rpere 3:accf08e39ba0 93 victory = victoryVals[menuSelection];
rpere 3:accf08e39ba0 94 }
rpere 3:accf08e39ba0 95 break;
rpere 3:accf08e39ba0 96
rpere 3:accf08e39ba0 97 case S_PLAY:
rpere 3:accf08e39ba0 98 playSequence();
rpere 3:accf08e39ba0 99 if(!listenSequence())
rpere 3:accf08e39ba0 100 gameState = S_DEFEAT;
rpere 3:accf08e39ba0 101 else if(current == victory)
rpere 3:accf08e39ba0 102 gameState = S_VICTORY;
rpere 3:accf08e39ba0 103 break;
rpere 3:accf08e39ba0 104
rpere 3:accf08e39ba0 105 case S_VICTORY:
rpere 3:accf08e39ba0 106 lcd.cls();
rpere 3:accf08e39ba0 107 lcd.locate(0,0);
rpere 3:accf08e39ba0 108 lcd.printf(" YOU WON :D ");
rpere 3:accf08e39ba0 109 lcd.printf(" <( . _ . )> ");
rpere 3:accf08e39ba0 110 waver.play(Sounds[10]);
rpere 3:accf08e39ba0 111 rewind(Sounds[10]);
rpere 3:accf08e39ba0 112 wait(5);
rpere 3:accf08e39ba0 113 gameState = S_BEGIN;
rpere 3:accf08e39ba0 114 restart();
rpere 3:accf08e39ba0 115 break;
rpere 3:accf08e39ba0 116
rpere 3:accf08e39ba0 117 case S_DEFEAT:
rpere 3:accf08e39ba0 118 lcd.cls();
rpere 3:accf08e39ba0 119 lcd.locate(0,0);
rpere 3:accf08e39ba0 120 lcd.printf(" DEFEAT ");
rpere 3:accf08e39ba0 121 lcd.printf(" TRY HARDER ");
rpere 3:accf08e39ba0 122 waver.play(Sounds[9]);
rpere 3:accf08e39ba0 123 rewind(Sounds[9]);
rpere 3:accf08e39ba0 124 wait(5);
rpere 3:accf08e39ba0 125 gameState = S_BEGIN;
rpere 3:accf08e39ba0 126 restart();
rpere 3:accf08e39ba0 127 break;
rpere 3:accf08e39ba0 128 default:
rpere 3:accf08e39ba0 129 lcd.printf("Invalid State");
rpere 3:accf08e39ba0 130 }
rpere 3:accf08e39ba0 131 handleMenu();
4180_1 0:12f4911d7ba0 132 }
4180_1 0:12f4911d7ba0 133 }
rpere 3:accf08e39ba0 134
rpere 3:accf08e39ba0 135 void init()
rpere 3:accf08e39ba0 136 {
rpere 3:accf08e39ba0 137
rpere 3:accf08e39ba0 138 // Set chips opcodes (Dependent on hardware connections)
rpere 3:accf08e39ba0 139 opcodes[0] = 0x40;
rpere 3:accf08e39ba0 140 opcodes[1] = 0x42;
rpere 3:accf08e39ba0 141 opcodes[2] = 0x44;
rpere 3:accf08e39ba0 142
rpere 3:accf08e39ba0 143 /* Create IO Expander objects with their respective opcodes
rpere 3:accf08e39ba0 144 * and set port B of each chip for input and port A of each chip
rpere 3:accf08e39ba0 145 * for output.
rpere 3:accf08e39ba0 146 */
rpere 3:accf08e39ba0 147
rpere 3:accf08e39ba0 148 for(int i = 0; i <3 ; i++)
rpere 3:accf08e39ba0 149 {
rpere 3:accf08e39ba0 150 chips[i] = new MCP23S17(spi, p8, opcodes[i]);
rpere 3:accf08e39ba0 151 // Set all 8 Port A bits to output direction
rpere 3:accf08e39ba0 152 chips[i]->direction(PORT_A, 0x00);
rpere 3:accf08e39ba0 153 // Set all 8 Port B bits to input direction
rpere 3:accf08e39ba0 154 chips[i]->direction(PORT_B, 0xFF);
rpere 3:accf08e39ba0 155 // Turn off all LEDs
rpere 3:accf08e39ba0 156 chips[i]->write(PORT_A, 0);
rpere 3:accf08e39ba0 157 }
rpere 3:accf08e39ba0 158
rpere 3:accf08e39ba0 159 // Clear sequence
rpere 3:accf08e39ba0 160 for(int i = 0; i < 15; i++)
rpere 3:accf08e39ba0 161 sequence[i] = 0 ;
rpere 3:accf08e39ba0 162
rpere 3:accf08e39ba0 163 set_time(1256729737); // Set RTC time to Wed, 28 Oct 2009 11:35:37
rpere 3:accf08e39ba0 164
rpere 3:accf08e39ba0 165 // Initialize sounds and file system
rpere 3:accf08e39ba0 166 char ftotal[] = "/sd/sounds/x.wav";
rpere 3:accf08e39ba0 167 for(int i = 0;i<9;i++)
rpere 3:accf08e39ba0 168 {
rpere 3:accf08e39ba0 169 ftotal[11] = i + '0';
rpere 3:accf08e39ba0 170 Sounds[i] = fopen(ftotal, "r");
rpere 3:accf08e39ba0 171
rpere 3:accf08e39ba0 172 if(Sounds[i] == NULL)
rpere 3:accf08e39ba0 173 lcd.printf("SOUND ERROR");
rpere 3:accf08e39ba0 174 }
rpere 3:accf08e39ba0 175
rpere 3:accf08e39ba0 176 Sounds[9] = fopen("/sd/sounds/lose.wav", "r");
rpere 3:accf08e39ba0 177 Sounds[10] = fopen("/sd/sounds/win.wav" , "r");
rpere 3:accf08e39ba0 178 }
rpere 3:accf08e39ba0 179
rpere 3:accf08e39ba0 180 int handleMenu()
rpere 3:accf08e39ba0 181 {
rpere 3:accf08e39ba0 182 menuBuffer +=rpg.dir();
rpere 3:accf08e39ba0 183
rpere 3:accf08e39ba0 184 if(menuBuffer == -15)
rpere 3:accf08e39ba0 185 {
rpere 3:accf08e39ba0 186 menuState++;
rpere 3:accf08e39ba0 187 menuBuffer = 0;
rpere 3:accf08e39ba0 188 } else if (menuBuffer == 15)
rpere 3:accf08e39ba0 189 {
rpere 3:accf08e39ba0 190 menuState--;
rpere 3:accf08e39ba0 191 menuBuffer = 0;
rpere 3:accf08e39ba0 192 }
rpere 3:accf08e39ba0 193
rpere 3:accf08e39ba0 194 if(menuState < 0)
rpere 3:accf08e39ba0 195 menuState = 0;
rpere 3:accf08e39ba0 196 else if(menuState > 2)
rpere 3:accf08e39ba0 197 menuState = 2;
rpere 3:accf08e39ba0 198
rpere 3:accf08e39ba0 199 if( oldMenuState != menuState)
rpere 3:accf08e39ba0 200 {
rpere 3:accf08e39ba0 201 lcd.cls();
rpere 3:accf08e39ba0 202 lcd.printf("Difficulty:");
rpere 3:accf08e39ba0 203 lcd.locate(0,1);
rpere 3:accf08e39ba0 204 lcd.printf("%s", menuOptions[menuState]);
rpere 3:accf08e39ba0 205 }
rpere 3:accf08e39ba0 206 oldMenuState = menuState;
rpere 3:accf08e39ba0 207
rpere 3:accf08e39ba0 208 if(rpg.pb())
rpere 3:accf08e39ba0 209 return menuState;
rpere 3:accf08e39ba0 210 else
rpere 3:accf08e39ba0 211 return -1;
rpere 3:accf08e39ba0 212 }
rpere 3:accf08e39ba0 213
rpere 3:accf08e39ba0 214 void playSequence()
rpere 3:accf08e39ba0 215 {
rpere 3:accf08e39ba0 216 lcd.cls();
rpere 3:accf08e39ba0 217 lcd.locate(0,0);
rpere 3:accf08e39ba0 218 lcd.printf("Sequence Playing");
rpere 3:accf08e39ba0 219 lcd.printf("...");
rpere 3:accf08e39ba0 220 wait(delay + 0.5);
rpere 3:accf08e39ba0 221 sequence[current] = time(NULL)%9 ;
rpere 3:accf08e39ba0 222 current++;
rpere 3:accf08e39ba0 223 for(int i = 0; i < current; i++)
rpere 3:accf08e39ba0 224 {
rpere 3:accf08e39ba0 225 int chipNum = sequence[i]/3;
rpere 3:accf08e39ba0 226 int ledNum = sequence[i]%3;
rpere 3:accf08e39ba0 227 chips[chipNum]->write(PORT_A, (1 << ledNum) );
rpere 3:accf08e39ba0 228 waver.play(Sounds[sequence[i]]);
rpere 3:accf08e39ba0 229 rewind(Sounds[sequence[i]]);
rpere 3:accf08e39ba0 230 wait(delay);
rpere 3:accf08e39ba0 231 chips[chipNum]->write(PORT_A, 0);
rpere 3:accf08e39ba0 232 wait(delay);
rpere 3:accf08e39ba0 233 }
rpere 3:accf08e39ba0 234 lcd.cls();
rpere 3:accf08e39ba0 235 lcd.locate(0,0);
rpere 3:accf08e39ba0 236 lcd.printf("Get ready...");
rpere 3:accf08e39ba0 237 wait(timeout + 0.5 );
rpere 3:accf08e39ba0 238 lcd.cls();
rpere 3:accf08e39ba0 239 lcd.locate(0,0);
rpere 3:accf08e39ba0 240 lcd.printf("GO!!!");
rpere 3:accf08e39ba0 241 wait(delay + 0.3);
rpere 3:accf08e39ba0 242 }
rpere 3:accf08e39ba0 243
rpere 3:accf08e39ba0 244 int listenSequence()
rpere 3:accf08e39ba0 245 {
rpere 3:accf08e39ba0 246 time_t startTime = time(NULL);
rpere 3:accf08e39ba0 247 time_t currentTime = startTime;
rpere 3:accf08e39ba0 248 time_t timeDiff = 0;
rpere 3:accf08e39ba0 249 int totalTime = timeout * current;
rpere 3:accf08e39ba0 250 int currentCheck = 0;
rpere 3:accf08e39ba0 251 bool correct = false;
rpere 3:accf08e39ba0 252 int input;
rpere 3:accf08e39ba0 253 int oldInput[3] = {0, 0, 0};
rpere 3:accf08e39ba0 254 lcd.cls();
rpere 3:accf08e39ba0 255 while(timeDiff <= totalTime)
rpere 3:accf08e39ba0 256 {
rpere 3:accf08e39ba0 257 lcd.locate(0,0);
rpere 3:accf08e39ba0 258 lcd.printf("Time: %d", totalTime - timeDiff);
rpere 3:accf08e39ba0 259 if(totalTime - timeDiff < 10)
rpere 3:accf08e39ba0 260 lcd.printf(" ");
rpere 3:accf08e39ba0 261 lcd.locate(0,1);
rpere 3:accf08e39ba0 262 lcd.printf("Round: %d",current);
rpere 3:accf08e39ba0 263 currentTime = time(NULL);
rpere 3:accf08e39ba0 264 timeDiff = currentTime - startTime;
rpere 3:accf08e39ba0 265 for(int i = 0; i < 3; i++)
rpere 3:accf08e39ba0 266 {
rpere 3:accf08e39ba0 267 // Read lower 3 bits
rpere 3:accf08e39ba0 268 input = chips[i]->read(PORT_B) & 7;
rpere 3:accf08e39ba0 269
rpere 3:accf08e39ba0 270 if(input != 0 && oldInput[i] == 0)
rpere 3:accf08e39ba0 271 {
rpere 3:accf08e39ba0 272 chips[i]->write(PORT_A, input);
rpere 3:accf08e39ba0 273 wait(0.3);
rpere 3:accf08e39ba0 274 chips[i]->write(PORT_A, 0);
rpere 3:accf08e39ba0 275 if(correct)
rpere 3:accf08e39ba0 276 return 0;
rpere 3:accf08e39ba0 277
rpere 3:accf08e39ba0 278 int rest;
rpere 3:accf08e39ba0 279 if(input == 1)
rpere 3:accf08e39ba0 280 rest = 0;
rpere 3:accf08e39ba0 281 else if(input == 2)
rpere 3:accf08e39ba0 282 rest = 1;
rpere 3:accf08e39ba0 283 else if(input == 4)
rpere 3:accf08e39ba0 284 rest = 2;
rpere 3:accf08e39ba0 285 else
rpere 3:accf08e39ba0 286 rest = 3;
rpere 3:accf08e39ba0 287
rpere 3:accf08e39ba0 288 if( i * 3 + rest == sequence[currentCheck])
rpere 3:accf08e39ba0 289 {
rpere 3:accf08e39ba0 290 waver.play(Sounds[sequence[currentCheck]]);
rpere 3:accf08e39ba0 291 rewind(Sounds[sequence[currentCheck]]);
rpere 3:accf08e39ba0 292 currentCheck++;
rpere 3:accf08e39ba0 293 correct = true;
rpere 3:accf08e39ba0 294
rpere 3:accf08e39ba0 295 }
rpere 3:accf08e39ba0 296 else
rpere 3:accf08e39ba0 297 { lcd.cls();
rpere 3:accf08e39ba0 298 lcd.locate(0,0);
rpere 3:accf08e39ba0 299 lcd.printf("You pressed: %d", i * 3 + rest);
rpere 3:accf08e39ba0 300 lcd.locate(0,1);
rpere 3:accf08e39ba0 301 lcd.printf("Next Was: %d",sequence[currentCheck]);
rpere 3:accf08e39ba0 302 wait(6);
rpere 3:accf08e39ba0 303 return 0;
rpere 3:accf08e39ba0 304 }
rpere 3:accf08e39ba0 305 }
rpere 3:accf08e39ba0 306 oldInput[i] = input;
rpere 3:accf08e39ba0 307
rpere 3:accf08e39ba0 308 }
rpere 3:accf08e39ba0 309 correct = false;
rpere 3:accf08e39ba0 310
rpere 3:accf08e39ba0 311 if(currentCheck == current)
rpere 3:accf08e39ba0 312 break;
rpere 3:accf08e39ba0 313 }
rpere 3:accf08e39ba0 314 wait(delay + 0.5);
rpere 3:accf08e39ba0 315
rpere 3:accf08e39ba0 316 if(currentCheck == current)
rpere 3:accf08e39ba0 317 return 1;
rpere 3:accf08e39ba0 318 else
rpere 3:accf08e39ba0 319 return 0;
rpere 3:accf08e39ba0 320 }
rpere 3:accf08e39ba0 321
rpere 3:accf08e39ba0 322 void restart()
rpere 3:accf08e39ba0 323 {
rpere 3:accf08e39ba0 324 current = 0;
rpere 3:accf08e39ba0 325 menuState = 0 ;
rpere 3:accf08e39ba0 326 oldMenuState = -1;
rpere 3:accf08e39ba0 327 }