거북이처럼 천천히

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

Embedded Programming/Atmega 128A 이것저것

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

유로 청년 2024. 6. 6. 13:08

 

6월 6일 현충일날, 쉬면서 ATmega 128 가지고 예전에 해보고 싶었던 거를 구현해 보았다.

 

 

1. 환경

  • PORT F에 LED (KB-1008SR) 연결
  • PORT D에 0~2핀에 버튼 연결

 

2. 동작

  • PD 0 : 첫 번째 버튼, PD 1 : 두 번째 버튼, PD 2: 세 번째 버튼 으로 설정
  • PD 0 : Low-level interrupt, PD 1 : Falling-edge interrupt, PD 2 : Rising-edge interrupt 를 각각 감지
  • PD 0 버튼을 누르면 0핀부터 3핀으로 LED 빛이 accumulation 된다.
  • PD 1 버튼을 누르면 7핀부터 4핀으로 LED 빛이 accumulation 된다.
  • PD 2 버튼을 누르면 누적되었던 LED들이 점차 사라진다.

 

3. 구현 영상

 

 

 

 

 

4. 소스 코드

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

// Substitute Constant.
#define BUTTON_DDR			DDRD
#define LED_DDR				DDRF
#define LED_PORT			PORTF
#define TIME				300

// Global Variable.
static uint8_t accumulation = 0x00;
static uint8_t is_it_turn_on_LED_right = 0;
static uint8_t is_it_turn_on_LED_left = 0;

// ISR (Interrupt Service Routine)
ISR(INT0_vect) {	
	for(int i=3; i>=0; i--) {
		for(int j=0; j<=i; j++) {
			LED_PORT = accumulation | (0x01<<j);
			_delay_ms(TIME);
		}
		
		accumulation |= (0x01<<i);
	}
	
	is_it_turn_on_LED_right = 1;
}

ISR(INT1_vect) {
	for(int i=3; i>=0; i--) {
		for(int j=0; j<=i; j++) {
			LED_PORT = accumulation | (0x80>>j);
			_delay_ms(TIME);
		}
		
		accumulation |= (0x80>>i);
	}
	
	is_it_turn_on_LED_left = 1;
}

ISR(INT2_vect) {
	for(int i=0; i<4; i++) {	
		for(int j=i; j>=0; j--) {
			accumulation &= ~(0x01<<j | 0x80>>j);
			
			if(j>0) {
				if(is_it_turn_on_LED_right) accumulation |= (0x01<<(j-1));
				if(is_it_turn_on_LED_left) accumulation |= (0x80>>(j-1));
			}
			
			LED_PORT = accumulation;
			_delay_ms(TIME);
		}
	}
	
	is_it_turn_on_LED_right = 0;
	is_it_turn_on_LED_left = 0;
}

// Function prototype.
void init_button();
void init_LED();

// Main method
int main(void){
    init_button();
	init_LED();
	
	// 전역 인터런트 활성화
	sei();
	
	// EICRA = External Interrupt Control Register A
	//       = INT 0 ~ 3까지의 핀에서 "어떤 Interrupt를 감지할 것인가?"를 결정
	//       = INT0 : Low-level, INT1 : Falling edge, INT2 : Rising edge.      
	//       = ob0011 1000
	EICRA |= (1<<ISC21 | 1<<ISC20 | 1<<ISC11);
	
	// EIMSK = External Interrupt Mask Register 
	//       = "어떤 핀에서 Interrupt를 감지할 것인가?"를 결정
	//       = ob0000 0111
	EIMSK |= (1<<INT2 | 1<<INT1 | 1<<INT0);
	
	while(1) {
		
	}
}

// Initialization for button.
void init_button() {
	// PORT D 의 0핀, 1핀, 2핀에 버튼 연결.
	BUTTON_DDR &= ~(1<<DDD0 | 1<<DDD1 | 1<<DDD2);
}

// Initialization for LED.
void init_LED() {
	// PORT F 에 LED 연결.
	LED_DDR = 0xff;
	
	// PORT F 에 연결된 LED 초기 설정
	LED_PORT = 0x00;
}