标题: PIC16F84A MemoSound Game 【转】 [打印本页] 作者: eva 时间: 2012-8-21 11:51 标题: PIC16F84A MemoSound Game 【转】 /*
* Project : memosound
* Author : Bruno Gavand
* Date : August, 2006
* Description : Sound & Light memorization game
*
* Target : PIC16F84A @ 8 MHz
* Flags : HS oscillator, no watchdog, no power up timer
*
* IDE : mikroC V6.0
*
* the player has to memorize and play back a melody :
* the PIC creates a new melody for each new game
* a melody is up to 63 steps
* each step is a tone corresponding to a color
* there are 4 tones (A, B, C, D) and then 4 LEDs (red, green , orange, yellow)
*
* start-up : the PIC plays a welcome melody and secretly creates the new melody
* the PIC plays the first step of the melody, and the player have to play it back
* if it is the good one, the PIC plays the melody from the beginnig with one more step
* the player have to repeat the same melody
* if the player fails, an error melody is played and the PIC plays the same melody again
* when all 63 steps of the melody are correctly played back by the player,
* the PIC plays a win melody and creates a new one.
* at any time, the player can press two buttons at a time to give up with the current melody
* and start with a new one.
*
* RA0...RA3 : LEDs
* RB0 : Piezzo buzzer
* RB4...RB7 : Buttons
*
* see more details on *
*/
/*
* macro definitions
*/
#define NBFREQ 7 // size of frequency table
#define NBCYCLES(freq) (2000/f) // duration of a sound
#define EEPROM_SIZE 64 // size of P16F84A EEPROM : steps are stored in EEPROM
#define NBSTEPS (EEPROM_SIZE - 2) // maximum number of steps
#define ADDR_NBSTEPS (EEPROM_SIZE - 2) // address in EEPROM of the step counter
#define ADDR_SPEED (EEPROM_SIZE - 1) // address in EEPROM of the game speed
/*
* frequency table : periods in thousands of ms
*/
const unsigned char t_period[NBFREQ] =
{
132,
148,
165,
176,
198,
220,
247
} ;
unsigned char speed ; // game speed
/*
* delays are made as function instead of macro
* to save ROM space
*
* 1 second delay
*/
void delay1000ms()
{
Delay_ms(1000) ;
}
/*
* play one sound with LED
*
* s : index of the sound in frequency table
* d : duration of the sound in numbers of periods
* t : duration of silence after the sound (to be multiplied by 10 ms)
*/
void playSound(unsigned char s, unsigned char d, unsigned char n, unsigned char t)
{
unsigned char c ;
c = t_period ;
PORTA = 1 << (s & 3) ; // light LED corresponding to the sound index
while(n--)
{
while(d--)
{
unsigned char cc ;
PORTB.F0 ^= 1 ;
for(cc = 0 ; cc < c ; cc++) Delay_us(1) ;
}
}
PORTA = 0 ; // turn LED off
PORTB.F0 = 0 ; // turn loudspeaker off
while(t--) delay10ms() ; // do the silence if needed
}
/*
* play the error melody, all tones in descending order
*/
void playError()
{
unsigned char i ;
/*
* fill EEPROM with a new melody
*/
void fillEEPROM()
{
unsigned char i ;
for(i = 0 ; i < NBSTEPS ; i++) // for all melody steps
{
EEPROM_Write(i, rand() % 4) ; // writes a random index from 0 to 3 in EEPROM location
}
EEPROM_Write(ADDR_NBSTEPS, 0) ; // reset the current step number
}
/*
* increment melody step number
*
* return 0 if the player won
* return 1 otherwise
*/
unsigned char nextStep()
{
unsigned char s ;
s = EEPROM_Read(ADDR_NBSTEPS) ; // read current step number from EEPROM
s++ ; // next one
if(s == NBSTEPS) // is it the maximum step number ?
{
return(0) ; // yes, player has won
}
/*
* play a step
*
* a : index in EEPROM of the step to play
*/
void playEEPROM(unsigned char a)
{
unsigned char n ;
n = EEPROM_Read(a) ; // read frequency index from EEPROM
playSound(n, t_period[NBFREQ - 1 - n], speed, 10) ; // play corresponding sound
}
/*
* most important routine,
* verify if player's entry matches melody stored in EEPROM
*/
unsigned char verifEEPROM()
{
unsigned char i, s, v, b ;
s = EEPROM_Read(ADDR_NBSTEPS) ; // read current player's level
for(i = 0 ; i < s ; i++) // for each level
{
INTCON.RBIF = 0 ; // clear PORTB on change interrupt flag
INTCON.RBIE = 1 ; // enables PORTB on change interrupt
INTCON.GIE = 0 ; // do not call interrupt routine at wake up
asm { sleep } ; // go to sleep mode, and low power consomption
/*
* when user press at least one key, the PIC wakes up
* and continues in sequence here
*/
v = EEPROM_Read(i) ; // get next tone of the melody
while((PORTB & 0xf0) != 0xf0) // while a key is still pressed
{
b = PORTB & 0xf0 ; // get keys status
if(b == 0b01110000) b = 0 ; // decode keys, and get tone number
else if(b == 0b10110000) b = 1 ;
else if(b == 0b11010000) b = 2 ;
else if(b == 0b11100000) b = 3 ;
else if(b == 0b11000000) // is speed mode selected ?
{
delay1000ms() ; // debounce with delay
for(;;) // enter forever selection loop
{
for(b = 0 ; b < 4 ; b++) // for all LEDS
{
PORTA = 1 << (b & 3) ; // light LED
for(s = 0 ; s < 200 ; s++) // for a little while
{
if((PORTB & 0xf0) != 0xf0) // if a key is pressed
{
PORTA = 0 ; // clear LEDs
speed = b + 1 ; // compute speed
EEPROM_Write(ADDR_SPEED, speed) ; // store speed in EEPROM
delay1000ms() ; // wait a little bit
return(0) ; // resume melody
}
delay10ms() ;
}
}
}
}
else if(b == 0b00110000) // is melody reset selected ?
{
PORTA = 0xf ; // understood, light all LEDs
delay1000ms() ; // wait one second
PORTA = 0 ; // clear all LEDs
return(2) ; // code 2 to prevent error melody to be played
}
playSound(b, t_period[NBFREQ - 1 - b], 1, 0) ; // play the sound corresponding to the key pressed by the player
}
delay10ms() ; // debounce keys
rand() ; // usefull to get more unpredictable melodies
if(b != v) // did the player gave the wrong tone ?
{
playError() ; // yes, play error melody
return(0) ; // code 2 for player's memory failure about this tone
}
}
return(1) ; // code 1 for correct player's memory for this tone
}
/*
* play all melody according to player's level
*/
void playMusic()
{
unsigned char i, s ;
s = EEPROM_Read(ADDR_NBSTEPS) ; // get player's level
for(i = 0 ; i < s ; i++) // for each level
{
playEEPROM(i) ; // play the tone of the melody
}
}
/*
* program entry
*/
void main()
{
unsigned char r ;
TRISA = 0 ; // PORTA is output
PORTA = 0 ; // clear output
TRISB = 0xf0 ; // high nibble is input for keys, low nibble is output
PORTB = 0 ; // clear output
OPTION_REG &= 0b01111111 ; // weak pull-up on PORTB
speed = EEPROM_Read(ADDR_SPEED) ; // get game speed
PlayWelcome() ; // play welcome melody
delay1000ms() ; // 1 second delay before game start
for(;;) // forerver
{
fillEEPROM() ; // fill EEPROM with new melody
while(nextStep()) // next step in melody
{
do
{
playMusic() ; // play melody to current step
}
while((r = verifEEPROM()) == 0) ; // until player repeat it correctly
if(r == 2) // player asked for new melody
{
break ;
}
delay1000ms() ; // 1 second delay before next step
}
if(r == 1) // player repeated all steps correctly
{
PlayWelcome() ; // play win melody
PlayWelcome() ;
PlayWelcome() ;
PlayWelcome() ;
delay1000ms() ; // 1 second delay befor new game
}
}
}