2011년5월26일_두더지게임(시작화면, 메뉴, ATmega128 내부EEPROM에 순위데이터저장)

 

오늘 어제 기획한 내용들에 대해 프로그래밍하여 보았다.
몇 가지 부족한 점이 있으니 개선해 나아 가야겠다.

 

 

통신속도수정

 

   1:  //통신관련
   2:  #define CPU_CLOCK        16000000
   3:  #define BAUD_RATE        115200            // 통신시 이용할 속도
   4:  #define BAUD_RATE_L        (CPU_CLOCK / (8l * BAUD_RATE)) - 1
   5:  #define BAUD_RATE_H        ((CPU_CLOCK / (8l * BAUD_RATE)) - 1) >> 8
   6:  /*    통신속도의 결과 값을 입력하기 위해 상하위 비트로 구분
   7:      16l은 16 + L이며, 연산 시 값이 너무 커져 overflow가 발생하므로 32비트 연산을
   8:      위해 16에 Long을 의미하는 l을 붙인다.*/

보레이트를 4800에서 115200으로 올리고,
보레이트 계산식에서 2배속을 하기 위해 16을 8로 낮춤.

   1:  //UART1 초기화
   2:  void init_USART1(void)
   3:  {
   4:      //baud rate설정
   5:      UBRR1L = (unsigned char)BAUD_RATE_L;    
   6:      UBRR1H = (unsigned char)BAUD_RATE_H;
   7:      
   8:      // no parity, 1stop bit, 8bit data설정
   9:      UCSR1C = (0 << UPM1) | (0 << UPM0) | (0 << USBS) | (1 << UCSZ1) | (1 << UCSZ0);
  10:      // rx/tx interrupt설정, 8bit설정
  11:      UCSR1B = (1 << TXEN) | (1 << RXEN) | (0 << UCSZ2);
  12:      // x2 speed
  13:      UCSR1A = (1 << U2X);
  14:   
  15:      return ;
  16:  }

2배속을 해야 하니 UCSR1A레지스터의 1번비트를 1로 세트함.

UCSR1A = (1 << U2X);

 

시작화면과 메뉴

 

image

귀여운 두더지가 나왔다 들어갔다 하는 모습을 표현하기 위해 화면을 뿌리고 지우고 반복하는데,
아래에 보면 통신속도가 115200bps로 4800bps보다 24배나 빠르다.
그래서 인간이 화면을 보면 문자 하나씩 뿌려지는 것을 느낄 수 없다.
소스코드는 아래와 같이 3차원 배열을 선언하여 각 씬마다 두더지 위치가 다르게 하였다.


   1:  char aMole[][][50]={    "  と─つ                                      \n",
   2:                          "  │⊙⊙│     と─つ      と─つ      と─つ  \n",
   3:                          "─┴──┴──┴──┴──┴──┴──┴──┴─\n"},
   4:   
   5:                     {    "               と─つ                          \n",
   6:                          "   と─つ     │⊙⊙│     と─つ      と─つ  \n",
   7:                          "─┴──┴──┴──┴──┴──┴──┴──┴─\n"},
   8:   
   9:                     {    "                           と─つ             \n",
  10:                          "   と─つ      と─つ     │⊙⊙│     と─つ  \n",
  11:                          "─┴──┴──┴──┴──┴──┴──┴──┴─\n"},
  12:   
  13:                     {    "                                       と─つ \n",
  14:                          "   と─つ      と─つ      と─つ     │⊙⊙│ \n",
  15:                          "─┴──┴──┴──┴──┴──┴──┴──┴─\n"}};
  16:   
  17:  //랜덤값 발생
  18:  ucTemp = rand() % 4;
  19:   
  20:  //화면에 표시
  21:  for(ucLoop = 0 ; 3 > ucLoop ; ++ucLoop)
  22:  {
  23:      uart_send_string_suman("\t\t");
  24:      uart_send_string_suman((char*)(aMole[ucTemp] + ucLoop));
  25:  }                                                                        

배열aMole[4][3][50]인데 소스에는 aMole[][][50]이라고 되어 있다. 잘 못 되었음.
그리고 두더지 모양이 조금 이상한데 출력하면 잘 나옵니다 >_<

aMole[ucTemp] + ucLoop에서…
ucTemp는 두더지 위치이고,
ucLoop는 두더지 머리, 눈알, 몸통 세 부분을 각각 나타내는 문자열..즉, 행이다.
다음 aMole자체 주소는 그 행의 시작주소이니 50이라는 크기의 문자열이 되겠다.

 

 

내부EEPROM에 저장된 순위 데이터 출력

 

image

