2011년5월30일_두더지잡기게임 프로젝트 보고서

 

PDF파일 다운로드

 

미리보기

 

 

 

동영상

 

 

 

 

 

 

소스코드

 

   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:  ****************************************************************************/
  31:  #include "./../../ATmega128.h"
  32:  #include <stdlib.h>
  33:  #include <avr/pgmspace.h>
  34:   
  35:  //포트 정의
  36:  #define DDR_LED        DDRF
  37:  #define PORT_LED        PORTF
  38:  #define DDR_FND        DDRE
  39:  #define PORT_FND        PORTE
  40:  #define DDR_KEY        DDRC
  41:  #define PIN_KEY        PINC
  42:  #define PORT_KEY        PORTC
  43:  #define DDR_SENSOR    DDRD
  44:  #define PIN_SENSOR    PIND
  45:  #define DDR_BELL    DDRB
  46:  #define PORT_BELL    PORTB
  47:   
  48:  //통신관련
  49:  #define CPU_CLOCK        16000000
  50:  #define BAUD_RATE        115200            // 통신시 이용할 속도
  51:  #define BAUD_RATE_L        (CPU_CLOCK / (8l * BAUD_RATE)) - 1
  52:  #define BAUD_RATE_H        ((CPU_CLOCK / (8l * BAUD_RATE)) - 1) >> 8
  53:  /*    통신속도의 결과 값을 입력하기 위해 상하위 비트로 구분
  54:      16l은 16 + L이며, 연산 시 값이 너무 커져 overflow가 발생하므로 32비트 연산을
  55:      위해 16에 Long을 의미하는 l을 붙인다.*/
  56:   
  57:  //타이머관련
  58:  #define TICKS_PER_SEC    1000            // Ticks per sec = 1,000
  59:  #define    PRESCALER        64                // Prescaler = 64
  60:   
  61:   
  62:  //ISR선언
  63:  void __vector_15 (void) __attribute__ ((signal, used, externally_visible));     
  64:  void init_port(void);
  65:  void init_TC0(void);
  66:  void init_USART1(void);
  67:  void sleep(unsigned int);
  68:  void uart_send_byte(unsigned char);
  69:  void uart_send_string(unsigned char *, unsigned int);
  70:  void uart_send_string_suman(char *);
  71:  unsigned char USART_Receive(void);
  72:  unsigned char eeprom_read(unsigned int uiAddress);
  73:  void eeprom_write(unsigned int uiAddress, unsigned char ucData);
  74:  unsigned char hex_to_dec(unsigned char);
  75:  void printf_suman(char *, unsigned char, unsigned char, unsigned char);
  76:  void dec_to_ascii(unsigned char, char *);
  77:  char log_2(unsigned char);
  78:  void ToggleNumber(unsigned char *);
  79:  //game메뉴
  80:  void game_start(unsigned int);
  81:  unsigned int game_option(void);
  82:  void game_rank(void);
  83:  void game_score(void);
  84:  void game_exit(void);
  85:  void game_over(unsigned char);
  86:  void game_display_LED_SW(unsigned char);
  87:   
  88:   
  89:  /*------------------------------ 전역 변수 ---------------------------------- */
  90:  volatile unsigned int g_elapsed_time = 0;        // 시간 변수
  91:  volatile unsigned char gKey = 0;                // 키입력값 저장 버퍼
  92:  volatile unsigned char gSensor = 0;                // 적외선 센서
  93:  /*------------------------------ 전역 변수 ---------------------------------- */
  94:   
  95:   
  96:   
  97:  /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 프로그램 시작 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  98:  int main(void)
  99:  {
 100:      unsigned int uiDiff = 1000;        //난이도 (1000 = EASY, 750 = NORMAL, 500 = HARD)
 101:      unsigned char ucTemp = 0;        //임시 저장공간
 102:      unsigned char ucLoop = 0;        //루프 제어변수
 103:      const char aMole[4][3][50] = {{"   と─つ                                      \n",
 104:                                      "  │⊙⊙│     と─つ      と─つ      と─つ  \n",
 105:                                      "─┴──┴──┴──┴──┴──┴──┴──┴─\n"},
 106:   
 107:                                  {    "               と─つ                          \n",
 108:                                      "   と─つ     │⊙⊙│     と─つ      と─つ  \n",
 109:                                      "─┴──┴──┴──┴──┴──┴──┴──┴─\n"},
 110:          
 111:                                  {    "                           と─つ             \n",
 112:                                      "   と─つ      と─つ     │⊙⊙│     と─つ  \n",
 113:                                      "─┴──┴──┴──┴──┴──┴──┴──┴─\n"},
 114:   
 115:                                  {    "                                       と─つ \n",
 116:                                      "   と─つ      と─つ      と─つ     │⊙⊙│ \n",
 117:                                      "─┴──┴──┴──┴──┴──┴──┴──┴─\n"}};
 118:   
 119:      
 120:      init_port();        // LED, FND, KEY에 해당하는 포트만 초기화
 121:      init_USART1();        // UART1 초기화
 122:      init_TC0();            // 타이머/카운터0 초기화
 123:      sei();                // 인터럽트 활성화
 124:   
 125:   
 126:      while(1)
 127:      {
 128:          uart_send_string_suman("\n\n");
 129:          uart_send_string_suman("\t\t\tMole-catching game\n\n\n");
 130:   
 131:   
 132:          ucTemp = rand() % 4;
 133:   
 134:          for(ucLoop = 0 ; 3 > ucLoop ; ++ucLoop)
 135:          {
 136:              uart_send_string_suman("\t\t");
 137:              uart_send_string_suman((char*)(aMole[ucTemp] + ucLoop));
 138:          }
 139:   
 140:          uart_send_string_suman("\n\n\n\n\n");
 141:   
 142:          uart_send_string_suman("\t\t\t\t");
 143:          uart_send_string_suman("1. START\n");
 144:          uart_send_string_suman("\t\t\t\t");
 145:          uart_send_string_suman("2. OPTION\n");
 146:          uart_send_string_suman("\t\t\t\t");
 147:          uart_send_string_suman("3. RANK\n");
 148:          uart_send_string_suman("\t\t\t\t");
 149:          uart_send_string_suman("4. EXIT\n");
 150:          
 151:          gKey = 0;        //키값 초기화
 152:          sleep(500);
 153:          //메뉴선택버튼을 눌렀을 때.
 154:          switch(gKey)
 155:          {
 156:              //1번 스위치 누름.
 157:              case 0x01:
 158:                  game_start(uiDiff);            //난이도를 넣고 시작.
 159:                  break;
 160:              
 161:              //2번 스위치 누름.
 162:              case 0x02:
 163:                  uiDiff = game_option();        //난이도를 선택하여 받아오는 함수 호출.
 164:                  break;
 165:                  
 166:              //3번 스위치 누름.
 167:              case 0x04:
 168:                  game_rank();                //순위출력
 169:                  break;
 170:                  
 171:              //4번 스위치 누름.
 172:              case 0x08:
 173:                  game_exit();                //종료.
 174:                  break;
 175:              
 176:              default:
 177:                  break;
 178:          }
 179:          
 180:          
 181:          uart_send_byte(0x0C);        //다음 페이지
 182:      }
 183:   
 184:      return 1;    //종료
 185:  }
 186:   
 187:  /*****************************************************************************
 188:                  
 189:                  타이머/카운터0 비교매치 인터럽트 서비스 루틴
 190:                  
 191:  *****************************************************************************/
 192:  void __vector_15(void)
 193:  {
 194:      ++g_elapsed_time;                                // 시간변수 1증가
 195:      gKey = gKey | ~PIN_KEY;                            // 키입력값을 반전하여 저장. 
 196:      gSensor = gSensor | ((~PIN_SENSOR) & 0x80);    // 센서신호를 저장.
 197:  }
 198:   
 199:  //ms단위 시간지연함수 (전역변수 사용.)
 200:  void sleep(unsigned int elapsed_time)
 201:  {
 202:      g_elapsed_time = 0;                            // 시간 변수 초기화
 203:      while(elapsed_time > g_elapsed_time);        // 참이 될 때까지 대기.
 204:      
 205:      return ;
 206:  }
 207:   
 208:   
 209:  /******************************************************************************
 210:  
 211:                  두더지 게임 시작!
 212:  
 213:  *******************************************************************************/
 214:  void game_start(unsigned int uiDiff)
 215:  {
 216:      unsigned char ucLED = 0;        //LED
 217:      unsigned char ucScore = 0;        //점수
 218:      unsigned char ucScoreSum = 0;    //점수합
 219:      unsigned char ucLoop = 0;        //루프제어변수
 220:      unsigned char ucTemp = 0;        //임시 중간계산결과저장?
 221:      unsigned char ucGameLv = 0;        //단계
 222:      unsigned char ucBomb = 3;        //폭탄. 처음에는 3개로 시작.
 223:   
 224:      /* srand()에 seed값을 시작할 때마다 다르게 넣어주기 위해
 225:         PC에선 내부RTC의 시간을 이용하나 AVR은 RTC가 없기 때문에
 226:         언제 누를지 알 수 없는 KEY와 항상 변화하고 있는 TCNT0의 값을 
 227:         이용한다. */
 228:      srand(TCNT0);                    //시드값을 넣어줌.
 229:      sleep(100);                        //100ms대기
 230:      
 231:      while(1)    //무한루프
 232:      {
 233:          ++ucGameLv;
 234:          if(10 < ucGameLv)
 235:          {
 236:              game_over(ucScoreSum);            //게임 끝 메세지와 함께 기록.
 237:              break;
 238:          }
 239:          
 240:          uart_send_byte(0x0C);        //다음 페이지
 241:          printf_suman("%d세트 시작...폭탄 갯수는 %d개 남았습니다.", ucGameLv, ucBomb, 0);
 242:          
 243:          //5에서 0까지 카운트 다운! (두더지1-2)
 244:          for(ucLoop = 5 ; 0 < ucLoop ; --ucLoop)
 245:          {
 246:              uart_send_byte(ucLoop + '0');    //54321 (카운트다운)        
 247:                                              //숫자를 문자로 바꾸어 전송.
 248:              PORT_FND = ucLoop | 0xF0;        //5초 부터 1초까지
 249:                                              //10단위자리는 blank
 250:              sleep(200);                    //카운트다운하며 대기.
 251:          }    
 252:          
 253:          PORT_FND = 0x00;                //FND초기화
 254:          uart_send_string_suman("\n\n");
 255:      
 256:          for(ucLoop = 1 ; 20 >= ucLoop ; ++ucLoop)
 257:          {
 258:              gKey = 0;                 //키값 리셋                
 259:              //1 ~ 7까지 난수를 발생하여 그 수 만큼 좌로 시프트
 260:              ucLED = 1 << (rand() % 8);        
 261:              PORT_LED = ~ucLED;        //반전하여 출력        
 262:              sleep(uiDiff - (ucGameLv * 25));        //난이도에 따라 지연시간이 달라짐.
 263:                                                      //EASY    = 1000ms ~ 750ms(10세트)
 264:                                                      //NORMAL= 750ms ~ 500ms
 265:                                                      //HARD     = 500ms ~ 250ms
 266:   
 267:              //횟수와 점수를 출력.
 268:              ucLED = log_2(ucLED);    
 269:              ucTemp = log_2(gKey);
 270:              printf_suman("%d.\t", ucLoop, 0, 0);              
 271:              game_display_LED_SW(ucLED);            //LED - 0~8까지의 값을 받아 ○○○○○○○●출력
 272:              
 273:              uart_send_string_suman("\n\t");
 274:              
 275:              if(0 != gSensor && 0 < ucBomb)                //센서 감지되고 폭탄갯수가 충분하면,
 276:              {                                        
 277:                  uart_send_string_suman("▲▲▲Boom▲▲▲\a\a");    //뽀개진거 출력.
 278:                  PORT_BELL = 0x00;        //BELL ON
 279:                  sleep(20);                //50ms
 280:                  PORT_BELL = 0xFF;        //BELL OFF
 281:                  sleep(20);                //50ms
 282:                  PORT_BELL = 0x00;        //BELL ON
 283:                  sleep(20);                //50ms
 284:                  PORT_BELL = 0xFF;        //BELL OFF
 285:              }
 286:              else                                        //일반상태
 287:              {
 288:                  game_display_LED_SW(ucTemp);            //KEY - 0~8까지의 값을 받아 ○○○○○○○●출력                
 289:              }
 290:   
 291:              //두더지가 맞았으면 
 292:              if(ucLED == ucTemp || ((0 != gSensor) && (0 < ucBomb)))    //두더지를 맞추었으니
 293:              {
 294:                  ucScore = ucScore + 1;    //1점증가 (표시할 땐 *5해서 표시)
 295:                  uart_send_string_suman("...OK!\n");
 296:              }
 297:              else
 298:              {
 299:                  uart_send_string_suman("...Fail!!\n");
 300:              }
 301:   
 302:              //폭탄처리
 303:              if(0 != gSensor)            //센서 감지되면,
 304:              {
 305:                  gSensor = 0;            //센서값 초기화
 306:   
 307:                  if(0 < ucBomb)
 308:                  {
 309:                      --ucBomb;            //폭탄 갯수 줄임.
 310:                  }
 311:              }
 312:              
 313:              //100점은 제외. 16진수변환 함수가 3자리를 처리 못 함.
 314:              if(100 != ucScore)
 315:              {
 316:                  PORT_FND = hex_to_dec(ucScore * 5);        //FND에 점수표시
 317:              }
 318:   
 319:              PORT_LED = 0xFF;    //LED모두 OFF
 320:              sleep(uiDiff);        //500ms 대기
 321:          }
 322:          
 323:          //점수 출력.
 324:          printf_suman("\t\t\t점수: %d점\n", ucScore * 5, 0, 0);
 325:          sleep(2000);        //2초 대기.
 326:   
 327:          ucScoreSum = ucScoreSum + ucScore;        //점수 합산
 328:          ucLED = 0xFF;        //점수 출력 전 초기화
 329:   
 330:          if(100 == (ucScore * 5))            //만약 모두 맞추었다면
 331:          {
 332:              PORT_FND = 0x00;    // "00"표시
 333:              uart_send_string_suman("100점이네요. ㅊㅋㅊㅋ\n\n");
 334:   
 335:              for(ucLoop = 0; 5 > ucLoop ; ++ucLoop)    //LED깜빡깜빡
 336:              {
 337:                  PORT_LED = ucLED;    // 모두 OFF
 338:                  sleep(500);
 339:                  ToggleNumber(&ucLED);
 340:                  PORT_LED = 0xFF;    // 모두 ON
 341:                  sleep(500);
 342:              }
 343:          }
 344:          else                    //100점이 아니면 현재 점수 보여줌.
 345:          {
 346:              PORT_LED = ucLED;        // LED 모두 OFF
 347:              sleep(300);                // 300ms 딜레이
 348:              
 349:              if(8 > ucScore)
 350:              {
 351:                  game_over(ucScoreSum);        // GAME OVER메세지와 EEPROM에 총점 기록.
 352:   
 353:   
 354:                  break;                // 메뉴로
 355:              }
 356:          }    
 357:   
 358:          ucScore = 0;                    // 점수 초기화
 359:          gKey = 0;                    // 키값 리셋
 360:      }
 361:  }
 362:   
 363:   
 364:  void game_display_LED_SW(unsigned char cNum)
 365:  {
 366:      char aBuf[][18] = {"○○○○ ○○○○",
 367:                          "○○○○ ○○○●",
 368:                          "○○○○ ○○●○",
 369:                          "○○○○ ○●○○",
 370:                          "○○○○ ●○○○",
 371:                          "○○○● ○○○○",
 372:                          "○○●○ ○○○○",
 373:                          "○●○○ ○○○○",
 374:                          "●○○○ ○○○○"};
 375:   
 376:      uart_send_string_suman(aBuf + cNum);
 377:      
 378:      return ;
 379:  }
 380:   
 381:   
 382:  /******************************************************************************
 383:  
 384:                  게임 옵션 설정
 385:  
 386:  *******************************************************************************/
 387:  unsigned int game_option(void)
 388:  {
 389:      unsigned int uiDiff = 1000;
 390:      unsigned char ucBreak = 0;
 391:   
 392:      uart_send_byte(0x0C);        //다음 페이지
 393:      
 394:      uart_send_string_suman("\n\n\n\n");
 395:      uart_send_string_suman("\t\t\t1. EASY\n");
 396:      uart_send_string_suman("\t\t\t2. NORMAL\n");
 397:      uart_send_string_suman("\t\t\t3. HARD\n");
 398:      uart_send_string_suman("\t\t\t4. EXIT\n");
 399:      
 400:      
 401:      sleep(1000);        //1초 대기
 402:      
 403:      while(0 == ucBreak)
 404:      {
 405:          gKey = 0;        //key값 초기화
 406:          sleep(100);        //키입력 받을 시간.
 407:          
 408:          switch(gKey)
 409:          {
 410:              //1번
 411:              case 0x01:
 412:                  uiDiff = 1000;        //1초
 413:                  uart_send_string_suman("\rEASY MODE!  ");
 414:                  break;
 415:              
 416:              //2번
 417:              case 0x02:
 418:                  uiDiff = 750;        //0.75초
 419:                  uart_send_string_suman("\rNORMAL MODE!");
 420:                  break;
 421:          
 422:              //3번
 423:              case 0x04:
 424:                  uiDiff = 500;        //0.5초
 425:                  uart_send_string_suman("\rHARD MODE!  ");
 426:                  break;
 427:                  
 428:              //4번
 429:              case 0x08:
 430:                  ucBreak = 1;        //탈출값.
 431:                  break;
 432:          
 433:              default:
 434:                  break;
 435:          }
 436:      }
 437:      
 438:      sleep(1000);
 439:      
 440:      return uiDiff;        //난이도 값 반환
 441:  }
 442:   
 443:   
 444:  /******************************************************************************
 445:  
 446:                  순위 출력 및 초기화
 447:  
 448:  *******************************************************************************/
 449:  void game_rank(void)
 450:  {
 451:      unsigned char ucLoop;
 452:      
 453:      game_score();
 454:      
 455:      uart_send_string_suman("\n\n");
 456:      uart_send_string_suman("\t순위를 초기화하려면 적외선 센서를 막으세요.\n");
 457:      uart_send_string_suman("\t나가시려면 아무 키나 눌러주세요.");
 458:      
 459:      sleep(1000);        //1초 대기
 460:      
 461:      gKey = 0;        //키 값 초기화
 462:   
 463:      while(1)
 464:      {
 465:          if(0 == (0x80 & PIN_SENSOR))        //적외선 센서가 감지되면,
 466:          {
 467:              for(ucLoop = 0 ; 10 > ucLoop ; ++ucLoop)
 468:              {
 469:                  eeprom_write(ucLoop, 0);    //EEPROM 데이터 초기화 (0~10까지)
 470:              }
 471:              
 472:              game_score();                    //점수 출력.
 473:              
 474:              break;
 475:          }
 476:          
 477:          if(0 != gKey)                        //아무 키나 누르면 탈출.
 478:          {
 479:              break;
 480:          }
 481:      }
 482:      
 483:      sleep(1000);
 484:   
 485:      return ;
 486:  }
 487:   
 488:   
 489:  void game_score(void)
 490:  {
 491:      unsigned char ucLoop;
 492:      unsigned char ucTemp;
 493:   
 494:   
 495:      uart_send_byte(0x0C);            //다음 페이지
 496:      
 497:      uart_send_string_suman("\n\n\n\n");
 498:      
 499:      //1위 부터 10위까지 출력
 500:      for(ucLoop = 0 ; 10 > ucLoop ; ++ucLoop)
 501:      {
 502:          uart_send_string_suman("\t\t\t");
 503:   
 504:          ucTemp = eeprom_read(ucLoop);
 505:          printf_suman("%d. %d점\n", ucLoop + 1, ucTemp * 5, 0);
 506:      }
 507:   
 508:      return ;
 509:  }
 510:   
 511:  /******************************************************************************
 512:  
 513:                  게임 종료 함수.
 514:  
 515:  *******************************************************************************/
 516:  void game_exit(void)
 517:  {
 518:      uart_send_byte(0x0C);
 519:      uart_send_string_suman("\n\n\n\n\t\t\tGood Bye~");
 520:      
 521:      while(1);        //일단 지금은 잡아둠. 나중에 종료되도록 할 것..
 522:      
 523:      return ;
 524:  }
 525:   
 526:   
 527:  /******************************************************************************
 528:  
 529:                          GAME OVER
 530:  
 531:  *******************************************************************************/
 532:  void game_over(unsigned char ucScoreSum)
 533:  {
 534:      unsigned char ucLoop;
 535:      unsigned char ucTemp;
 536:      
 537:      uart_send_byte(0x0C);
 538:      uart_send_string_suman("\n\n\n\n\t\t\tGAME OVER");
 539:      
 540:      //점수를 정렬하며 EEPROM에 기록 1위~10위까지
 541:      eeprom_write(10, ucScoreSum);        //제일 밑에 총점을 넣고
 542:      
 543:      for(ucLoop = 10 ; 0 < ucLoop ; --ucLoop)
 544:      {
 545:          if(eeprom_read(ucLoop) > eeprom_read(ucLoop - 1))        //바로 위에 수치와 비교하여,
 546:          {
 547:              ucTemp = eeprom_read(ucLoop - 1);                    //교체
 548:              eeprom_write(ucLoop - 1, eeprom_read(ucLoop));
 549:              eeprom_write(ucLoop, ucTemp);
 550:          }
 551:      }
 552:   
 553:      sleep(3000);
 554:      
 555:      return ;
 556:  }
 557:   
 558:   
 559:   
 560:  /*********************************************************************************
 561:          <초기화 함수들>
 562:                  
 563:          모두 상단의 전처리문을 참조해야 함.
 564:          
 565:  *********************************************************************************/
 566:  //I/O 포트 초기화
 567:  void init_port(void)
 568:  {
 569:      DDR_KEY = 0x00;        // 모두 입력
 570:      DDR_SENSOR = 0x00;    // 모두 입력
 571:      DDR_LED = 0xFF;        // 모두 출력
 572:      DDR_FND = 0xFF;        // 모두 출력
 573:      PORT_LED = 0xFF;    // 모든 LED꺼짐. 
 574:      PORT_FND = 0x00;    // 00출력
 575:      DDR_BELL = 0xFF;    // 모두 출력.
 576:      PORT_BELL = 0xFF;    // 모두 FF
 577:      
 578:      return ;
 579:  }
 580:      
 581:   
 582:  //타이머0 초기화
 583:  void init_TC0(void)
 584:  {
 585:      //CTC Mode, prescanler = 1/64
 586:      TCCR0 = (1 << WGM01) | (1 << CS02);        
 587:      //8bit Timer0 = 16,000,000 / 1000 / 64
 588:      //            = 250
 589:      OCR0 = CPU_CLOCK / TICKS_PER_SEC / PRESCALER;
 590:      //타이머0 비교 매치 인터럽트 활성
 591:      TIMSK = (1 << OCIE0);        
 592:      
 593:      return ;
 594:  }
 595:   
 596:  //UART1 초기화
 597:  void init_USART1(void)
 598:  {
 599:      //baud rate설정
 600:      UBRR1L = (unsigned char)BAUD_RATE_L;    
 601:      UBRR1H = (unsigned char)BAUD_RATE_H;
 602:      
 603:      // no parity, 1stop bit, 8bit data설정
 604:      UCSR1C = (0 << UPM1) | (0 << UPM0) | (0 << USBS) | (1 << UCSZ1) | (1 << UCSZ0);
 605:      // rx/tx interrupt설정, 8bit설정
 606:      UCSR1B = (1 << TXEN) | (1 << RXEN) | (0 << UCSZ2);
 607:      // x2 speed
 608:      UCSR1A = (1 << U2X);
 609:   
 610:      return ;
 611:  }
 612:   
 613:   
 614:  /*>>>>>>>>>>>>>>>>>> 하드웨어와 밀접한 관련이 있는 함수들 (통신주변장치) <<<<<<<<<<<<<<<<<<<<*/
 615:   
 616:  //1바이트 수신함수
 617:  unsigned char USART_Receive(void)    // ← 이름 바꿀까?
 618:  {
 619:      //RXC의 값이 0이어 수신버퍼가 비어 있으면 계속 대기.
 620:      while(!(UCSR1A & (1 << RXC)));
 621:      
 622:      return UDR1;
 623:  }
 624:   
 625:  //1바이트 전송함수
 626:  void uart_send_byte(unsigned char byte)
 627:  {
 628:      while(!(UCSR1A & (1 << UDRE)));        //전송 버퍼가 빌 때까지 대기
 629:      UDR1 = byte;                            //문자1개를 전송한다.
 630:      
 631:      return ;
 632:  }
 633:   
 634:   
 635:  /*******************************************************
 636:              EEPROM에 데이터 읽기/쓰기 함수
 637:  *******************************************************/
 638:  void eeprom_write(unsigned int uiAddress, unsigned char ucData)
 639:  {
 640:      while(EECR & (1 << EEWE));        //쓰기 작업 중이면 루프
 641:      
 642:      EEAR = uiAddress;                //쓸 주소 설정
 643:      EEDR = ucData;                    //쓸 데이터
 644:      EECR = EECR | (1 << EEMWE);    //EEWE할 준비해라
 645:      EECR = EECR | (1 << EEWE);        //쓰기 명령
 646:      
 647:      return ;
 648:  }
 649:   
 650:  unsigned char eeprom_read(unsigned int uiAddress)
 651:  {
 652:      while(EECR & (1 << EEWE));        //쓰기 작업 중이면 루프
 653:      
 654:      EEAR = uiAddress;                //읽을 주소 설정
 655:      EECR = EECR | (1 << EERE);        //읽기 명령
 656:      
 657:      return EEDR;                    //데이터 읽기
 658:  }
 659:   
 660:   
 661:   
 662:   
 663:  /**********************************************************************************************
 664:      <급조한 printf함수>
 665:          
 666:      일정 포맷에 맞게 제작된 함수. 
 667:      3개의 10진수 입력만 받아 문자열로 변환하여 합성하여 출력. (1Byte크기의 정수)
 668:          
 669:      printf_suman("const char *", num1, num2, num3)
 670:      
 671:      <요구사항>
 672:      uart_send_string_suman()필요.
 673:      
 674:      작 성 자: 김수만
 675:      작성일자: 2011년 5월 23일    
 676:  
 677:  **********************************************************************************************/
 678:  void printf_suman(char *cStr, unsigned char cNum1, unsigned char cNum2, unsigned char cNum3)
 679:  {
 680:      int i;                //문자열 시작부터의 Offset값.
 681:      char cCnt = 0;        //%d형식지정자에 전달할 값의 위치 기억.
 682:      char aStr[4];        //숫자를 문자로 바꿀 때 사용하는 문자배열
 683:      
 684:      for(i = 0 ; '\0' != *(cStr + i) ; ++i)            //문자열의 끝까지 반복.
 685:      {
 686:          if('%' == *(cStr + i))                        //형식지정자를 만나면
 687:          {
 688:              switch(cCnt)
 689:              {
 690:                  //첫 번째 인자를 문자로 변환하여 출력.
 691:                  case 0:                                
 692:                      dec_to_ascii(cNum1, aStr);
 693:                      uart_send_string_suman(aStr);
 694:                      break;
 695:                  //두 번째 인자를 문자로 변환하여 출력.
 696:                  case 1:
 697:                      dec_to_ascii(cNum2, aStr);
 698:                      uart_send_string_suman(aStr);
 699:                      break;
 700:                  //세 번째 인자를 문자로 변환하여 출력.
 701:                  case 2:
 702:                      dec_to_ascii(cNum3, aStr);
 703:                      uart_send_string_suman(aStr);
 704:                      break;
 705:                  //인자를 추가하려면 여기다 하이소.
 706:                  default:
 707:                      break;
 708:              }
 709:              
 710:              ++i;            //다음 문자를 가리키도록 1증가.
 711:              ++cCnt;            //다음 인자를 가리키도록 1증가.
 712:          }
 713:          else                                //형식지정자가 아닌 일반 문자이면,
 714:          {                                    //문자를 출력.
 715:              if('\n' == *(cStr + i))
 716:              {
 717:                  uart_send_byte('\r');        //개행문자를 만나면,
 718:                  uart_send_byte('\n');        //케리지리턴 + 라인피드
 719:              }
 720:              else
 721:              {
 722:                  uart_send_byte(*(cStr + i));    //시작번지로 부터 i번째 문자 전송.
 723:              }
 724:          }
 725:      }
 726:      
 727:      return ;
 728:  }    
 729:   
 730:  //문자열 전송함수 len은 문자열의 길이.
 731:  void uart_send_string(unsigned char *str, unsigned int len)
 732:  {
 733:      int i;
 734:      
 735:      for(i = 0 ; i < len ; i++)        //문자열의 길이만큼 반복.
 736:      {
 737:          uart_send_byte(*(str + i));    //시작번지로 부터 i번째 문자 전송.
 738:      }
 739:      
 740:      return ;
 741:  }
 742:   
 743:  //문자열 전송함수(수만)
 744:  void uart_send_string_suman(char *cStr)
 745:  {
 746:      int i;        //Offset
 747:      
 748:      for(i = 0 ; '\0' != *(cStr + i) ; ++i)        //NULL문자까지 반복.
 749:      {
 750:          if('\n' == *(cStr + i))            //개행문자를 만나면,
 751:          {
 752:              uart_send_byte('\r');            //캐리지 리턴후에
 753:              uart_send_byte('\n');            //라인 피드
 754:          }
 755:          else
 756:          {
 757:              uart_send_byte(*(cStr + i));    //시작번지로 부터 i번째 문자 전송.
 758:          }
 759:      }
 760:      
 761:      return ;
 762:  }    
 763:   
 764:   
 765:  /*>>>>>>>>>>>>>>>>>>>>> 어느 하드웨어에나 이식이 자유로운 수치처리함수 <<<<<<<<<<<<<<<<<<<<<<*/
 766:   
 767:   
 768:  //16진수를 10진수로 바꾸는 함수 (100미만의 값만 취급한다.)
 769:  unsigned char hex_to_dec(unsigned char cNum)
 770:  {
 771:      unsigned char temp;
 772:      
 773:      //실제 16진수가 아닌 10진수를 16진수로 취급하여,
 774:      //10의 자리 잘라내 곱하기 16 + 1의 자리.
 775:      temp = (cNum / 10) * 16 + (cNum % 10);
 776:      
 777:      return temp;
 778:  }
 779:   
 780:  //정수를 문자로 바꾸는 함수. (0~255까지만 취급함.)
 781:  void dec_to_ascii(unsigned char cNum, char *p)
 782:  {
 783:      unsigned char ucLoop = 3;
 784:   
 785:      *(p + ucLoop) = '\0';                    //문자열끝.
 786:      
 787:      for(; 0 < ucLoop ; --ucLoop)
 788:      {
 789:          *(p + ucLoop - 1) = (cNum % 10) + '0';     //일자리부터 백자리까지 저장 후 문자로 변환.
 790:          cNum = cNum / 10;                            //일자리부터 10단위로 잘라냄.
 791:      }
 792:      
 793:      //숫자 앞에 0을 없애는 부분.
 794:      for(ucLoop = 0 ; 2 > ucLoop ; ++ucLoop)
 795:      {
 796:          if('0' == *(p + ucLoop))                    //현재 자리가 '0'이면,
 797:          {
 798:              if(0 == ucLoop)                                    //첫 번째 자리에는,
 799:              {
 800:                  *(p + ucLoop) = ' ';                        //공백문자로 만들어 버림.
 801:              }
 802:              else if((0 != ucLoop) && (2 != ucLoop) && (' ' == *(p + ucLoop - 1)))        
 803:              {                                                //첫 번째와 마지막자리를 제외한 자리에는,
 804:                  *(p + ucLoop) = ' ';                        //공백문자로 만들어 버림.
 805:              }
 806:              else                                            //마지막자리는,
 807:              {
 808:                  *(p + ucLoop) = '0';                        //'0'으로 만들어 버림.
 809:              }
 810:          }
 811:      }
 812:   
 813:      return ;
 814:  }
 815:   
 816:   
 817:  //log2 N의 값을 구함. (128~0 -> 8~0)
 818:  char log_2(unsigned char cNum)
 819:  {
 820:      unsigned char ucLoop = 0;        //log2 N에서 N의 값이 0이면 0이다.
 821:      
 822:      //계속 2로 나누어 나눈 횟수를 반환.
 823:      while(cNum >= 1)                
 824:      {
 825:          cNum = cNum / 2;
 826:          ucLoop++;
 827:      }
 828:      
 829:      return ucLoop;
 830:  }
 831:   
 832:  //입력 받은 숫자 반전. (변수의 주소를 참조해 1의 보수를 취함.)
 833:  void ToggleNumber(unsigned char * state)
 834:  {
 835:      *state = ~*state;        //반전
 836:      
 837:      return ;
 838:  }