본문 바로가기

Embeded/프로젝트

2010년 11월 04일 목요일 [ATmega128] (직렬 포트 통신을 이용한 두더지잡기 게임)

// 직렬 포트를 이용한 두더지 잡기 게임
#include "header/io.h"      // 직접 만든 헤더파일

#define LED_DDR  DDRF
#define LED_OUT  PORTF
#define KEY_IN  PINC
#define FND_DDR DDRE
#define FND_OUT PORTE

//================================================================//
//      인터럽트 & 통신 속도 설정                                 //
//================================================================//
#define CPU_CLOCK  16000000    // MCU의 속도
#define TICKS_PER_SEC  1000
#define PRESCALER  128
#define BAUD_RATE   4800        //  통신 속도
#define BAUD_RATE_L (CPU_CLOCK/(16l*BAUD_RATE))-1
#define BAUD_RATE_H ((CPU_CLOCK/(16l*BAUD_RATE))-1)>>8

//================================================================//
//      전역 변수 설정                                            //
//================================================================//
volatile unsigned int g_elapsed_time;  // 시간변수 
unsigned char stron[]="\r\n<<<<<<<<<<<<< Power ON >>>>>>>>>>>>\r\n";
unsigned char strnosw[]="[Did not PUSH switch!]\r\n";
unsigned char endscore[]="My End Game Score : [";
unsigned char endstage[]="]Stage ";
unsigned char strnum[]=".Games : ";
unsigned char strclear[]="**** Congratulates. Next Game. ****\r\n";
unsigned char fnd=0;
unsigned char key_value=0;
unsigned char LED_Match=0xff;
unsigned char KEY_Match=0xff;
unsigned char count;
unsigned int delay_ms;
char stage=1;
char key=0;
char one=0;
char ten=0;
//================================================================//
//      함수 원형 설정                                            //
//================================================================//
void init_PORT(void);                  // 포트 초기화
void init_TIMER(int timers);            // Timer Counter 설정
void init_TC0(void);                  // Timer0 초기화 
void init_USART1(void);                 // 직렬 통신 포트 1번 설정 
void GAME_SET(char set);                // 게임 시작 / 종료 문장
void GAME_COUNT(void);                  // 게임 카운터
char bit_match(char cnum);              // 비트 검사 
void sleep(unsigned int elapsed_time);  // sleep함수
void delay(unsigned int speed);       // SW입력 대기
void SW_loop(void);                     // SW 무한 루프
void uart_send_byte(unsigned char byte);// 한 문자 전송
void uart_send_string(unsigned char *str, unsigned char len); // 문자열 전송

//================================================================//
//      메인 프로그램                                             //
//================================================================//
int main(void)

    /* 변수 설정 */
    char score=0;
    char score1=0;
    unsigned char led=1;
    
    /* 사용 설정 초기화 */
    SREG = SREG|(1<<7);  // 전체 인터럽트 활성화
    init_PORT();        // 포트 초기화
    init_TC0();         // Timer0 초기화
    init_TIMER(OCIE0);  // 타이머 설정
    OCR0 = 0x7D;    // 비교매치 인터럽트 비교값 설정
    sei();            // 인터럽트 활성화 함수
    init_USART1();      // 직렬 통신 포트 1번 설정

    /****************************************/
    /* 프로그램 작성 시작                   */
    /****************************************/  
    /* 두더지 게임 시작 */
    uart_send_string(stron, sizeof(stron)); // Power on 전송
    GAME_SET(1);    // 시작전 대기 & 5초 카운터 
    while(1)        // 무한 루프
    {
        score=0x00;
        score1=0x00;
        for(count=0; count<25; count++)  // 25번 두더지 생성(LED On/off)
        {
            key=5
            fnd=0;
            one+=1;
            if(9<one)
            {
                one=0;
                ten+=1;
            }

            LED_OUT = ~(led<<rand()%8);  // 두더지(LED) 랜덤 위치 생성
            delay(delay_ms);             // 1초간 지연하면서 스위치 입력 대기  
            if((2 != fnd) && (3 != fnd))// SW를 누르지 않을 경우 전송
            {
                SW_loop(); 
                uart_send_string(strnosw, sizeof(strnosw));  
            }

            if(2==fnd)                  // 두더지를 잡으면 점수 5점씩 올림
            {  
                score += 5;
                if(score==0x0a)         // FND가 10점이되면 실행
                {
                    score=0x00;
                    score1+=0x10;
                }
            } 
 
            if(score1>=0xa0||10==fnd)  // 7+8번SW or 점수가 100점이 되면 FND,LED on/off 6회반복
            {
                LED_OUT=0x00;
                FND_OUT=0x00;
                sleep(500);
                for(count=06>=count; count++)
                {
                    LED_OUT=~LED_OUT;
                    FND_OUT=~FND_OUT;
                    sleep(200);
                }
                sleep(2000);
                FND_OUT=0;
                stage++;
                break;          // on/off 6회 반복 끝나면 두더지 생성 금지!
            } 
            FND_OUT = score+score1;  // 점수 표시
            LED_OUT = 0xff;      // 두더지 숨기(LED off)
            sleep(1000);      // 1초 지연
        }
        if((25<=count)||(100>=delay_ms))  // 두더지(LED)가 25번 생성안되면 게임 종료(100점미만)    
        {  
            uart_send_string(endscore, sizeof(endscore));
            uart_send_byte(stage+48);
            uart_send_string(endstage, sizeof(endstage));
            uart_send_byte((score1>>4)+48);
            uart_send_byte(score+48);
            GAME_SET(0);      // 게임 종료 메시지 전송!!
            GAME_SET(1);            // 게임 대기
        }
        uart_send_string(strclear, sizeof(strclear)); // 축하 메시지 전송
        delay_ms=delay_ms-200;      // 100점이면 게임 계속 실행(속도 점점 빨라짐)
    }
    return 1;
}

