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);
시작화면과 메뉴 |
귀여운 두더지가 나왔다 들어갔다 하는 모습을 표현하기 위해 화면을 뿌리고 지우고 반복하는데,
아래에 보면 통신속도가 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에 저장된 순위 데이터 출력 |
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: }
게임옵션 |
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: }
게임진행화면 |
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: }
진행 동영상 |
시작화면이 귀엽지 아니한가?
귀엽다!
귀엽다!
귀엽다!