BASIC4MCU | 질문게시판 | 답변 : ATmega128 : 7seg, Switch, LED, USART를 이용한 게임기
페이지 정보
작성자 master 작성일2022-12-17 10:30 조회3,034회 댓글0건본문
1. 하이퍼 터미널으로 char를 출력하는데요, 디바이스에 코드를 쓸 때 하이퍼 터미널에 무작위 char가 출력됩니다.
디바이스에 프로그래밍되면 원하는 매뉴얼 코드가 출력되긴 하는데, 쓰기 전까지는 계속 char가 출력돼요..
128의 ISP는 PE0,PE1핀에 연결되서 프로그램을 주입하는데 이 핀들이 UART0 포트와 동일해서 발생하는 현상입니다.
뭐가 잔뜩 뜨는 것이 문제가 된다면 UART1을 사용하세요
//
2. mode=0의 두더지 게임을 실행하면 LED가 켜지지 않습니다. 이게 앞에서 문제가 생기는건지, 아니면 LEDon 함수에서 문제가 있는지 모르겠습니다.
3. 처음에는 Press07 함수를 while(!(swtich & 0x81)); 으로 스위치의 7,0번을 동시에 눌러야 다음으로 넘어갈 수 있도록 만들었었습니다.
0과 7 중 하나만 입력해도 다음으로 넘어가서 수정했었는데, 기존의 함수를 썼을 때 뭐가 문제였던걸까요?
코드가 복잡하면 무슨 생각으로 코드를 작성 했는지 코드만 보고 알 수가 없고, 분석이 안됩니다.
코드가 복잡하면 스스로 해결해야 합니다.
//
for(i; 30; i++)
이런 코드가 몇개 보이는 군요
for(i; i<30; i++)
조건식을 제대로 작성하셔야겠죠
for문을 잘 모른다면 c언어 기초서적을 다시 공부하세요(서적을 다 읽지말고 잘 모르는 문법만 공부하면 됩니다.)
//
while((n&m)==1){ // n과 m이 1이 될때까지 반복한다.(sw의 입력이 있었다면(sw1)n,(sw2)m이 set된다)
이 조건식도 "n과 m이 1이 될때까지"가 아니고 "n과 m이 1인 동안" 이므로 와일문은 실행되지 않겠습니다.//
TCCR0=0x02; TCNT0=0x38; TIMSK=0x01; // 1s 마다 인터럽트 발생 // 1초에 한번씩 인터럽터 실행(7seg 출력 함수가 1초마다 반복되게 하기 위함)
0x38은 56인데 위 설정은 100us 인터벌의 설정입니다.어떻게 1초가 될 수 있다고 생각하는지 모르겠고if(Init7seg==1)seg_Hello(); // 메뉴창:7seg_Hello else seg(); // 메뉴창 아닐때에는 7seg함수를 따른다.이100us주기의 인터럽트 안에서 20ms이상 걸리는 코드를 실행하면 메인함수가 실행되지 못합니다.
인터럽트안에서 딜레이를 실행하면 좋은 방법이 아닙니다.
그 것 때문에 코드에서 cli()와 sei()를 남발하고 있습니다.
보통은 메인초기 설정후에는 건드릴 일이 거의 없습니다.
//
#define F_CPU 16000000UL #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include <stdlib.h> #include <math.h> // uint8_t FND_TABLE[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //0 to 9 uint8_t LEDnum; int data1=0; // 7seg의 왼쪽 2개의 LED 데이터 & SW1의 점수 int data2=0; // 7seg의 오른쪽 2개의 LED 데이터 & SW2의 점수 int Init7seg=1; // 메뉴창에서 1이 되는,7seg의 제어를 위한 변수 int mode=0; // Init7seg=0일 때 7seg의 게임 선택을 위한 변수 int Selected=0; // Game 선택 완료되면 1이 되는 변수,Game이 끝나면 0이 된다. int Score1=0,Score2=0; uint16_t RandTime; //--------------------uart0 송신 설정------------------------- void U0_TX(char ch){ if(ch=='\n')ch='\r'; // 개행문자 처리 while(!(UCSR0A&0x20)); UDR0=ch; } // void U0_STR(char *s){ while(*s)U0_TX(*s++); } //------------------------------------------- void Random(){ LEDnum=(char)(rand()%8); RandTime=rand()%4000; } // LED가 켜지는 시간범위: 0.5s~4.5s가 되도록한다. // void LEDon(){ PORTB=(char)(pow(2,LEDnum)+0.001); } // LEDnum에 해당하는 비트의 LED가 켜짐 // ISR로 인해 버튼의 스위치 입력이 무시될 것 같아 인터럽트 중지 //------------------------------------------- void Count3(){ int i; for(i=0;i<3;i++){ PORTA=FND_TABLE[3-i]; PORTC=~0x08; _delay_ms(1000); } // 첫째자리에 3,2,1가 차례대로 표시됨. & cli();를 사용하여 인터럽트 루틴이 실행되지 않는다. } //------------------------------------------- void GetScore(){ int i=0; while(i==1){ if (PIND==LEDnum){ Score1++; data1=Score1; PORTB=0; i=1; } //LED를 끈다. //while의 조건문이 충족되어,GetScore 함수가 끝난다. else if(PINE==LEDnum){ Score2++; data2=Score2; PORTB=0; i=1; } } sei(); // 득점하면 7seg에 점수가 업데이트 되며 켜진다. 짧은 순간 꺼지는 것이므로 큰 영향이 없을 것 같다. } //------------------------------------------- void Game1(){ int i,t; for(i=0;i<30;i++){// 30회 LED를 On시키면 게임이 끝난다. Random(); for(t=0;500+RandTime;t++){ _delay_ms(1); } //_delay_ms(RandTime); 이 되지 않아 사용 LEDon(); GetScore(); } } //------------------------------------------- void Game2(){ int n=0,m=0,time=0,t1=0,t2=0; Count3(); // 7seg에서 3초 카운트다운한다. count3 함수가 끝나면 cli()로 인해 인터럽터가 실행되지 않아 7seg에 아무것도 출력되지 않는다. PORTA=0; while((n&m)==1){ // n과 m이 1이 될때까지 반복한다.(sw의 입력이 있었다면(sw1)n,(sw2)m이 set된다) time++; _delay_ms(1000); // 1초가 지날때마다 time이 1씩 추가된다. // record time if(PIND==0x01){ t1=time; data1=t1; n=1; } if(PINE==0x01){ t2=time; data2=t2; m=1; } } // 끝나고 data1,data2가 업데이트 되면서 7 seg에 각자가 몇초에 버튼을 눌렀는지 뜨게 된다. } //------------------------------------------- void menu(){ mode=0; data1=0; data2=0; Init7seg=1; Selected=0; Score1=0; Score2=0; // 모두 초기 설정으로 돌아간다. } // void WhichGame(){ Init7seg=0; // Menu화면에서 넘어감. Hello가 뜨지 않고 7seg함수로 7seg LED가 제어된다. while(!(PIND&0x80)){ // 0,7을 동시에 누르기 전까지는 WhichGame함수가 끝나지 않는다. if(PIND&0x01){ mode^=1; } // sw1의 0번 스위치로 mode를 바꾼다. data2=mode; // data2를 업데이트하여 7seg의 우측 2개 LED에 몇 번 mode인지 뜬다. } } // void Loading(){ cli(); data1=0; data2=0; Selected=1; Press07(); sei(); } // sw1에서 07을 눌러 7seg를 다시 출력한다. // void Press07(){ while(!(PIND&0x80)); } //sw1의 7,0번 비트가 1이 되어야 다음으로 넘어감. // void StartGame(){ if(mode==0)Game1(); else Game2(); } // //------------------------------------------- ISR(TIMER0_COMP_vect){ // 1ms static char c=0; PORTC=0xFF; if(Init7seg){ // Hello switch(c){ case 0: PORTA=0b01110110; break; // H case 1: PORTA=0b01111001; break; // E case 2: PORTA=0b00110110; break; // ll case 3: PORTA=0b00111111; break; // O } } else{ // switch(c){ case 0: PORTA=FND_TABLE[data1/10]; break; // 1000의 자리 case 1: PORTA=FND_TABLE[data1%10]; if(Selected)PORTA|=0x80; break; // 게임 선택 전: 100의 자리 표시됨.// 게임 선택 후 : 100의 자리 와 점이 표시됨. case 2: PORTA=FND_TABLE[data2/10]; break; // 10의 자리 case 3: PORTA=FND_TABLE[data2%10]; break; // 1의 자리 } } PORTC=~(1<<c); if(++c>3)c=0; } //------------------------main------------------ void main(){ DDRD=0x00; // SW1(Player1) DDRE=0x00; // SW2(Player2) DDRB=0xFF; // 8 LED DDRC=0xFF; // 7seg LED control connector DDRA=0xFF; // 7seg LED data connector DDRG=0xFF; // USART UCSR0B=0x18; UBRR0L=25; // baudrate=38400 U0_STR("Manual:\n1. Press0,7 if you want to play games\n "); // 하이퍼 터미널 창으로 설명서 출력 TCCR0=0x0D; OCR0=124; TIMSK=2; //16000000/128/(1+124),1ms sei(); while(1){ menu(); Press07(); WhichGame(); Loading(); Press07(); StartGame(); _delay_ms(5000); // 게임이 끝나고 5초 후에 다시 while문이 시작된다. } }
댓글 0
조회수 3,034등록된 댓글이 없습니다.