//================================================================//
//    여 러 함 수 들 모 아 놓 은 곳                               //
//================================================================//

/* 게임 스타트 & 일시정지 함수 */
void GAME_SET(char set)
{
    key=0;
    fnd=0;
    one=0;
    ten=0;
    LED_OUT=0xff;
    delay_ms=1000;
    if(set == 1)
    {
        while(1)  //  난수 함수 시작점을 다르게하기 위한 무한 루프
       {
        for(count=08>count; count++)
        {
                LED_OUT=~(1<<count);
          delay(200);    
            srand((unsigned int)g_elapsed_time);  // 난수 발생 함수
            
                if(5==fnd)  // 아무 스위치가 눌려지면 두더지 게임 시작
          { 
            for(count=08>=count; count++) // 시작전 LED 8번 루프
            {
              LED_OUT=~(1<<count);
              sleep(200);
            }
            LED_OUT=0x00;
            FND_OUT=0x00;
            for(count=51<=count; count--) // 게임 시작 카운트 5~0
            {
              LED_OUT=0xff;
              sleep(500);
              LED_OUT=0x00;
              FND_OUT=count+(count<<4);
              sleep(500);
            }
            LED_OUT=0xff;
            FND_OUT=0x00;
            sleep(2000);  // 게임 시작전 2초 지연
                 break;        // 게임 시작을 위해 무한루프 브레이크
          }
        }
        if(5==fnd)  //  스위치값 초기화
        {
          fnd=0;            
          break;
        }
      }
        unsigned char strs[] = "******** [";
        uart_send_string(strs, sizeof(strs));
        uart_send_byte(stage+48);
        unsigned char strst[] = "]Stage Game Start *******\r\n";
        uart_send_string(strst, sizeof(strst));
    }

    else
    {
        unsigned char str1[] = "\r\n************ Game  Over ***********\r\n";
      uart_send_string(str1, sizeof(str1));
    }
  asm("NOP");
}

