|
|
Appendix 1
Code Listing
download the code here
/* SIMON!! */
// Jorel Luyando - 391959
// Senaida San Miguel - 392059
#asm
.equ __lcd_port=0x15 ;port c
#endasm
#include lcd.h // LCD driver routines
#include 90s8515.h
#include Stdio.h
#include delay.h
#define prescale1 1
#define clear_on_match 8
#define OffT 2000
#define OnT 2000
#define userOnT 1000
#define LCDwidth 16 //number of characters across length of LCD
#define mask 0b00011000 //mask for random number generator
#define t1 50 //task 1 timeout value
#define t2 50 //task 2 timeout value
// state, mode, level, and color variables
enum gameStates {ModeStart, ModeSelect, LevelStart, LevelSelect, Playback, ButtonPress, Check, EndGame, RoundCheck, GameCont} gameState;
enum debounceStates {Released, MaybePressed, ButtonPressed, Pressed, MaybeReleased} debounceState;
enum modes {Simon, FFA} mode;
enum levels {easy, medium, hard} level;
enum colors {red, blue, yellow, green, grey} color;
//various variables for FSM and button debounce
unsigned char noteArray[99];
unsigned char reload, time1, time2;
unsigned char index, round, userNoteCount, noteCount;
unsigned char OffTimer, OnTimer, userOnTimer, timertemp;
unsigned char butnum, maybe;
unsigned char num, gameLength, speedup;
//flags needed
unsigned char bttnpressFlag, playbackFlag, userplaybackFlag, startFlag, selectFlag;
char lcd_buffer[17]; // LCD display buffer
flash int noteTable[8]={15267/2, 12121/2, 10204/2, 8097/2, 30534/2, 3824/2, 2000/2, 9090/2};
// must have first 4 values be red, blue, yellow, and green note values
//**********************************************************
/* Use an 1x16 alphanumeric LCD connected
to PORTA as follows:
[LCD pin] [8515]
1 GND - GND
2 +5V - Vcc
3 VLC 10k trimpot wiper (trimpot ends go to +Vcc and GND)
4 RS - PA0
5 RD - PA1
6 EN - PA2
11 D4 - PA4
12 D5 - PA5
13 D6 - PA6
14 D7 - PA7
*/
//**********************************************************
void soundOn(void); //turn speaker on
void soundOff(void); //turn speaker off
void ledsOn(void); //turn specified color leds on
void ledsOff(void); //turn all leds off
void wingame(void); //game is won, blink "win" light/sound pattern
void wrong(void); //game is lost, blink "lose" light/sound pattern
void modeLCD(void); //initializes LCD to display mode
void levelLCD(void); //initializes LCD to display level
void gameLCD(void); //initializes LCD to display game info
void updateLCD(void); //updates the number of rounds the user has won on LCD
void endgameLCD(void); //display losing msg, mode, level, rounds to user
void wingameLCD(void); //display winning msg, mode, level, rounds to user
void toggleMode(void); //toggles mode and updates LCD when select is pressed
void toggleLevel(void); //toggles level and updates LCD when select is pressed
void init(void); //initializes needed game variables
void randNote(void); //creates random note, inc(noteCount), stores note in noteArray
void playback(void); //runs through noteArray, turning on sound and led for a period of time
void userPush(void); //inc(userNoteCount), turns on sound and led of button pressed
void initialize(void); //initialize ports and timers
void task1(void); //FSM
void task2(void); //debounce buttons
//**********************************************************
//timer 0 overflow ISR
interrupt [TIM0_OVF] void timer0_overflow(void)
{
//reload to force 1 mSec overflow
TCNT0=reload;
//num is running for the randnum generator
num++;
//Decrement the three times if they are not already zero
if (time1>0) --time1; //task1 timer
if (time2>0) --time2; //task2 timer
if (OnTimer>0) --OnTimer; //time that LED/sound is on for playback
if (OffTimer>0) --OffTimer; //time that LED/sound is off for playback
if (userOnTimer>0) --userOnTimer; //time that LED/sound is on for user
}
//**********************************************************
//timer 1 compare-match A ISR
interrupt [TIM1_COMPA] void cmpA_overflow(void)
{
PORTA = ~PORTA ; //toggle the port to make a sound
}
//**********************************************************
void init(void)
{
//initialize needed game variables
noteCount = 0;
userNoteCount = 0;
index = 0;
round = 0;
bttnpressFlag = 0;
playbackFlag = 0;
userplaybackFlag=0;
startFlag = 0;
selectFlag = 0;
gameLength = 99;
num = 0;
color = grey;
mode = Simon;
level = easy;
gameState = ModeStart;
debounceState = Released;
OnTimer = 0;
OffTimer = 0;
userOnTimer = 0;
timertemp = OnT;
modeLCD();
}
//------------------------------------------------------------
void soundOn(void)
{
//zero the T1 counter
TCNT1 = 0;
//begin timer
TCCR1B = prescale1 + clear_on_match;
}
void soundOff(void)
{
//turn off timer
TCCR1B = 0;
}
void ledsOn(void)
{
if (color == red)
//light up red
PORTB = 0x01;
else if (color == blue)
//light up blue
PORTB = 0x02;
else if (color == yellow)
//light up yellow
PORTB = 0x04;
else if (color == green)
//light up green
PORTB = 0x08;
}
void ledsOff(void)
{
//turn off all leds
PORTB = 0x00;
}
//------------------------------------------------------------
void wrong(void)
{
//turn all the leds on
PORTB = 0xff;
//load the "wrong" note into OCR1A
OCR1A = noteTable[4];
//turn speaker "on" - turn on T1
soundOn();
//keep sound on a little longer
delay_ms(300);
}
void wingame(void)
{
//flash lights and play tune
//red
PORTB = 0x01;
OCR1A = noteTable[0];
soundOn(); //turn sound on
delay_ms(200); //hold sound out
//blue
PORTB = 0x02;
OCR1A = noteTable[1];
delay_ms(200); //hold sound/LED out
//yellow
PORTB = 0x04;
OCR1A = noteTable[2];
delay_ms(200); //hold sound/LED out
//green
PORTB = 0x08;
OCR1A = noteTable[3];
delay_ms(200); //hold sound/LED out
soundOff(); //turn sound off
PORTB = 0x00; //turn LEDS off
}
//------------------------------------------------------------
void modeLCD(void)
{
//clear the display
lcd_clear();
//display current mode to user
lcd_gotoxy(0,0);
lcd_putsf("Simon FFA " );
lcd_gotoxy(0,1);
lcd_putsf(" ^ ");
}
void levelLCD(void)
{
//clear the display
lcd_clear();
//display current level to user
lcd_gotoxy(0,0);
lcd_putsf("Easy Med Hard " );
lcd_gotoxy(0,1);
lcd_putsf(" ^ ");
}
void toggleMode(void)
{
//toggle modes
if (mode == Simon) mode = FFA;
else mode = Simon;
//display new mode
lcd_gotoxy(0,1);
if (mode==Simon)
lcd_putsf(" ^ ");
else lcd_putsf(" ^ ");
//load start/select "beep"
OCR1A = noteTable[6];
soundOn();
}
void toggleLevel(void)
{
//toggle levels
if (level == easy)
level = medium;
else if (level == medium)
level = hard;
else if (level == hard)
level = easy;
//display new level
lcd_gotoxy(0,1);
if (level == easy)
lcd_putsf(" ^ ");
else if (level == medium)
lcd_putsf(" ^ ");
else lcd_putsf(" ^ ");
//load start/select "beep"
OCR1A = noteTable[6];
soundOn();
}
//------------------------------------------------------------
void gameLCD(void)
{
//clear the display
lcd_clear();
//display mode to user
lcd_gotoxy(0,0);
if (mode == Simon)
lcd_putsf("Simon ");
else lcd_putsf("FFA ");
//display level to user
if (level == easy)
lcd_putsf("Easy");
else if (level == medium)
lcd_putsf("Med");
else lcd_putsf("Hard");
//display rounds won
lcd_gotoxy(0,1);
lcd_putsf("Rounds: 0 ");
}
void updateLCD(void)
{
//display current rounds won
lcd_gotoxy(0,1);
sprintf(lcd_buffer, "Rounds: %-i", round);
lcd_puts(lcd_buffer);
}
void endgameLCD(void)
{
//initialize the display
lcd_init(LCDwidth);
lcd_clear();
//display losing message and current round
lcd_gotoxy(0,0);
sprintf(lcd_buffer, "Loser! %-i rounds", round);
lcd_puts(lcd_buffer);
//display mode
lcd_gotoxy(0,1);
lcd_putsf("on ");
if (mode == Simon)
lcd_putsf("Simon ");
else lcd_putsf("FFA ");
//display level
if (level == easy)
lcd_putsf("Easy");
else if (level == medium)
lcd_putsf("Med");
else lcd_putsf("Hard");
}
void wingameLCD(void)
{
//clear display
lcd_clear();
//display winning message and rounds won
lcd_gotoxy(0,0);
sprintf(lcd_buffer, "Winner %-i rounds", round);
lcd_puts(lcd_buffer);
//display mode
lcd_gotoxy(0,1);
lcd_putsf("on ");
if (mode == Simon)
lcd_putsf("Simon ");
else lcd_putsf("FFA ");
//display level
if (level == easy)
lcd_putsf("Easy");
else if (level == medium)
lcd_putsf("Med");
else lcd_putsf("Hard");
}
//------------------------------------------------------------
void randNote(void)
{
//variables used in randNote()
unsigned char newColor;
unsigned char randnum;
//generate a random number
randnum = num & mask;
//create a new color by using random number
if (randnum == 0x00)
newColor = red;
else if (randnum == 0x08)
newColor = blue;
else if (randnum == 0x10)
newColor = yellow;
else if (randnum == 0x18)
newColor = green;
//append new color to end of sequence
noteCount++;
noteArray[noteCount-1] = newColor;
}
void playback(void)
{
//load the current color's note value into OCR1A
color = noteArray[index];
OCR1A = noteTable[color];
index++;
//speed up in FFA-medium and FFA-hard levels only
if (mode == FFA)
{
if (level == medium)
{
//speed up every 5 rounds
if (round%5 == 0) timertemp = timertemp - speedup;
}
else if (level == hard)
{
//speed up every 3 rounds
if (round%3 == 0) timertemp = timertemp - speedup;
}
}
//note/LED is on for the amount of time in timertemp
OnTimer = timertemp;
soundOn(); //turn on sound
ledsOn(); //turn on LED
}
void userPush(void)
{
//set flag low
bttnpressFlag = 0;
//load current color pressed into OCR1A
OCR1A = noteTable[color];
//user's current note count incremented
userNoteCount++;
//hold sound/LED on for period of time
userOnTimer = userOnT;
soundOn(); //turn sound on
ledsOn(); //turn LED on
}
//**********************************************************
// TASK 1 - FSM for Simon game
void task1(void)
{
time1 = t1;
//turn off start/select "beep"
if ((playbackFlag==0)&&(userplaybackFlag==0) )
{ soundOff();
ledsOff();
}
// Run FSM for Simon
switch(gameState)
{
case ModeStart:
if (startFlag == 1)
{
//init LCD to level
levelLCD();
gameState = LevelStart;
startFlag = 0;
//play start/select "beep"
OCR1A = noteTable[6];
soundOn();
}
else gameState = ModeSelect;
break;
case ModeSelect:
if (selectFlag == 1)
{
//toggle mode and update LCD
toggleMode();
gameState = ModeSelect;
selectFlag = 0;
}
else gameState = ModeStart;
break;
case LevelStart:
if (startFlag == 1)
{
//play start/select "beep"
OCR1A = noteTable[6];
soundOn();
//init length of game and speed up
if (mode==FFA)
{
//game is practically infinite
gameLength = 99;
//easy has no speedup
if ( (level == medium)||(level == hard) )
speedup = 2;
}
else // in Simon mode - no speed up at all
{ // speed up is initialized in init() to OnT
if (level == easy) gameLength = 7;
else if (level == medium) gameLength = 15;
else gameLength = 31; //hard is 31 rounds
}
randNote(); //create new random note
gameLCD(); //get LCD ready for game
gameState = Playback; //go to Playback state
startFlag = 0;
delay_ms(100);
soundOff(); //turn off sound
delay_ms(700); //let user get ready for game
}
else gameState = LevelSelect;
break;
case LevelSelect:
if (selectFlag == 1)
{
//toggle level and display
toggleLevel();
gameState = LevelSelect;
selectFlag = 0;
}
else gameState = LevelStart;
break;
case Playback:
if (playbackFlag == 0) //ready to play notes
{
//cycle through sequence
if (index < noteCount)
{
playbackFlag = 1; //we're going into playback mode now
playback(); //play note in noteArray
gameState = Playback;
}
else gameState = ButtonPress; //played all the notes, wait for user button press
}
//else do nothing - have to wait for end of playback mode
break;
case ButtonPress:
if (userplaybackFlag ==0) //ready to check if user pressed anything
{
if (bttnpressFlag == 1) //user pressed a colored button
{
userPush(); //play note/color that user pressed
userplaybackFlag =1; //go into userplayback mode
gameState = ButtonPress;
bttnpressFlag = 0;
//this line is set after userOnTimer has run out in the "main" function
//gameState = Check; //check if the button pressed is correct
}
}
else gameState = ButtonPress; //wait for user button press
break;
case Check:
if (color == noteArray[userNoteCount - 1])
gameState = GameCont;
else
{ //game is over, user pressed wrong button
wrong();
endgameLCD();
gameState = EndGame;
}
break;
case EndGame:
if (startFlag == 1)
{
init(); //reinitialize game vars for next game
modeLCD(); //reinitialize LCD
gameState = ModeStart; //begin new game
startFlag = 0;
}
else gameState = EndGame; //wait for user to press start
break;
case RoundCheck:
if (round < gameLength)
{
//user entered in the correct sequence
gameState = Playback;
randNote(); //create new note
index = 0; //reinitialize for new round
userNoteCount = 0; //reinitialize for new round
updateLCD(); //update rounds won
ledsOff();
soundOff();
delay_ms(800); //let user get ready for next round
}
else
{ //user won game
//blink winning lights, play winning sounds, update winning msg on LCD
wingame();
wingameLCD();
gameState = EndGame;
}
break;
case GameCont:
if (userNoteCount < noteCount)
gameState = ButtonPress; //wait for user to enter in the next color
else
{
round++; //user just won the round
gameState = RoundCheck;
}
break;
} // End FSM
}// end task 1
//------------------------------------------------------------
// TASK 2
void task2(void)
{
time2 = t2;
//get butnum from PIND
butnum = PIND;
switch(debounceState)
{
case Released:
if (butnum == 0) debounceState = Released;
else
{ maybe = butnum;
debounceState = MaybePressed;
}
break;
case MaybePressed:
if (butnum == maybe)
debounceState = ButtonPressed;
else debounceState = Released;
break;
case ButtonPressed:
if (butnum == 0x01)
{ color = red;
bttnpressFlag =1;
}
else if (butnum == 0x02)
{ color = blue;
bttnpressFlag =1;
}
else if (butnum == 0x04)
{ color = yellow;
bttnpressFlag =1;
}
else if (butnum == 0x08)
{ color = green;
bttnpressFlag =1;
}
else if (butnum == 0x80) startFlag = 1;
else if (butnum == 0x40) selectFlag = 1;
debounceState = Pressed;
break;
case Pressed:
if (butnum == maybe) debounceState = Pressed;
else debounceState = MaybeReleased;
break;
case MaybeReleased:
if (butnum==maybe) debounceState = Pressed;
else debounceState = Released;
break;
} //end debounce
}// end task 2
//**********************************************************
void main(void)
{
initialize();
init();
while(1)
{
if (time1==0) task1(); //FSM
if (time2==0) task2(); //debounce button
//check if we're still in playback mode
if (playbackFlag == 1)
{
if (OnTimer ==1) //catch it right before it zeros out
{ soundOff(); //turn off sound
ledsOff(); //turn off LED
OffTimer = timertemp; //set "off time"
}
//check if out of playback mode
if (OffTimer == 1) playbackFlag = 0;
}
else
{ //check if we're in user playback
if (userplaybackFlag==1)
{
if (userOnTimer ==1)
{
ledsOff(); //turn off LED
soundOff(); //turn off sound
userplaybackFlag =0; //out of userplayback mode
gameState = Check; //check if color entered is correct
}
}
}
} //end while
} //end main
//**********************************************************
//Set it all up
void initialize(void)
{
//set up the ports
DDRD=0x00; // PORT D is an input for buttons
// PORT C is an ouput for lcd
DDRB=0xff; // PORT B is an output for leds
DDRA=0xff; // PORT A is an output for speaker
PORTA=0;
PORTB=0x00; //all LEDs off
//set up timer 0
//62.5 x (64x.25) microSec = 1.0 mSec, so prescale 64, and count 62 times.
reload=256-125; //value for 1 Msec
TCNT0=reload; //preload timer 1 so that is interrupts after 1 mSec.
TCCR0=3; //prescalar to 64
TIMSK=2; //turn on timer 0 overflow ISR
//set up timer 1
TIMSK=TIMSK | 0x40; //turn on timer 1 compare match interrupt
TCCR1B = 0; //disable timer 1
TCNT1 = 0; //zero the timer
//init the task timers
time1=t1;
time2=t2;
//initialize and clear the display
lcd_init(LCDwidth);
lcd_clear();
//crank up the ISRs
#asm
sei
#endasm
}
|