1등이 처리되지 않아 0점으로 나왔다. 이 부분을 수정해야함.

   1:          //점수를 정렬하며 EEPROM에 기록
   2:          eeprom_write(10, ucScore);        //제일 밑에  현재 점수를 넣고
   3:          
   4:          for(ucLoop = 10 ; 1 < ucLoop ; --ucLoop)
   5:          {
   6:              if(eeprom_read(ucLoop) > eeprom_read(ucLoop - 1))        //바로 위에 수치와 비교하여,
   7:              {
   8:                  ucTemp = eeprom_read(ucLoop - 1);                    //교체
   9:                  eeprom_write(ucLoop - 1, eeprom_read(ucLoop));
  10:                  eeprom_write(ucLoop, ucTemp);
  11:              }
  12:          }

반복횟수를 9회가 아닌 10회로 해야겠음.
화면에 출력하는 함수는 아래와 같음.


   1:  /******************************************************************************
   2:  
   3:                  순위 출력 및 초기화
   4:  
   5:  *******************************************************************************/
   6:  void game_rank(void)
   7:  {
   8:      unsigned char ucLoop;
   9:      
  10:      game_score();
  11:      
  12:      uart_send_string_suman("\n\n");
  13:      uart_send_string_suman("\t순위를 초기화하려면 적외선 센서를 막으세요.\n");
  14:      uart_send_string_suman("\t나가시려면 아무 키나 눌러주세요.");
  15:      
  16:      sleep(1000);        //1초 대기
  17:      
  18:      gKey = 0;        //키 값 초기화
  19:   
  20:      while(1)
  21:      {
  22:          if(0 == (0x80 & PIN_SENSOR))        //적외선 센서가 감지되면,
  23:          {
  24:              for(ucLoop = 0 ; 10 > ucLoop ; ++ucLoop)
  25:              {
  26:                  eeprom_write(ucLoop, 0);    //EEPROM 데이터 초기화 (0~10까지)
  27:              }
  28:              
  29:              game_score();                    //점수 출력.
  30:              
  31:              break;
  32:          }
  33:          
  34:          if(0 != gKey)                        //아무 키나 누르면 탈출.
  35:          {
  36:              break;
  37:          }
  38:      }
  39:      
  40:      sleep(1000);
  41:   
  42:      return ;
  43:  }

 

 

게임옵션

 

image

EASY모드는 1000ms켜지고 1000ms동안 꺼짐.
NORMAL모드는 750ms켜지고 750ms동안 꺼짐.
HARD모드는 500ms켜지고 500ms동안 꺼짐.

 

   1:  /******************************************************************************
   2:  
   3:                  게임 옵션 설정
   4:  
   5:  *******************************************************************************/
   6:  unsigned int game_option(void)
   7:  {
   8:      unsigned int uiDiff = 1000;
   9:      unsigned char ucBreak = 0;
  10:   
  11:      uart_send_byte(0x0C);        //다음 페이지
  12:      
  13:      uart_send_string_suman("\n\n\n\n");
  14:      uart_send_string_suman("\t\t\t1. EASY\n");
  15:      uart_send_string_suman("\t\t\t2. NORMAL\n");
  16:      uart_send_string_suman("\t\t\t3. HARD\n");
  17:      uart_send_string_suman("\t\t\t4. EXIT\n");
  18:      
  19:      
  20:      sleep(1000);        //1초 대기
  21:      
  22:      while(0 == ucBreak)
  23:      {
  24:          gKey = 0;        //key값 초기화
  25:          sleep(100);        //키입력 받을 시간.
  26:          
  27:          switch(gKey)
  28:          {
  29:              //1번
  30:              case 0x01:
  31:                  uiDiff = 1000;        //1초
  32:                  uart_send_string_suman("\rEASY MODE!  ");
  33:                  break;
  34:              
  35:              //2번
  36:              case 0x02:
  37:                  uiDiff = 750;        //0.75초
  38:                  uart_send_string_suman("\rNORMAL MODE!");
  39:                  break;
  40:          
  41:              //3번
  42:              case 0x04:
  43:                  uiDiff = 500;        //0.5초
  44:                  uart_send_string_suman("\rHARD MODE!  ");
  45:                  break;
  46:                  
  47:              //4번
  48:              case 0x08:
  49:                  ucBreak = 1;        //탈출값.
  50:                  break;
  51:          
  52:              default:
  53:                  break;
  54:          }
  55:      }
  56:      
  57:      sleep(1000);
  58:      
  59:      return uiDiff;        //난이도 값 반환
  60:  }

 

 

 

게임진행화면

 