/* 스위치 입력 대기 딜레이 */
void delay(unsigned int speed)
{
    unsigned char str1[]="[LED : ";
    unsigned char str2[]="]_[Switch : ";
    unsigned char str3[]="] OK\r\n";
    unsigned char str4[]="] Fail\r\n";
    unsigned char keys;
    unsigned char leds;
    g_elapsed_time=0;
    while(g_elapsed_time<speed)
    {
        LED_Match = LED_OUT&LED_Match;
        KEY_Match = KEY_IN&KEY_Match;
        if((key==0&& (0xff != KEY_Match))  // 아무키 누르면 시작
        {
            fnd=5;                        // fnd변수에 5대입            
            break;
        }

        if((key==5)&&(LED_Match == KEY_Match)) // LED와 스위치가 같으면 실행
        {
            leds=bit_match(~LED_Match);
            SW_loop();                          // 스위치 땔때까지 대기
            if(fnd==10)                         // 7+8번 SW 눌러지면 브레이크
            {
                break;                         
            }

            fnd=2;                        // fnd변수에 2대입
            uart_send_string(str1, sizeof(str1));
            uart_send_byte((leds)+49);
            uart_send_string(str2, sizeof(str2));
            uart_send_byte((leds)+49);
            uart_send_string(str3, sizeof(str3));
            sleep(20);
            break;
        }

        else if((key==5)&&(LED_Match != KEY_Match)&&(0xff != KEY_Match))
        {
            leds=bit_match(~LED_Match);
            keys=bit_match(~KEY_Match);
            SW_loop();                          // 스위치 땔때까지 대기
            if(fnd==10)                         // 7+8번 SW 눌러지면 브레이크
            {
                break;
            }

            fnd=3;                        // fnd변수에 3대입
            uart_send_string(str1, sizeof(str1));
            uart_send_byte((leds)+49);
            uart_send_string(str2, sizeof(str2));
            uart_send_byte((keys)+49);
            uart_send_string(str4, sizeof(str4));
            sleep(20);
            break;
        }
    }
}

/* 스위치 누르고 있을 경우 무한 루프 */
void SW_loop(void)
{
    while(1)
    {
        if(0xff == KEY_IN)  // 무한 루프 브레이크
        {
            uart_send_byte(ten+48);     // 10의 자리 통신 전송
            uart_send_byte(one+48);     //  1의 자리 통신 전송
            uart_send_string(strnum, sizeof(strnum));   // 게임 글자 통신 전송
            break;
        }
        if(KEY_IN == 0x3f)  // 7+8번 SW : 다음탄으로 넘김
        {
            fnd=10;      // fnd변수에 10대입
            break;
        }
    }


/* bit 검사 */
char bit_match(char cnum)
{
    char cnt;
    char temp;

    for(cnt=07>cnt; cnt++)
    {
        temp=(cnum&(1<<cnt))/(1<<cnt);
        if(1==temp)
        {
            return cnt;
        }
    }
    return cnt;
}

/* 직렬 포트 통신 송신 함수 */
void uart_send_byte(unsigned char byte)
{
  while (!(UCSR1A&(1<<UDRE)));  // 전송 버퍼가 비었을 때 까지 대기
  UDR1 = byte;  // 문자 1개씩 전송
}

/* 전체 문자를 전송하기 위한 함수 */
void uart_send_string(unsigned char *str, unsigned char len)
{
  int i;
  for(i=0; i<len; i++)
  {
    if(! str[i])    // 문자열 전송을 끝냄
    {
      break;
    }
    uart_send_byte(*(str+i));
  }
}

/* 직렬 통신 포트 1번 설정 함수 */
void init_USART1(void)
{
  UBRR1L = (unsigned char)BAUD_RATE_L;
  UBRR1H = (unsigned char)BAUD_RATE_H;  
  UCSR1C = (0<<UPM1)|(0<<UPM0)|(0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);
  UCSR1B = (1<<TXEN)|(1<<RXEN)|(0<<UCSZ2);
}

/* LED포트 초기화 설정 함수 */
void init_PORT(void)
{
  LED_DDR = 0xFF;  // PORTF 출력 설정
  LED_OUT = 0xFF;  // PORTF 초기화  
  FND_DDR = 0xFF; // PORTE 츨력 설정
  FND_OUT = 0x00// PORTE 초기
  DDRC    = 0x00// PORTC 입력 설정 (SW)
}

/* 타이머 설정 함수 */
void init_TIMER(int timers)
{
  TIMSK=(1<<timers);
}

/* Timer0 초기화 설정 함수 */
void init_TC0(void)  
{
  //TCCR0 = 0x0D;  // TCCR0 CTC모드 설정 / 분주비 설정
  TCCR0 = 1<<2|0<<1|0<<0// 이런식으로 설정도 가능함
}

/* 딜레이 함수 */
void sleep(unsigned int elapsed_time)
{
  g_elapsed_time=0;
  while(g_elapsed_time<elapsed_time)
  {
  }
}

/*     시그널 함수  */
/*  비교매치 인터럽트  */
void __vector_15(void)
{
  g_elapsed_time++;
    LED_Match=0xff;
    KEY_Match=0xff;
}