2011년5월27일_ATmega128 내부EEPROM기록 오류 수정, 게임진행화면 이쁘게, 1세트 ~ 10세트까지 점수를 합산(점수기록시 /5, 표시시 *5), dec_to_ascii() 앞에 0없애기, DK-128 적외선 센서불량으로 보드교체

 

   1:  /***************************************************************************
   2:  
   3:      파일명: main.c            
   4:              ATmega128.h        - I/O정의
   5:              
   6:      작성자:    1.출처: 내 머리
   7:              2.작성: [내장형 하드웨어]과정    김수만
   8:              
   9:      목적: 두더지게임
  10:      
  11:      사용방식:
  12:      
  13:      사용파일:    stdlib.h - 랜덤함수 
  14:      
  15:      제한사항:
  16:      
  17:      오류처리:
  18:      
  19:      이력사항:    1.2011년 5월 23일...최초 작성.
  20:                  2.2011년 5월 24일...주석 정리. 
  21:                                      함수의 배치 순서 정리.
  22:                                      문자열 전송함수 개선 - \n만 하면 되도록
  23:                  3.2011년 5월 26일...시작화면, 메뉴, 통신속도최대로 115200bps
  24:                  4.2011년 5월 27일...EEPROM RANK기록 오류 수정. (1위까지 잘 표시)
  25:                                      게임진행화면 이쁘게
  26:                                      1세트~10세트까지 만들고 점수 합산 저장.
  27:                                      (점수기록시 그대로, 표시시 *5)
  28:                                      dec_to_ascii() - 앞에 '0'표시 없애기.
  29:  
  30:  ****************************************************************************/

 

 

EEPROM에 기록할 순위데이터 오류 수정

 

game_over( ) 함수의,

   1:  for(ucLoop = 10 ; 1 < ucLoop ; --ucLoop)        // 10번지부터 1번지까지 교체  (i - 1)
   2:  {
   3:          //EEPROM의 데이터 정렬
   4:  }

예전 소스는 위와 같이 10번지부터 1번지까지만 교체되어 1위인 0번지의 데이터가 정렬되지 않았다.
그래서 조건식에 1 대신 0을 넣어 0번지까지 정렬되도록 하였다.

   1:      //점수를 정렬하며 EEPROM에 기록 1위~10위까지
   2:      eeprom_write(10, ucScoreSum);        //제일 밑에 총점을 넣고
   3:      
   4:      for(ucLoop = 10 ; 0 < 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:      }

그나저나 블록단위 쓰기를 해야 하는데 바이트단위 읽고 수정 쓰기를 하니 수명이 많이 걱정된다.
어려운 것도 아닌데 왜 이렇게 잘 되지 않는가?

 

game_score( ) 함수의,

   1:      //1위 부터 10위까지 출력
   2:      for(ucLoop = 0 ; 10 > ucLoop ; ++ucLoop)
   3:      {
   4:          uart_send_string_suman("\t\t\t");
   5:   
   6:          ucTemp = eeprom_read(ucLoop);
   7:          printf_suman("%d. %d점\n", ucLoop + 1, ucTemp * 5, 0);
   8:      }

순위데이터 출력하는 부분은 참고용으로 올린다.

 

image

그런데 이상하게 수정했는데 전원OFF후 재투입 시 1위 부터 0으로 초기화된다.
이상해! 이상해!

 

 

 

게임진행화면 이쁘게 꾸미기

 

image


   1:  void game_display_LED_SW(unsigned char cNum)
   2:  {
   3:      char aBuf[][18] = {"○○○○ ○○○○",
   4:                          "○○○○ ○○○●",
   5:                          "○○○○ ○○●○",
   6:                          "○○○○ ○●○○",
   7:                          "○○○○ ●○○○",
   8:                          "○○○● ○○○○",
   9:                          "○○●○ ○○○○",
  10:                          "○●○○ ○○○○",
  11:                          "●○○○ ○○○○"};
  12:   
  13:      uart_send_string_suman(aBuf + cNum);
  14:      
  15:      return ;
  16:  }


2차원 배열을 선언하여 화면에 표시할 그림을 저장하였으나, 이 영역은 SRAM이다.
SRAM은 변수가 놓이는 부분인데 여기선 상수를 넣어 조금 아깝다.
그래서 FLASH영역에 선언하는 것을 찾아 보았으나,

#include <avr/pgmspace.h>

pgmspace.h를 인클루드(?)해야 하고 함수를 써서 엑세스하는 것이 조금 복잡해서 관두었다.
아마 FLASH는 SRAM과 다르게 16비트라 조금 복잡한 것 같다. 후에 필요하면 필사적으로 찾을 것이나 지금은 필요없다.
그러니 SRAM영역에 넣고 쓰자.