image

 

   1:  /******************************************************************************
   2:  
   3:                  두더지 게임 시작!
   4:  
   5:  *******************************************************************************/
   6:  void game_start(unsigned int uiDiff)
   7:  {
   8:      unsigned char ucLED = 0;        //LED
   9:      unsigned char ucScore = 0;        //점수
  10:      unsigned char ucLoop = 0;        //루프제어변수
  11:      unsigned char ucTemp = 0;        //임시 중간계산결과저장?
  12:   
  13:      /* srand()에 seed값을 시작할 때마다 다르게 넣어주기 위해
  14:         PC에선 내부RTC의 시간을 이용하나 AVR은 RTC가 없기 때문에
  15:         언제 누를지 알 수 없는 KEY와 항상 변화하고 있는 TCNT0의 값을 
  16:         이용한다. */
  17:      srand(TCNT0);                    //시드값을 넣어줌.
  18:      sleep(100);                        //100ms대기
  19:      
  20:      while(1)    //무한루프
  21:      {
  22:          uart_send_byte(0x0C);        //다음 페이지
  23:          uart_send_string_suman("게임 시작...\n");
  24:   
  25:          //5에서 0까지 카운트 다운! (두더지1-2)
  26:          for(ucLoop = 5 ; 0 < ucLoop ; --ucLoop)
  27:          {
  28:              uart_send_byte(ucLoop + '0');    //54321 (카운트다운)        
  29:                                              //숫자를 문자로 바꾸어 전송.
  30:              PORT_FND = ucLoop | 0xF0;        //5초 부터 1초까지
  31:                                              //10단위자리는 blank
  32:              sleep(200);                    //카운트다운하며 대기.
  33:          }    
  34:          
  35:          PORT_FND = 0x00;                //FND초기화
  36:          uart_send_string_suman("\n\n");
  37:      
  38:          for(ucLoop = 1 ; 20 >= ucLoop ; ++ucLoop)
  39:          {
  40:              gKey = 0;                 //키값 리셋                
  41:              //1 ~ 7까지 난수를 발생하여 그 수 만큼 좌로 시프트
  42:              ucLED = 1 << (rand() % 8);        
  43:              PORT_LED = ~ucLED;        //반전하여 출력        
  44:              sleep(uiDiff);            //1000ms 대기
  45:   
  46:              //횟수와 점수를 출력.
  47:              ucLED = log_2(ucLED);    
  48:              ucTemp = log_2(gKey);
  49:              printf_suman("%d. LED[%d]_Input Value[%d]", ucLoop, ucLED, ucTemp);  
  50:   
  51:              //두더지가 맞았으면 
  52:              if(ucLED == ucTemp)            //두더지를 맞추었으니
  53:              {
  54:                  ucScore = ucScore + 5;    //5점증가
  55:                  uart_send_string_suman("...OK!\n");
  56:              }
  57:              else
  58:              {
  59:                  uart_send_string_suman("...Fail!!\n");
  60:              }
  61:              
  62:              //100점은 제외. 16진수변환 함수가 3자리를 처리 못 함.
  63:              if(100 != ucScore)
  64:              {
  65:                  PORT_FND = hex_to_dec(ucScore);        //FND에 점수표시
  66:              }
  67:   
  68:              PORT_LED = 0xFF;    //LED모두 OFF
  69:              sleep(uiDiff);        //500ms 대기
  70:          }
  71:          
  72:          //점수 출력.
  73:          printf_suman("\t\t\t총 점수: %d점\n", ucScore, 0, 0);
  74:   
  75:   
  76:          //점수를 정렬하며 EEPROM에 기록
  77:          eeprom_write(10, ucScore);        //제일 밑에  현재 점수를 넣고
  78:          
  79:          for(ucLoop = 10 ; 1 < ucLoop ; --ucLoop)
  80:          {
  81:              if(eeprom_read(ucLoop) > eeprom_read(ucLoop - 1))        //바로 위에 수치와 비교하여,
  82:              {
  83:                  ucTemp = eeprom_read(ucLoop - 1);                    //교체
  84:                  eeprom_write(ucLoop - 1, eeprom_read(ucLoop));
  85:                  eeprom_write(ucLoop, ucTemp);
  86:              }
  87:          }
  88:   
  89:          ucLED = 0xFF;        //점수 출력 전 초기화
  90:   
  91:   
  92:          if(100 == ucScore)            //만약 모두 맞추었다면
  93:          {
  94:              PORT_FND = 0x00;    // "00"표시
  95:              uart_send_string_suman("100점이네요. ㅊㅋㅊㅋ\n\n");
  96:   
  97:              for(ucLoop = 0; 5 > ucLoop ; ++ucLoop)    //LED깜빡깜빡
  98:              {
  99:                  PORT_LED = ucLED;    // 모두 OFF
 100:                  sleep(500);
 101:                  ToggleNumber(&ucLED);
 102:                  PORT_LED = 0xFF;    // 모두 ON
 103:                  sleep(500);
 104:              }
 105:          }
 106:          else                    //100점이 아니면 현재 점수 보여줌.
 107:          {
 108:              PORT_LED = ucLED;        // LED 모두 OFF
 109:              sleep(300);                // 300ms 딜레이
 110:              
 111:              if(40 > ucScore)
 112:              {
 113:                  game_over();        // GAME OVER메세지
 114:                  break;                // 메뉴로
 115:              }
 116:          }    
 117:   
 118:          ucScore = 0;                    // 점수 초기화
 119:          gKey = 0;                    // 키값 리셋
 120:      }
 121:  }

 

 

진행 동영상

 

시작화면이 귀엽지 아니한가?
귀엽다!
귀엽다!
귀엽다!