본문 바로가기

AVR

[AVR] 2. ATmega128A 버튼 제어

////////////
//main.c//
////////////

#if 1
#define F_CPU 16000000UL
#include <avr/io.h>
#include "button.h"

extern int get_button();  // extern : 내 화일에 있지 않고 다른 화일에 있음을 알림,
extern void init_button();

int button1_state = 0;  // 초기 상태는 버튼이 off된 상태에서 출발

int main(void)
{
	DDRA = 0xff;		//LED포트는 출력모드
	init_button();		//버튼 레지스터 초기화 함수
	PORTA = 0x00;
	
	while(1)
	{
		if(get_button(BUTTON1))		//버튼 1(PD4)을 누르면
		{
			if(!button1_state)	//홀수번째 눌렀을 때
			{
				PORTA |= (1 << 7 |1 << 6 |1 << 5 |1 << 4);	//PA4~7포트 LED 출력	
			}
			
			else	//짝수번째 눌렀을 때
			{
				PORTA = 0x00;		//LED ALL OFF
			}
			button1_state = !button1_state;		//버튼 1 플레그 변경
		}	
	}
}
#endif


////////////
//button.c//
////////////


#include "button.h"
int get_button(int button);
void init_button();

void init_button()
{
	BUTTON_DDR &= ~(1 << BUTTON1);
}
// 0 : 버튼을 누르지 않은 상태
// 1 : 완전히 버튼을 누른 상태
int get_button(int button)
{
	static unsigned char prev_state[8]={0, 0, 0, 0, 0, 0, 0, 0};
	//함수를 빠져 나왔다 다시 진입해도 전역변수처럼 변화된 값 그대로 유지
	unsigned char current_state; // 현재 버튼 상태
	
	current_state = BUTTON_PIN & (1 << button); // 00010000
	
	if( prev_state[button] == 0 && current_state !=0)
	{
		_delay_ms(60); //noise가 지나가기를 기다림
		prev_state[button]=1; //처음 누른 상태가 아님을 기다리는 의미에서
		//prev_state를 1로 set
		return 0;		//아직 진짜로 눌러진 상태가 아님
		//지금은 noise 상태임
	}				//버튼을 눌렀다 땐 상태
	else if(prev_state[button] == 1 && current_state == 0)
	{
		prev_state[button] = 0;
		return 1; //완전히 스위치를 눌렀다 땐 것으로 인정
	}
	
	return 0; //아직 완전히 스위치를 올렸다 때지 않은 상태
}


////////////
//button.h//
////////////

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

#define LED_DDR  DDRA  // LED_DDR로 설정을 하면 compiler가 DDRA로 바꿔준다.
#define LED_PORT PORTA // PORTA에 출력
#define BUTTON_DDR DDRD
#define BUTTON_PIN  PIND  // PORD값을 읽어 들이는 register
// 1: 5v 0: 0v
#define BUTTON1  4   // PORTD.4
#define BUTTON2  5   // PORTD.5
#define BUTTON3  6   // PORTD.6

<회로 구성>

PA의 4~7에는 LED, PD의 4에는 SW1를 연결해 줌

 

<코드 분석>

1. button.h 헤더파일을 통해 코드 가독성을 높이기 위해서 각 포트와 넘버에 이름을 부여

 

2. button.c 파일에서는 get_button(int button)와 init_button() 함수를 구현

 2-1 get_button(int button)

      (1) 함수에 입력된 버튼 번호에 해당하는 버튼 상태를 읽어옵니다.

      (2) 버튼이 이전에 눌리지 않은 상태이고, 현재 버튼이 눌린 상태라면, 버튼 누름에 대한 Noise를 방지하기 위해 60ms의 시간을 기다립니다.

      (3) 버튼 누름에 대한 Noise 시간이 지나면, 이전 버튼 상태 배열(prev_state)의 입력된 버튼 번호에 해당하는 값을 1로 변경하고, 0을 반환합니다. 이는 버튼이 아직 눌리지 않은 상태이나, 눌리려는 상태임을 나타냅니다.

      (4) 버튼이 이전에 눌려진 상태이고, 현재 버튼이 눌리지 않은 상태라면, 이전 버튼 상태 배열(prev_state)의 입력된 버튼 번호에 해당하는 값을 0으로 변경하고, 1을 반환합니다. 이는 버튼이 눌려있었으나, 떨어졌다는 것을 나타냅니                다.

      (5) 버튼이 이전에 눌리지 않은 상태이고, 현재 버튼도 눌리지 않은 상태라면, 0을 반환합니다. 이는 버튼이 아직 눌리지 않은 상태임을 나타냅니다.

   2-1. init_button()에서는 PIND에서는 SW를 누를 때, 값을 읽어야하므로 핀 D의 방향을 입력상태로 만듦

 

3. 메인에서는 if문에서 get_button함수를 이용하여 LED를 제어함

 

<실행 결과>

SW1을 처음 누를 때는 5~8번 째 LED ON, 다음 PUSH 동작에는 꺼짐. 버튼을 누르면 계속 반복