main( )의 표시하는 부분은,

   1:              //횟수와 점수를 출력.
   2:              ucLED = log_2(ucLED);    
   3:              ucTemp = log_2(gKey);
   4:              printf_suman("%d.\t", ucLoop, 0, 0);              
   5:              game_display_LED_SW(ucLED);            //LED - 0~8까지의 값을 받아 ○○○○○○○●출력
   6:              
   7:              uart_send_string_suman("\n\t");
   8:              
   9:              if(0 != gSensor && 0 < ucBomb)                //센서 감지되고 폭탄갯수가 충분하면,
  10:              {                                        
  11:                  uart_send_string_suman("▲▲▲Boom▲▲▲\a\a");    //뽀개진거 출력.
  12:                  PORT_BELL = 0x00;        //BELL ON
  13:                  sleep(20);                //50ms
  14:                  PORT_BELL = 0xFF;        //BELL OFF
  15:                  sleep(20);                //50ms
  16:                  PORT_BELL = 0x00;        //BELL ON
  17:                  sleep(20);                //50ms
  18:                  PORT_BELL = 0xFF;        //BELL OFF
  19:              }
  20:              else                                        //일반상태
  21:              {
  22:                  game_display_LED_SW(ucTemp);            //KEY - 0~8까지의 값을 받아 ○○○○○○○●출력                
  23:              }

 

 

 

점수 합산


   1:          //점수 출력.
   2:          printf_suman("\t\t\t점수: %d점\n", ucScore * 5, 0, 0);
   3:          sleep(2000);        //2초 대기.
   4:   
   5:          ucScoreSum = ucScoreSum + ucScore;        //점수 합산
   6:          ucLED = 0xFF;        //점수 출력 전 초기화
   7:   
   8:          if(100 == (ucScore * 5))            //만약 모두 맞추었다면
   9:          { }

2행에 printf_suman( ) 함수의 인자로 문자열과 점수의 5배한 값을 넘겨주고 있다. (0은 더미값)
5행에 점수를 합하여 저장한다.
그 다음 게임 종료 시 점수합을 출력하기 위해 game_over( ) 함수의 인자로 넘겨준다.


   1:              if(8 > ucScore)
   2:              {
   3:                  game_over(ucScoreSum);        // GAME OVER메세지와 EEPROM에 총점 기록.
   4:   
   5:   
   6:                  break;                // 메뉴로
   7:              }

점수가 8보다 작을 때니 실제 점수가 40점미만일 때 종료하면서 점수의 합을 넘겨준다.

 


 

 

 

dec_to_ascii( ) – 출력되는 숫자 앞에 ‘0’없애기


   1:  //정수를 문자로 바꾸는 함수. (0~255까지만 취급함.)
   2:  void dec_to_ascii(unsigned char cNum, char *p)
   3:  {
   4:      unsigned char ucLoop = 3;
   5:   
   6:      *(p + ucLoop) = '\0';                    //문자열끝.
   7:      
   8:      for(; 0 < ucLoop ; --ucLoop)
   9:      {
  10:          *(p + ucLoop - 1) = (cNum % 10) + '0';     //일자리부터 백자리까지 저장 후 문자로 변환.
  11:          cNum = cNum / 10;                            //일자리부터 10단위로 잘라냄.
  12:      }
  13:      
  14:      //숫자 앞에 0을 없애는 부분.
  15:      for(ucLoop = 0 ; 2 > ucLoop ; ++ucLoop)
  16:      {
  17:          if('0' == *(p + ucLoop))                    //현재 자리가 '0'이면,
  18:          {
  19:              if(0 == ucLoop)                                    //첫 번째 자리에는,
  20:              {
  21:                  *(p + ucLoop) = ' ';                        //공백문자로 만들어 버림.
  22:              }
  23:              else if((0 != ucLoop) && (2 != ucLoop) && (' ' == *(p + ucLoop - 1)))        
  24:              {                                                //첫 번째와 마지막자리를 제외한 자리에는,
  25:                  *(p + ucLoop) = ' ';                        //공백문자로 만들어 버림.
  26:              }
  27:              else                                            //마지막자리는,
  28:              {
  29:                  *(p + ucLoop) = '0';                        //'0'으로 만들어 버림.
  30:              }
  31:          }
  32:      }
  33:   
  34:      return ;
  35:  }


숫자 앞에 ‘0’을 없애는 부분이 복잡한 이유는 비밀입니다. 하하하