eva 发表于 2012-8-21 11:51:17

PIC16F84A MemoSound Game 【转】

http://www.micro-examples.com/pics/092-MEMOSOUND-memosoundcircuit.png/*
* 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 NBFREQ7                     // 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 =
      {
      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) ;
      }

/*
* 10 ms delay
*/
void    delay10ms()
      {
      Delay_ms(10) ;
      }

/*
* 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 ;

      for(i = 0 ; i < NBFREQ ; i++)
                {
                playSound(i, 50, 1, 0) ;
                }
      delay1000ms() ;
      }

/*
* play the welcome melody, all tones in ascending order
*/
void    playWelcome()
      {
      unsigned char i ;

      for(i = NBFREQ ; i > 0 ; i--)
                {
                playSound(i - 1, 50, 1, 0) ;
                }
      }

/*
* 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
                }

      delay10ms() ;                           // waits a little bit

      INTCON.RBIE = 0 ;                     // disable portb interrupt
      INTCON.RBIF = 0 ;                     // clear pending interrupt
      EEPROM_Write(ADDR_NBSTEPS, s) ;         // no, write new step

      delay10ms() ;                           // waits a little bit

      return(1) ;                           // not won yet
      }

/*
* 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, 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, 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
                        }
                }
      }

页: [1]
查看完整版本: PIC16F84A MemoSound Game 【转】