2011년5월13일...두더지잡기게임 코드정리, C과제2(코드오류수정, 2의 보수변환, 초를 분초로 변환, 10진수를 8진수로 변환하는 함수, 각 자릿수들의 합구하기)
두더지잡기게임 1-2
두더지잡기게임 1-1을 하느라 바빴다. ┐-
두더지게임 소스코드 정리
소스코드는 크게 8개의 항목으로 나눌 수 있다.
이 중 헤더파일에 넣을 수 있는 부분은 헤더파일에 넣고,
따로 분할컴파일을 해야 하는 부분은 오브젝트파일을 따로 만들어 링크를 해야 하나…
만들어진 함수가 모두 재사용하기 불편한 구조로 되어 있다.
예를 들어…I/O포트 초기화 함수의 경우…
initLED에서 항상 하드웨어가 같을 경우엔 문제가 없으나 LED를 다른 포트에 결선할 때는 문제가 발생한다.
이런 함수는 분할컴파일하기엔 적합하지 않다.
그리고 워낙 단순한 코드이고 초기화 함수는 대부분 프로그램이 시작할 때 한 번만 수행되는 경우가 많으니 main( )에,
넣는 게 좋다. 굳이 따로 함수를 만들고 싶다면 초기화 SFR의 주소인자와 값 인자를 호출할 때 전달하는 것이 어떨까?
타이머/카운터0초기화 함수의 경우도 마찬가지다.
설정값을 바꿔야 하고 MCU가 달라지면 많이 수정해야 한다.
sleep( ) 함수는 아예 전역변수를 사용하고 있으니 분할컴파일이 불가능하다.
굳이 분할컴파일하자면 호출할 때 전역변수의 주소를 인자로 넘겨주는 방법이 있겠다.
ISR은 말할 것도 없으나, 방법이 아예 없는 것은 아니다. (이 부분에 잘 모르나 불가능하진 않다는 것을 알고 있다.)
결국 정리할 부분은 main( ) 함수가 되겠다.
간소화와 보기 좋게 정리해야겠으나 오늘은 너무 피곤하다. –_-zZ zZ (5월15일 11시 7분전)
정의 부분
1: /***************************************************************************
2: <두더지잡기 게임1-1>
3:
4: - 무한 루프 진행
5: - 랜덤으로 20번 LED 켜짐. 난수를 발생하여 LED On/Off를
6: 각각 0.5초간 유지
7: - LED가 켜진 시점에 해당 스위치를 누르면 점수 5점씩 증가
8: - 점수는 FND로 출력(점수 0x00~0x95 표시)
9: - 100점인 경우 FND는 0x00 출력, LED는 모두 깜박깜박~
10:
11: 소속: 내장형하드웨어
12: 작성자: 김수만
13: 작성일자: 2011년 5월 12일
14:
15: ***************************************************************************/
16: #include "ATmega128.h"
17: #include <stdlib.h>
18:
19: //포트 정의
20: #define DDR_LED DDRF
21: #define PORT_LED PORTF
22: #define DDR_FND DDRE
23: #define PORT_FND PORTE
24: #define DDR_KEY DDRC
25: #define PIN_KEY PINC
26: #define PORT_KEY PORTC
27: //타이머관련
28: #define CPU_CLOCK 16000000 // CPU clock = 16Mhz
29: #define TICKS_PER_SEC 1000 // Ticks per sec = 1,000
30: #define PRESCALER 64 // Prescaler = 64
31: // 클럭의 배수(크기,오버헤드)
전역변수
1: volatile unsigned int g_elapsed_time = 0; // 시간 변수
2: volatile unsigned char key = 0; // 키입력값 저장 버퍼
함수의 프로토타입
1: //ISR
2: void __vector_15 (void) __attribute__ ((signal, used, externally_visible));
3: void initLED(void); // LED초기화
4: void initKEY(void); // KEY초기화
5: void initFND(void); // FND초기화
6: void setTCCR0(void); // 타이머0 초기화
7: void initOCR0(void); // OCR0 초기화
8: void setTIMSK(void); // TIMSK초기화
9: void toggleLED(char * state); // LED반전
10: void sleep(unsigned int elapsed_time); // 1초 대기
프로그램의 시작
1: //프로그램 시작
2: int main(void)
3: {
4: unsigned char cLED = 0; //LED
5: unsigned char cScore = 0; //점수
6: unsigned char cLoop = 0;
7:
8: initLED(); // LED초기화
9: initFND(); // FND초기화
10: initKEY(); // KEY초기화
11: setTCCR0(); // TCCR0 설정
12: initOCR0(); // OCR0 초기화
13: setTIMSK(); // TIMSK 설정
14: sei(); // 인터럽트 활성화
15:
16: /* srand()에 seed값을 시작할 때마다 다르게 넣어주기 위해
17: PC에선 내부RTC의 시간을 이용하나 AVR은 RTC가 없기 때문에
18: 언제 누를지 알 수 없는 KEY와 항상 변화하고 있는 TCNT0의 값을
19: 이용한다. */
20: while(0xFF == PIN_KEY); //아무 키나 누를 때까지 대기
21: srand(TCNT0); //시드값으로 TCNT0전달.
22:
23: while(0xFF != PIN_KEY); //키를 땔 때까지 대기
24: key = 0; //key값 리셋
25: sleep(100); //100ms대기
26:
27: while(1) //무한루프
28: {
29: for(cLoop = 0; 20 > cLoop ; ++cLoop)
30: {
31: //1 ~ 7까지 난수를 발생하여 그 수 만큼 좌로 시프트
32: cLED = 1 << (rand() % 8);
33: PORT_LED = ~cLED; //반전하여 출력
34: sleep(1000); //1000ms 대기
35:
36: //두더지가 맞았으면
37: if(cLED == key) //두더지를 맞추었으니
38: {
39: cScore = cScore + 5; //5점증가
40: }
41:
42: key = 0; //키값 리셋
43: if(100 != cScore)
44: {
45: PORT_FND = (cScore / 10) * 16 + (cScore % 10); //FND에 점수표시
46: }
47:
48: PORT_LED = 0xFF; //LED모두 OFF
49: sleep(500); //500ms 대기
50: }
51:
52: if(100 == cScore) //만약 모두 맞추었다면
53: {
54: PORT_FND = 0x00; // "00"표시
55:
56: for(cLoop = 0; 7 > cLoop ; ++cLoop) //LED깜빡깜빡
57: {
58: PORT_LED = 0x00; // 모두 ON
59: sleep(500);
60: PORT_LED = 0xFF; // 모두 OFF
61: sleep(500);
62: }
63: }
64: else //100점이 아니면 현재 점수 보여줌.
65: {
66: PORT_LED = 0xFF; // LED 모두 OFF
67: sleep(5000); // 5초 딜레이
68: }
69:
70: cScore = 0; // 점수 초기화
71: key = 0; // 키값 리셋
72:
73: }
74:
75: return 1; //종료
76: }
Interrupt Service Routine
1: /*******************************************************
2: 타이머/카운터0 비교매치 인터럽트 서비스 루틴
3: *******************************************************/
4: void __vector_15(void)
5: {
6: ++g_elapsed_time; // 시간변수 1증가
7: key = key | ~PIN_KEY; //키입력값을 반전하여 저장.
8: }
I/O포트 초기화
1: //LED초기화
2: void initLED(void)
3: {
4: DDR_LED = 0xFF; //모두 출력
5: PORT_LED = 0xFF; //포트 초기화
6:
7: return ;
8: }
9:
10: //KEY초기화
11: void initKEY(void)
12: {
13: DDR_KEY = 0x00; //모두 입력
14: PORT_KEY = 0xFF; //모두 풀업처리
15:
16: return ;
17: }
18:
19: //FND초기화
20: void initFND(void)
21: {
22: DDR_FND = 0xFF; //모두 출력
23: PORT_FND = 0x00; // "00"출력
24:
25: return ;
26: }
타이머/카운터0 초기화
1: //타이머0 초기화
2: void setTCCR0(void)
3: {
4: TCCR0 = (1 << WGM01) | (1 << CS02); //CTC Mode, prescanler = 1/64
5: //TCCR0 = 0x44;
6: return ;
7: }
8:
9: //TCNT0 초기화
10: void initOCR0(void)
11: {
12: //8bit Timer0 = 16,000,000 / 1000 / 64
13: // = 250
14: OCR0 = CPU_CLOCK / TICKS_PER_SEC / PRESCALER;
15:
16: return ;
17: }
18:
19: //TIMSK 초기화
20: void setTIMSK(void)
21: {
22: TIMSK = (1 << OCIE0); //타이머0 비교 매치 인터럽트 활성
23:
24: return ;
25: }
대기 함수(시간 지연)
1: //1초 대기
2: void sleep(unsigned int elapsed_time)
3: {
4: g_elapsed_time = 0; //시간 변수 초기화
5: while(elapsed_time > g_elapsed_time); //참이 될 때까지 대기.
6:
7: return ;
8: }
C과제2
1. 잘못된 부분이 있으면 찾아서 고쳐보세요.
1)int value = 0;
printf("value 초기값은 %d \n" value);
답: printf("value 초기값은 %d \n", value); (콤마가 없었음)
2)printf("1 + 2 = %d \n");
답: printf("1 + 2 = %d \n", 3); (%d형식지정자와 쌍인 인자가 없음)
3)int num1, num2;
scanf("%d , %d", &num1, &num2);
답: scanf("%d %d", &num1, &num2); (콤마가 있으면 안 됨. 공백문자로 띄어쓰기 해야 함.)
4)char ch1;
scanf("%c \n", &ch1);
답: scanf("%c", &ch1);
(scanf( )에 인자로 ‘\n’ (개행문자)를 넣으면 두 번 입력해야 하고 두 번째 입력되는 값은 버려짐.)
5)int pwd;
scanf(“패스워드 입력 : %d”, &pwd);
답: printf("패스워드 입력: ");
scanf("%d", &pwd);
(“패스워드 입력 : %d”에서 큰 따옴표가 2Bytes유니코드이고 따옴표 안에 한글을 쓰면 안 됨.)
2011년 5월15일 추가…
따옴표 안에 한글도 쓰면 안 되지만 화면에 출력되는 내용자체를 넣으면 안 됨.
6)int value;
scanf("\n %d, %d \n", &value);
답: scanf("%d", &value); (따옴표 안에 ‘\n’(개행문자)가 있고 %d형식지정자가 하나 더 많음)
2. 정수 N을 입력 받아 2의 보수를 취한 값을 출력하세요.
출력) 정수 입력 : 1
2의 보수 출력 : -1
1: /****************************************************
2:
3: 2번. 정수를 입력 받아 2의 보수를 출력하는 프로그램
4:
5: 소 속: 내장형하드웨어
6: 작 성 자: 김수만
7: 작성일자: 2011년 5월 13일
8:
9: *****************************************************/
10: #include <stdio.h>
11:
12: int main()
13: {
14: int iNum;
15:
16: printf("정수 입력: ");
17: scanf("%d", &iNum);
18:
19: iNum = ~iNum;
20: iNum = iNum + 1;
21:
22: printf("2의 보수 출력: %d", iNum);
23:
24:
25:
26: return 0;
27: }
3. 초 입력시 분과 초로 변환하는 프로그램을 작성하세요.
출력) Input Seconds : 100
Output : 1 min 40 sec
Input Seconds : 80
Output : 1 min 20 sec
Input Seconds : –1
프로그램 종료!!!
1: /************************************************************
2:
3: 3번. 초 입력시 분과 초로 변환하는 프로그램을 작성하세요.
4:
5: 소 속: 내장형하드웨어
6: 작 성 자: 김수만
7: 작성일자: 2011년 5월 13일
8:
9: ************************************************************/
10: #include <stdio.h>
11:
12: int main()
13: {
14: int iSec;
15: int iMin;
16:
17: while(-100)
18: {
19: printf("Input Seconds : ");
20: scanf("%d", &iSec);
21:
22: if(-1 == iSec)
23: {
24: printf("프로그램 종료!!!\n");
25: return 0;
26: }
27:
28: iMin = iSec / 60;
29: iSec = iSec - iMin * 60;
30:
31: printf("Output : %d min %d sec\n\n", iMin, iSec);
32: }
33:
34:
35: return 0;
36: }
4. 10진수 0부터 16까지의 정수를 8진수로 출력합니다. 출력에는 10진수와 8진수의 대응관계를 반드시 포함시킵니다. printf함수의 %o플래그를 사용할 수 없습니다.
1: /************************************************************
2:
3: 4. 10진수 0부터 16까지의 정수를 8진수로 출력합니다.
4: 출력에는 10진수와 8진수의 대응관계를 반드시 포함시킵니다.
5: printf함수의 %o플래그를 사용할 수 없습니다.
6:
7:
8: 방법: 10진수를 8로 나누어 나머지와 몫을 이용해 8진수 구함.
9:
10: 소 속: 내장형하드웨어
11: 작 성 자: 김수만
12: 작성일자: 2011년 5월 13일
13:
14: ************************************************************/
15: #include <stdio.h>
16:
17: int dec_to_Oct(int iHex); //10진수를 8진수로 변환
18:
19: int main()
20: {
21: int iHex; //원본 10진수
22:
23: printf("10진수\t→\t8진수\n");
24:
25: //0~16까지의 십진수
26: for(iHex = 0 ; 16 >= iHex ; ++iHex)
27: {
28: printf(" %d\t→\t %d\n", iHex, dec_to_Oct(iHex));
29: }
30:
31: return 0;
32: }
33:
34: /************************************************************
35: 10진수를 입력받아 8진수를 반환하는 함수
36: ************************************************************/
37: int dec_to_Oct(int iMoc)
38: {
39: int iOct = 0; //최종 출력 8진수
40: int iMod = 0; //나머지 임시저장
41: int iCount = 0; //나눈 횟수
42:
43: while(8 <= iMoc)
44: {
45: iMod = iMoc % 8; //나머지를 구함.
46: iMoc = iMoc / 8; //몫을 구함.
47:
48: //나머지에 자릿수를 곱하여 합.
49: iOct = iOct + iMod * exp(iCount);
50: //자릿수 카운트
51: ++iCount;
52: }
53: //마지막으로 몫을 더하는데 자릿수를 곱하여 줌.
54: iOct = iOct + iMoc * exp(iCount);
55:
56: //8진수 반환
57: return iOct;
58: }
59:
60: /************************************************************
61: 10^N을 구하는 프로그램. 계산기의 Exp와 같음.
62: ************************************************************/
63: int exp(int iNum)
64: {
65: int result = 1; //0을 받았을 때의 반환값
66: //10^0은 1이다.
67: while(iNum--) //0이 될 때까지 반복
68: {
69: result = result * 10; //10을 계속 곱해줌.
70: }
71:
72: return result;
73: }
74:
75:
76:
5. 키보드로부터 최대 세 자리의 정수를 입력 받습니다. 자릿수들의 합계는 얼마입니까?
1: /************************************************************
2:
3: 5. 키보드로부터 최대 세 자리의 정수를 입력 받습니다.
4: 자릿수들의 합계는 얼마입니까?
5:
6: 소 속: 내장형하드웨어
7: 작 성 자: 김수만
8: 작성일자: 2011년 5월 13일
9:
10: ************************************************************/
11: #include <stdio.h>
12:
13: int main()
14: {
15: int iNum;
16: int iSum;
17:
18:
19: while(1)
20: {
21: printf("입력(3자리) : ");
22: scanf("%d", &iNum);
23:
24: if(-1 == iNum)
25: {
26: break;
27: }
28:
29: iSum = iNum / 100; //100자리
30: iNum = iNum % 100;
31:
32: iSum = iSum + iNum / 10; //10자리
33: iNum = iNum % 10;
34:
35: iSum = iSum + iNum; //1자리
36:
37:
38: printf("자릿수 합계 : %d\n", iSum);
39: }
40:
41: printf("프로그램 종료!!\n");
42:
43: return 0;
44: }