거북이처럼 천천히

LED 와 Button 가지고 놀기 - (2) 본문

Embedded Programming/Atmega 128A 이것저것

LED 와 Button 가지고 놀기 - (2)

유로 청년 2024. 6. 30. 21:55

Verilog을 공부하면서 머리 속에서 잊어버린 AVR에 대해서 다시 공부하기 위해 LED와 버튼을 이용한 게임을 만들었다. 게임은 간단하다. 두 명의 플레이어가 두 개의 버튼을 가지고, 누가 먼저 4번을 누르는지를 대결하는 게임이다. 각각 Player1, Player2이 하나의 버튼을 할당 받고, 대결한다.

 

 

1. 환경

  • PORTD 0번째, 1번째에 Button 연결
    Button 0 : Player1, Button 1 : Player2
  • PORTF에 LED 연결
  • Button은 Pull-up 저항과 함께 Pull-up 형태 연결
  • 단, Interrupt 사용없이 PIN Register를 사용하여 버튼이 눌렀는지 여부를 확인

 

 

 

2. 동작

  • Player1은 PORTD0, Player1은 PORTD1의 버튼을 사용한다.
  • Player1은 0핀 → 3핀까지 LED를 밝히면 이기고, Player2은  7 → 1핀까지 LED를 밝히면 이긴다.
  • 이긴 Player에 대해서는 이겼음을 표시하기 위해서 LED를 깜박거림으로 표현한다.
  • LED에 들어와 있던 불들은 가장 안쪽부터 차례차례 없애서 초기화를 시킨다.

 

 

 

3. 구현 영상

 

 

 

 

4. 소스 코드

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

// Substitute constant.
#define LED_DDR			DDRF
#define LED_PORT		PORTF
#define BUTTON_DDR		DDRD
#define BUTTON_PIN		PIND
#define DELAY_TIME		150

// Function prototype
void init_BUTTON();
void init_LED();
void accumulation_LED(uint8_t* p_data, uint8_t player);
void print_the_winner_reset(uint8_t* p_data, uint8_t winner);
void reset_LED(uint8_t* p_data);

// Main method
int main(void) {
	init_BUTTON();
	init_LED();
	
	// Data of display.
	uint8_t data = 0x00;
	
	while(1) {
		// 버튼감지 
		// PIND0 : Player1의 버튼
		// PIND1 : Player2의 버튼
		if(!(BUTTON_PIN & 1<<PIND0)) accumulation_LED(&data, 1);
		else if(!(BUTTON_PIN & 1<<PIND1)) accumulation_LED(&data, 2);
		
		// 3번째 or 4번째 LED에 도달했는지 여부 확인
		// 3번쩨 도달 했다. == Winner1 승!
		// 4번째 도달 했다. == Winner2 승!
		if(data & 0x08) print_the_winner_reset(&data, 1);
		else if(data & 0x10) print_the_winner_reset(&data, 2);
	}
	
	return 0;
}

// Initialization of Button
void init_BUTTON() {
	BUTTON_DDR &= ~(1<<DDRD0 | 1<<DDRD1);
}

// Initialization of LED
void init_LED() {
	LED_DDR = 0xff;
}

// Accumulation of LED.
void accumulation_LED(uint8_t* p_data, uint8_t player) {
	if(player == 1) {
		uint8_t temp = *p_data & 0xf0;
		*p_data = *p_data<<1 | 0x01;
		*p_data |= temp;
	}else if(player == 2) {
		uint8_t temp = *p_data & 0x0f;
		*p_data = *p_data>>1 | 0x80;
		*p_data |= temp;
	}
	
	// 축적된 LED를 출력.
	LED_PORT = *p_data;
	_delay_ms(200);
}

// Print the winner and reset 
void print_the_winner_reset(uint8_t* p_data, uint8_t winner) {
	uint8_t mask = 0;
	
	if(winner == 1) mask = 0x0f;
	else if(winner == 2) mask = 0xf0;
	
	for(uint8_t i=0; i<10; i++) {
		LED_PORT = *p_data & ~mask;
		_delay_ms(100);
		LED_PORT = *p_data & mask;
		_delay_ms(100);
	}
	
	// Reset LED.
	reset_LED(p_data);
}

// Reset LED.
void reset_LED(uint8_t* p_data) {
	uint8_t left_LED = *p_data & 0xf0;
	uint8_t right_LED = *p_data & 0x0f;
	
	for(uint8_t i=0; i<=4; i++) {
		left_LED<<=1;
		right_LED>>=1;
		
		LED_PORT = left_LED | right_LED;
		_delay_ms(100);
	}
	
	*p_data = 0x00;
}