2012-12-26 14:58:15 -07:00
|
|
|
/*
|
|
|
|
Started: 6-19-2007
|
|
|
|
Spark Fun Electronics
|
|
|
|
Nathan Seidle
|
2012-12-26 16:14:22 -07:00
|
|
|
|
2012-12-26 14:58:15 -07:00
|
|
|
Simon Says is a memory game. Start the game by pressing one of the four buttons. When a button lights up,
|
|
|
|
press the button, repeating the sequence. The sequence will get longer and longer. The game is won after
|
|
|
|
13 rounds.
|
2012-12-26 16:14:22 -07:00
|
|
|
|
2012-12-26 14:58:15 -07:00
|
|
|
This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
|
|
|
|
|
|
|
|
Simon Says game originally written in C for the PIC16F88.
|
|
|
|
Ported for the ATmega168, then ATmega328, then Arduino 1.0.
|
|
|
|
Fixes and cleanup by Joshua Neal <joshua[at]trochotron.com>
|
|
|
|
|
|
|
|
Generates random sequence, plays music, and displays button lights.
|
|
|
|
|
|
|
|
Simon tones from Wikipedia
|
|
|
|
- A (red, upper left) - 440Hz - 2.272ms - 1.136ms pulse
|
|
|
|
- a (green, upper right, an octave higher than A) - 880Hz - 1.136ms,
|
2012-12-26 16:14:22 -07:00
|
|
|
0.568ms pulse
|
2012-12-26 14:58:15 -07:00
|
|
|
- D (blue, lower left, a perfect fourth higher than the upper left)
|
2012-12-26 16:14:22 -07:00
|
|
|
587.33Hz - 1.702ms - 0.851ms pulse
|
2012-12-26 14:58:15 -07:00
|
|
|
- G (yellow, lower right, a perfect fourth higher than the lower left) -
|
2012-12-26 16:14:22 -07:00
|
|
|
784Hz - 1.276ms - 0.638ms pulse
|
2012-12-26 14:58:15 -07:00
|
|
|
|
|
|
|
The tones are close, but probably off a bit, but they sound all right.
|
2012-12-26 16:14:22 -07:00
|
|
|
|
2012-12-26 14:58:15 -07:00
|
|
|
The old version of SparkFun simon used an ATmega8. An ATmega8 ships
|
|
|
|
with a default internal 1MHz oscillator. You will need to set the
|
|
|
|
internal fuses to operate at the correct external 16MHz oscillator.
|
|
|
|
|
|
|
|
Original Fuses:
|
|
|
|
avrdude -p atmega8 -P lpt1 -c stk200 -U lfuse:w:0xE1:m -U hfuse:w:0xD9:m
|
|
|
|
|
|
|
|
Command to set to fuses to use external 16MHz:
|
|
|
|
avrdude -p atmega8 -P lpt1 -c stk200 -U lfuse:w:0xEE:m -U hfuse:w:0xC9:m
|
|
|
|
|
|
|
|
The current version of Simon uses the ATmega328. The external osciallator
|
|
|
|
was removed to reduce component count. This version of simon relies on the
|
|
|
|
internal default 1MHz osciallator. Do not set the external fuses.
|
2012-12-26 16:14:22 -07:00
|
|
|
*/
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
#include "hardware_versions.h"
|
2012-12-26 14:58:15 -07:00
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Define game parameters
|
2012-12-28 21:49:19 -07:00
|
|
|
#define MOVES_TO_WIN 13 //Number of rounds to succesfully remember before you win. 13 is do-able.
|
|
|
|
#define ENTRY_TIME_LIMIT 3000 //Amount of time to press a button before game times out. 3000ms = 3 sec
|
2012-12-26 16:14:22 -07:00
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
#define MODE_MEMORY 0
|
|
|
|
#define MODE_BATTLE 1
|
|
|
|
#define MODE_BEEGEES 2
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
int gameMode = MODE_MEMORY; //By default, let's play the memory game
|
2012-12-26 14:58:15 -07:00
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Game state variables
|
2011-03-24 16:05:35 -06:00
|
|
|
uint8_t moves[32];
|
|
|
|
uint8_t nmoves = 0;
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
//Timer 2 overflow ISR
|
2012-12-28 21:49:19 -07:00
|
|
|
/*ISR (SIG_OVERFLOW2)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-26 16:14:22 -07:00
|
|
|
// Prescalar of 1024, Clock = 16MHz, 15,625 clicks per second, 64us per click
|
|
|
|
|
|
|
|
// Preload timer 2 for 125 clicks. Should be 8ms per ISR call
|
2012-12-28 21:49:19 -07:00
|
|
|
TCNT2 = 131; //256 - 125 = 131
|
|
|
|
}*/
|
|
|
|
|
|
|
|
void setup()
|
|
|
|
{
|
|
|
|
|
|
|
|
init_gpio();
|
|
|
|
|
|
|
|
randomSeed(analogRead(0)); //Seed the random generator with noise on pin A0
|
|
|
|
|
|
|
|
/*
|
|
|
|
//Set Timer 0 Registers to Default Setting to over-ride the timer initialization made in the init() function of the \
|
|
|
|
//Arduino Wiring library (Wiring.c in the hardware/core/arduino folder)
|
|
|
|
TCCR0A = 0;
|
|
|
|
TIMSK0 = 0;
|
|
|
|
// Init timer 0 for delay_us timing (1,000,000 / 1 = 1,000,000)
|
|
|
|
//TCCR0B = (1<<CS00); // Set Prescaler to 1. CS00=1
|
|
|
|
TCCR0B = (1<<CS01); // Set Prescaler to 1. CS00=1
|
|
|
|
|
|
|
|
// Init timer 2
|
|
|
|
ASSR = 0;
|
|
|
|
// Set Prescaler to 1024. CS22=1, CS21=1, CS20=1
|
|
|
|
TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20);
|
|
|
|
TIMSK2 = (1<<TOIE2); // Enable Timer 2 Interrupt
|
|
|
|
|
|
|
|
cli(); //We don't use any interrupt functionality. Let's turn it off so Arduino doesn't screw around with it!
|
|
|
|
*/
|
|
|
|
|
|
|
|
Serial.begin(9600);
|
|
|
|
Serial.println("Welcome to Simon Says!");
|
|
|
|
/*
|
|
|
|
//Mode checking
|
|
|
|
// Check to see if the lower right button is pressed
|
|
|
|
if (checkButton() == CHOICE_YELLOW)
|
|
|
|
{
|
|
|
|
gameMode = MODE_BEEGEES;
|
|
|
|
|
|
|
|
//Turn on the yellow LED
|
|
|
|
setLEDs(CHOICE_YELLOW);
|
|
|
|
|
|
|
|
while(checkButton() != CHOICE_NONE) ; //Wait for user to stop pressing button
|
|
|
|
delay(100);
|
|
|
|
|
|
|
|
while(checkButton() == CHOICE_NONE)
|
|
|
|
{
|
|
|
|
//buzz(5);
|
|
|
|
//delay(750);
|
|
|
|
//if (checkButton() == CHOICE_NONE)
|
|
|
|
//{
|
|
|
|
//while (1)
|
|
|
|
playBeegees();
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check to see if LOWER RIGHT BUTTON is pressed
|
|
|
|
if (checkButton() == CHOICE_GREEN)
|
|
|
|
{
|
|
|
|
gameMode = MODE_BATTLE;
|
|
|
|
|
|
|
|
//Turn on the green LED
|
|
|
|
setLEDs(CHOICE_GREEN);
|
|
|
|
|
|
|
|
while(checkButton() != CHOICE_NONE) ; //Wait for user to stop pressing button
|
|
|
|
|
|
|
|
//Now do nothing. Battle mode will be serviced in the main routine
|
|
|
|
|
|
|
|
/*delay(100);
|
|
|
|
|
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
buzz(5);
|
|
|
|
delay(750);
|
|
|
|
if (checkButton() == CHOICE_NONE){
|
|
|
|
battle = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
//}
|
|
|
|
play_winner();
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
void loop()
|
|
|
|
{
|
|
|
|
// Wait for user to start game
|
|
|
|
attractMode();
|
|
|
|
|
|
|
|
// Indicate the start of game play
|
|
|
|
setLEDs(CHOICE_RED|CHOICE_GREEN|CHOICE_BLUE|CHOICE_YELLOW);
|
|
|
|
delay(1000);
|
|
|
|
setLEDs(CHOICE_OFF);
|
|
|
|
delay(250);
|
|
|
|
|
|
|
|
// Play game and handle result
|
|
|
|
if (game_mode() != 0)
|
|
|
|
{
|
|
|
|
// Player won, play winner tones
|
|
|
|
play_winner();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Player lost, play loser tones
|
|
|
|
play_loser();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
//General short delays, using internal timer do a fairly accurate 1us
|
2011-03-24 16:05:35 -06:00
|
|
|
#ifdef CHIP_ATMEGA168
|
2012-12-26 14:58:15 -07:00
|
|
|
void delay_us(uint16_t delay)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
|
|
|
while (delay > 256)
|
|
|
|
{
|
2012-12-26 16:14:22 -07:00
|
|
|
TIFR0 = (1<<TOV0); // Clear any interrupt flags on Timer0
|
2011-03-24 16:05:35 -06:00
|
|
|
TCNT0 = 0;
|
|
|
|
while ( (TIFR0 & (1<<TOV0)) == 0);
|
|
|
|
|
|
|
|
delay -= 256;
|
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
TIFR0 = (1<<TOV0); // Clear any interrupt flags on Timer0
|
|
|
|
|
|
|
|
// 256 - 125 = 131 : Preload timer 0 for x clicks. Should be 1us per click
|
2011-03-24 16:05:35 -06:00
|
|
|
TCNT0 = 256 - delay;
|
|
|
|
while ((TIFR0 & (1<<TOV0)) == 0) {
|
2012-12-26 16:14:22 -07:00
|
|
|
// Do nothing
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
//Lights a given LEDs
|
|
|
|
//Pass in a byte that is made up from CHOICE_RED, CHOICE_YELLOW, etc
|
|
|
|
void setLEDs(byte leds)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
if ((leds & CHOICE_RED) != 0)
|
|
|
|
digitalWrite(LED_RED, HIGH);
|
|
|
|
else
|
|
|
|
digitalWrite(LED_RED, LOW);
|
|
|
|
|
|
|
|
if ((leds & CHOICE_GREEN) != 0)
|
|
|
|
digitalWrite(LED_GREEN, HIGH);
|
|
|
|
else
|
|
|
|
digitalWrite(LED_GREEN, LOW);
|
|
|
|
|
|
|
|
if ((leds & CHOICE_BLUE) != 0)
|
|
|
|
digitalWrite(LED_BLUE, HIGH);
|
|
|
|
else
|
|
|
|
digitalWrite(LED_BLUE, LOW);
|
|
|
|
|
|
|
|
if ((leds & CHOICE_YELLOW) != 0)
|
|
|
|
digitalWrite(LED_YELLOW, HIGH);
|
|
|
|
else
|
|
|
|
digitalWrite(LED_YELLOW, LOW);
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef BOARD_REV_6_25_08
|
2012-12-26 16:14:22 -07:00
|
|
|
void init_gpio(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-26 16:14:22 -07:00
|
|
|
// 1 = output, 0 = input
|
2011-03-24 16:05:35 -06:00
|
|
|
DDRB = 0b11111111;
|
2012-12-26 16:14:22 -07:00
|
|
|
DDRC = 0b00001001; // LEDs and Buttons
|
|
|
|
DDRD = 0b00111110; // LEDs, buttons, buzzer, TX/RX
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
PORTC = 0b00100110; // Enable pull-ups on buttons 0, 2, 3
|
|
|
|
PORTD = 0b01000000; // Enable pull-up on button 1
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
2012-12-26 16:14:22 -07:00
|
|
|
#endif // End BOARD_REV_6_25_08
|
|
|
|
|
2011-03-24 16:05:35 -06:00
|
|
|
#ifdef BOARD_REV_4_9_2009
|
2012-12-26 16:14:22 -07:00
|
|
|
void init_gpio(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-26 16:14:22 -07:00
|
|
|
// 1 = output, 0 = input
|
|
|
|
DDRB = 0b11111100; // Button 2,3 on PB0,1
|
|
|
|
DDRD = 0b00111110; // LEDs, buttons, buzzer, TX/RX
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
PORTB = 0b00000011; // Enable pull-ups on buttons 2, 3
|
|
|
|
PORTD = 0b11000000; // Enable pull-up on button 0, 1
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
2012-12-28 21:49:19 -07:00
|
|
|
#endif // End BOARD_REV_4_9_2009
|
2011-03-24 16:05:35 -06:00
|
|
|
|
|
|
|
#ifdef BOARD_REV_PTH
|
2012-12-26 16:14:22 -07:00
|
|
|
void init_gpio(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
//Enable pull ups on inputs
|
|
|
|
pinMode(BUTTON_RED, INPUT_PULLUP);
|
|
|
|
pinMode(BUTTON_GREEN, INPUT_PULLUP);
|
|
|
|
pinMode(BUTTON_BLUE, INPUT_PULLUP);
|
|
|
|
pinMode(BUTTON_YELLOW, INPUT_PULLUP);
|
|
|
|
|
|
|
|
pinMode(LED_RED, OUTPUT);
|
|
|
|
pinMode(LED_GREEN, OUTPUT);
|
|
|
|
pinMode(LED_BLUE, OUTPUT);
|
|
|
|
pinMode(LED_YELLOW, OUTPUT);
|
|
|
|
|
|
|
|
pinMode(BUZZER1, OUTPUT);
|
|
|
|
pinMode(BUZZER2, OUTPUT);
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
2012-12-28 21:49:19 -07:00
|
|
|
#endif // End BOARD_REV_PTH
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
// Returns a '1' bit in the position corresponding to CHOICE_RED, CHOICE_GREEN, etc.
|
|
|
|
byte checkButton(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
byte buttonPressed = CHOICE_NONE;
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
if (digitalRead(BUTTON_RED) == 0) buttonPressed |= CHOICE_RED;
|
|
|
|
if (digitalRead(BUTTON_GREEN) == 0) buttonPressed |= CHOICE_GREEN;
|
|
|
|
if (digitalRead(BUTTON_BLUE) == 0) buttonPressed |= CHOICE_BLUE;
|
|
|
|
if (digitalRead(BUTTON_YELLOW) == 0) buttonPressed |= CHOICE_YELLOW;
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
return buttonPressed;
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Play the loser sound/lights
|
|
|
|
void play_loser(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
setLEDs(CHOICE_RED|CHOICE_GREEN);
|
2011-03-24 16:05:35 -06:00
|
|
|
buzz_sound(255, 1500);
|
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
setLEDs(CHOICE_BLUE|CHOICE_YELLOW);
|
2011-03-24 16:05:35 -06:00
|
|
|
buzz_sound(255, 1500);
|
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
setLEDs(CHOICE_RED|CHOICE_GREEN);
|
2011-03-24 16:05:35 -06:00
|
|
|
buzz_sound(255, 1500);
|
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
setLEDs(CHOICE_BLUE|CHOICE_YELLOW);
|
2011-03-24 16:05:35 -06:00
|
|
|
buzz_sound(255, 1500);
|
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Play the winner sound
|
|
|
|
void winner_sound(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
byte x, y;
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Toggle the buzzer at various speeds
|
2012-12-28 21:49:19 -07:00
|
|
|
for (x = 250 ; x > 70 ; x--) {
|
|
|
|
for (y = 0 ; y < 3 ; y++) {
|
|
|
|
//sbi(BUZZER2_PORT, BUZZER2);
|
|
|
|
//cbi(BUZZER1_PORT, BUZZER1);
|
|
|
|
digitalWrite(BUZZER2, HIGH);
|
|
|
|
digitalWrite(BUZZER1, LOW);
|
|
|
|
delayMicroseconds(x);
|
|
|
|
|
|
|
|
//cbi(BUZZER2_PORT, BUZZER2);
|
|
|
|
//sbi(BUZZER1_PORT, BUZZER1);
|
|
|
|
digitalWrite(BUZZER2, LOW);
|
|
|
|
digitalWrite(BUZZER1, HIGH);
|
|
|
|
delayMicroseconds(x);
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Play the winner sound and lights
|
2012-12-26 14:58:15 -07:00
|
|
|
void play_winner(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
setLEDs(CHOICE_GREEN|CHOICE_BLUE);
|
2011-03-24 16:05:35 -06:00
|
|
|
winner_sound();
|
2012-12-28 21:49:19 -07:00
|
|
|
setLEDs(CHOICE_RED|CHOICE_YELLOW);
|
2011-03-24 16:05:35 -06:00
|
|
|
winner_sound();
|
2012-12-28 21:49:19 -07:00
|
|
|
setLEDs(CHOICE_GREEN|CHOICE_BLUE);
|
2011-03-24 16:05:35 -06:00
|
|
|
winner_sound();
|
2012-12-28 21:49:19 -07:00
|
|
|
setLEDs(CHOICE_RED|CHOICE_YELLOW);
|
2011-03-24 16:05:35 -06:00
|
|
|
winner_sound();
|
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Plays the current contents of the game moves
|
2012-12-26 14:58:15 -07:00
|
|
|
void play_moves(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
byte currentMove;
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
for (currentMove = 0 ; currentMove < nmoves ; currentMove++)
|
|
|
|
{
|
|
|
|
toner(moves[currentMove], 150);
|
|
|
|
delay(150);
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Adds a new random button to the game sequence, by sampling the timer
|
2012-12-26 14:58:15 -07:00
|
|
|
void add_to_moves(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
byte newButton = random(0, 3);
|
|
|
|
moves[nmoves++] = newButton; //Add this new button to the game array
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Adds a user defined button to the game sequence, by waiting for their input
|
2012-12-26 14:58:15 -07:00
|
|
|
void add_to_moves_battle(void)
|
|
|
|
{
|
|
|
|
uint8_t new_button;
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// wait for user to input next move
|
2012-12-26 14:58:15 -07:00
|
|
|
new_button = wait_for_button();
|
2012-12-26 16:14:22 -07:00
|
|
|
|
2012-12-26 14:58:15 -07:00
|
|
|
toner(new_button, 150);
|
|
|
|
|
|
|
|
moves[nmoves++] = new_button;
|
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Toggle buzzer every buzz_delay_us, for a duration of buzz_length_ms.
|
2012-12-28 21:49:19 -07:00
|
|
|
//Given a length and a
|
2012-12-26 14:58:15 -07:00
|
|
|
void buzz_sound(uint16_t buzz_length_ms, uint16_t buzz_delay_us)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
|
|
|
uint32_t buzz_length_us;
|
|
|
|
|
|
|
|
buzz_length_us = buzz_length_ms * (uint32_t)1000;
|
|
|
|
while (buzz_length_us > buzz_delay_us*2) {
|
|
|
|
buzz_length_us -= buzz_delay_us*2;
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Toggle the buzzer at various speeds
|
2012-12-28 21:49:19 -07:00
|
|
|
//cbi(BUZZER1_PORT, BUZZER1);
|
|
|
|
//sbi(BUZZER2_PORT, BUZZER2);
|
|
|
|
digitalWrite(BUZZER1, LOW);
|
|
|
|
digitalWrite(BUZZER2, HIGH);
|
|
|
|
// delay_us(buzz_delay_us);
|
|
|
|
delayMicroseconds(buzz_delay_us);
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
//sbi(BUZZER1_PORT, BUZZER1);
|
|
|
|
//cbi(BUZZER2_PORT, BUZZER2);
|
|
|
|
digitalWrite(BUZZER1, HIGH);
|
|
|
|
digitalWrite(BUZZER2, LOW);
|
|
|
|
delayMicroseconds(buzz_delay_us);
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-12-26 16:14:22 -07:00
|
|
|
Light an LED and play tone
|
|
|
|
red, upper left: 440Hz - 2.272ms - 1.136ms pulse
|
|
|
|
green, upper right: 880Hz - 1.136ms - 0.568ms pulse
|
|
|
|
blue, lower left: 587.33Hz - 1.702ms - 0.851ms pulse
|
|
|
|
yellow, lower right: 784Hz - 1.276ms - 0.638ms pulse
|
2011-03-24 16:05:35 -06:00
|
|
|
*/
|
2012-12-26 14:58:15 -07:00
|
|
|
void toner(uint8_t which, uint16_t buzz_length_ms)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
setLEDs(which);
|
2011-03-24 16:05:35 -06:00
|
|
|
switch (which) {
|
2012-12-28 21:49:19 -07:00
|
|
|
case CHOICE_RED:
|
|
|
|
// buzz_sound(buzz_length_ms, 1136);
|
|
|
|
tone(BUZZER1, 440, buzz_length_ms);
|
2011-03-24 16:05:35 -06:00
|
|
|
break;
|
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
case CHOICE_GREEN:
|
|
|
|
// buzz_sound(buzz_length_ms, 568);
|
|
|
|
tone(BUZZER1, 880, buzz_length_ms);
|
2011-03-24 16:05:35 -06:00
|
|
|
break;
|
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
case CHOICE_BLUE:
|
|
|
|
// buzz_sound(buzz_length_ms, 851);
|
|
|
|
tone(BUZZER1, 587, buzz_length_ms);
|
2011-03-24 16:05:35 -06:00
|
|
|
break;
|
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
case CHOICE_YELLOW:
|
|
|
|
// buzz_sound(buzz_length_ms, 638);
|
|
|
|
tone(BUZZER1, 784, buzz_length_ms);
|
2011-03-24 16:05:35 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Turn off all LEDs
|
2012-12-28 21:49:19 -07:00
|
|
|
setLEDs(CHOICE_OFF);
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Show an "attract mode" display while waiting for user to press button.
|
2012-12-28 21:49:19 -07:00
|
|
|
void attractMode(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
setLEDs(CHOICE_RED);
|
|
|
|
delay(100);
|
|
|
|
if (checkButton() != CHOICE_NONE) return;
|
|
|
|
|
|
|
|
setLEDs(CHOICE_BLUE);
|
|
|
|
delay(100);
|
|
|
|
if (checkButton() != CHOICE_NONE) return;
|
|
|
|
|
|
|
|
setLEDs(CHOICE_GREEN);
|
|
|
|
delay(100);
|
|
|
|
if (checkButton() != CHOICE_NONE) return;
|
|
|
|
|
|
|
|
setLEDs(CHOICE_YELLOW);
|
|
|
|
delay(100);
|
|
|
|
if (checkButton() != CHOICE_NONE) return;
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Wait for a button to be pressed.
|
|
|
|
// Returns one of led colors (LED_RED, etc.) if successful, 0 if timed out
|
2012-12-26 14:58:15 -07:00
|
|
|
uint8_t wait_for_button(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
uint16_t time_limit = ENTRY_TIME_LIMIT;
|
2011-03-24 16:05:35 -06:00
|
|
|
uint8_t released = 0;
|
|
|
|
uint8_t old_button;
|
|
|
|
|
|
|
|
while (time_limit > 0) {
|
|
|
|
uint8_t button;
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Implement a small bit of debouncing
|
2011-03-24 16:05:35 -06:00
|
|
|
old_button = button;
|
2012-12-28 21:49:19 -07:00
|
|
|
button = checkButton();
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Make sure we've seen the previous button released before accepting new buttons
|
2012-12-28 21:49:19 -07:00
|
|
|
if (button == CHOICE_NONE)
|
2011-03-24 16:05:35 -06:00
|
|
|
released = 1;
|
|
|
|
if (button == old_button && released == 1) {
|
2012-12-26 16:14:22 -07:00
|
|
|
// Make sure just one button is pressed
|
2012-12-28 21:49:19 -07:00
|
|
|
if (button == CHOICE_RED ||
|
|
|
|
button == CHOICE_BLUE ||
|
|
|
|
button == CHOICE_GREEN ||
|
|
|
|
button == CHOICE_YELLOW) {
|
2011-03-24 16:05:35 -06:00
|
|
|
return button;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
delay(1);
|
2011-03-24 16:05:35 -06:00
|
|
|
|
|
|
|
time_limit--;
|
|
|
|
}
|
2012-12-26 16:14:22 -07:00
|
|
|
return 0; //Timed out
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Play the game. Returns 0 if player loses, or 1 if player wins.
|
2012-12-26 14:58:15 -07:00
|
|
|
int game_mode(void)
|
2011-03-24 16:05:35 -06:00
|
|
|
{
|
|
|
|
nmoves = 0;
|
2012-12-26 14:58:15 -07:00
|
|
|
int moves_to_win_var = MOVES_TO_WIN; // If in normal mode, then allow the user to win after a #define varialb up top (default is 13).
|
2012-12-26 16:14:22 -07:00
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
if(gameMode == MODE_BATTLE) moves_to_win_var = 1000; // If in battle mode, allow the users to go up to 1000 moves! Like anyone could possibly do that :)
|
2012-12-26 16:14:22 -07:00
|
|
|
|
|
|
|
while (nmoves < moves_to_win_var)
|
|
|
|
{
|
|
|
|
// Add a button to the current moves, then play them back
|
2012-12-28 21:49:19 -07:00
|
|
|
if(gameMode == MODE_BATTLE)
|
2012-12-26 16:14:22 -07:00
|
|
|
add_to_moves_battle(); // If in battle mode, then listen for user input to choose the next step
|
|
|
|
else
|
|
|
|
add_to_moves();
|
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
if(gameMode == MODE_BATTLE)
|
2012-12-26 16:14:22 -07:00
|
|
|
; // If in battle mode, then don't play back the pattern, it's up the the users to remember it - then add on a move.
|
|
|
|
else
|
|
|
|
play_moves();
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Then require the player to repeat the sequence.
|
2012-12-28 21:49:19 -07:00
|
|
|
for (byte currentMove = 0 ; currentMove < nmoves ; currentMove++) {
|
|
|
|
byte choice = wait_for_button();
|
2011-03-24 16:05:35 -06:00
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// If wait timed out, player loses.
|
2011-03-24 16:05:35 -06:00
|
|
|
if (choice == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
toner(choice, 150);
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// If the choice is incorect, player loses.
|
2012-12-28 21:49:19 -07:00
|
|
|
if (choice != moves[currentMove]) {
|
2011-03-24 16:05:35 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Player was correct, delay before playing moves
|
2012-12-28 21:49:19 -07:00
|
|
|
if(gameMode == MODE_BATTLE)
|
2012-12-26 16:14:22 -07:00
|
|
|
{
|
|
|
|
//reduced wait time, because we want to allow the battle to go very fast!
|
|
|
|
//plus, if you use the delay(1000), then it may miss capturing the users next input.
|
2012-12-28 21:49:19 -07:00
|
|
|
delay(100);
|
2012-12-26 16:14:22 -07:00
|
|
|
}
|
|
|
|
else
|
2012-12-28 21:49:19 -07:00
|
|
|
delay(1000);
|
2011-03-24 16:05:35 -06:00
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
// Player wins!
|
2011-03-24 16:05:35 -06:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-28 21:49:19 -07:00
|
|
|
//These ints are for the begees loop funtion to work
|
|
|
|
int counter = 0; // for cycling through the LEDs during the beegees loop
|
|
|
|
int count = 20; // for keeping rhythm straight in the beegees loop
|
2012-12-26 16:14:22 -07:00
|
|
|
//
|
2012-12-28 21:49:19 -07:00
|
|
|
|
|
|
|
//playBeegees() does nothing but play bad beegees music
|
|
|
|
void playBeegees()
|
2012-12-26 16:14:22 -07:00
|
|
|
{
|
|
|
|
buzz(3);
|
|
|
|
delay(400);
|
|
|
|
buzz(4);
|
|
|
|
rest(1);
|
|
|
|
delay(600);
|
|
|
|
buzz(5);
|
|
|
|
rest(1);
|
|
|
|
rest(1);
|
|
|
|
delay(400);
|
|
|
|
buzz(3);
|
|
|
|
rest(1);
|
|
|
|
rest(1);
|
|
|
|
rest(1);
|
|
|
|
buzz(2);
|
|
|
|
rest(1);
|
|
|
|
buzz(1);
|
|
|
|
buzz(2);
|
|
|
|
buzz(3);
|
|
|
|
rest(1);
|
|
|
|
buzz(1);
|
|
|
|
buzz(2);
|
|
|
|
rest(1);
|
|
|
|
buzz(3);
|
|
|
|
rest(1);
|
|
|
|
rest(1);
|
|
|
|
buzz(1);
|
|
|
|
rest(1);
|
|
|
|
buzz(2);
|
|
|
|
rest(1);
|
|
|
|
buzz(3);
|
|
|
|
rest(1);
|
|
|
|
buzz(4);
|
|
|
|
rest(1);
|
|
|
|
buzz(5);
|
|
|
|
rest(1);
|
|
|
|
delay(700);
|
2012-12-26 14:58:15 -07:00
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
//
|
2012-12-26 14:58:15 -07:00
|
|
|
void buzz(int tone){
|
2012-12-26 16:14:22 -07:00
|
|
|
|
|
|
|
//Declare an integer, "freq", for frequency of the note to be played.
|
2012-12-26 14:58:15 -07:00
|
|
|
int freq;
|
2012-12-26 16:14:22 -07:00
|
|
|
|
|
|
|
//5 different tones to select. Each tone is a different frequency.
|
2012-12-26 14:58:15 -07:00
|
|
|
if(tone == 1){
|
2012-12-26 16:14:22 -07:00
|
|
|
freq = 2000;
|
2012-12-26 14:58:15 -07:00
|
|
|
}
|
|
|
|
if(tone == 2){
|
2012-12-26 16:14:22 -07:00
|
|
|
freq = 1800;
|
2012-12-26 14:58:15 -07:00
|
|
|
}
|
|
|
|
if(tone == 3){
|
2012-12-26 16:14:22 -07:00
|
|
|
freq = 1500;
|
2012-12-26 14:58:15 -07:00
|
|
|
}
|
|
|
|
if(tone == 4){
|
2012-12-26 16:14:22 -07:00
|
|
|
freq = 1350;
|
2012-12-26 14:58:15 -07:00
|
|
|
}
|
|
|
|
if(tone == 5){
|
2012-12-26 16:14:22 -07:00
|
|
|
freq = 1110;
|
2012-12-26 14:58:15 -07:00
|
|
|
}
|
2012-12-26 16:14:22 -07:00
|
|
|
|
2012-12-26 14:58:15 -07:00
|
|
|
//freq = (freq/2);
|
2012-12-26 16:14:22 -07:00
|
|
|
|
|
|
|
// Because frequency is determined by the wavelength (the time HIGH and the time LOW),
|
|
|
|
// you need to have "count" in order to keep a note the same length in time.
|
|
|
|
// "count" is the number of times this function will repeat the HIGH/LOW pattern - to create the sound of the note.
|
|
|
|
|
2012-12-26 14:58:15 -07:00
|
|
|
count = 40;
|
2012-12-26 16:14:22 -07:00
|
|
|
|
|
|
|
// In order to keep all 5 notes the same length in time, you must compare them to the longest note (tonic) - aka the "1" note.
|
2012-12-28 21:49:19 -07:00
|
|
|
count = count * (2000/freq);
|
2012-12-26 16:14:22 -07:00
|
|
|
|
|
|
|
// this next function simply changes the next LED to turn on.
|
2012-12-28 21:49:19 -07:00
|
|
|
changeLED();
|
2012-12-26 16:14:22 -07:00
|
|
|
|
|
|
|
// this next for loop actually makes the buzzer pin move.
|
|
|
|
// it uses the "count" variable to know how many times to play the frequency.
|
|
|
|
// -this keeps the timing correct.
|
2012-12-28 21:49:19 -07:00
|
|
|
for(int i = 0 ; i < count ; i++)
|
|
|
|
{
|
2012-12-26 16:14:22 -07:00
|
|
|
digitalWrite(BUZZER1, HIGH);
|
|
|
|
digitalWrite(BUZZER2, LOW);
|
|
|
|
delayMicroseconds(freq);
|
2012-12-28 21:49:19 -07:00
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
digitalWrite(BUZZER1, LOW);
|
|
|
|
digitalWrite(BUZZER2, HIGH);
|
|
|
|
delayMicroseconds(freq);
|
2012-12-26 14:58:15 -07:00
|
|
|
}
|
|
|
|
delay(60);
|
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
//
|
|
|
|
void rest(int tone){
|
2012-12-26 14:58:15 -07:00
|
|
|
int freq;
|
2012-12-26 16:14:22 -07:00
|
|
|
if(tone == 1){
|
2012-12-26 14:58:15 -07:00
|
|
|
freq = 2000;
|
2012-12-26 16:14:22 -07:00
|
|
|
}
|
|
|
|
if(tone == 2){
|
2012-12-26 14:58:15 -07:00
|
|
|
freq = 1800;
|
2012-12-26 16:14:22 -07:00
|
|
|
}
|
|
|
|
if(tone == 3){
|
2012-12-26 14:58:15 -07:00
|
|
|
freq = 1500;
|
2012-12-26 16:14:22 -07:00
|
|
|
}
|
|
|
|
if(tone == 4){
|
2012-12-26 14:58:15 -07:00
|
|
|
freq = 1350;
|
2012-12-26 16:14:22 -07:00
|
|
|
}
|
|
|
|
if(tone == 5){
|
2012-12-26 14:58:15 -07:00
|
|
|
freq = 1110;
|
2012-12-26 16:14:22 -07:00
|
|
|
}
|
|
|
|
//freq = (freq/2);
|
2012-12-28 21:49:19 -07:00
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
count = 40;
|
2012-12-28 21:49:19 -07:00
|
|
|
count = count * (2000/freq);
|
2012-12-26 16:14:22 -07:00
|
|
|
//change_led();
|
|
|
|
|
|
|
|
for(int i = 0 ; i < count ; i++)
|
|
|
|
{
|
|
|
|
digitalWrite(BUZZER1, LOW);
|
|
|
|
delayMicroseconds(freq);
|
|
|
|
digitalWrite(BUZZER1, LOW);
|
|
|
|
delayMicroseconds(freq);
|
|
|
|
}
|
2012-12-26 14:58:15 -07:00
|
|
|
delay(75);
|
|
|
|
}
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
//
|
2012-12-28 21:49:19 -07:00
|
|
|
void changeLED()
|
2012-12-26 16:14:22 -07:00
|
|
|
{
|
2012-12-28 21:49:19 -07:00
|
|
|
setLEDs(1 << counter);
|
|
|
|
|
2012-12-26 16:14:22 -07:00
|
|
|
counter += 1;
|
2012-12-28 21:49:19 -07:00
|
|
|
if(counter > 3) counter = 0;
|
2012-12-26 14:58:15 -07:00
|
|
|
}
|