티스토리 뷰
앞의 글 푸쉬 버튼과 LED제어 연동 1에서는 PB0에 연결되어 있는 푸쉬버튼을 누르면 다음 LED 패턴을 출력하는 방법에 대해서 설명하였다.
그러나 조금 아쉬운 느낌이 든다. 하나의 패턴을 출력한 후 푸쉬버튼을 누를때까지 아무런 동작을 하지 않고 프로그램이 멈추어 있는것처럼 보이기 때문이다.
그래서 이번글에서는 하나의 LED패턴을 무한히 반복 수행하다가 푸쉬버튼이 눌러지는 시점에 그 다음 LED패턴으로 넘어가는 기능을 구현해 보겠다.
하드웨어 구성은 앞의 글과 동일하므로 회로 수정없이 프로그램만 수정하면 된다.
이번 프로젝트의 핵심은 어느 한 LED 패턴안에서 한동작을 수행한 후 푸쉬버튼이 눌리워 졌는지 항상 모니터링을 하여야 한다. 그래야 버튼이 눌러졌을 때 즉시 다음 LED 패턴으로 넘어갈 수 있기 때문이다.
이러한 방법을 폴링(polling) 방식이라고 한다. 이와 대비되는 방식을 인터럽트(interrupt) 방식이라고 한다. 두가지 방법은 각각 장단점이 있으므로 어떤 방식이 적합한지를 잘 생각해서 구현하도록 한다.
이번 프로젝트는 비교적 간단하게 구현할 수 있다. 앞의 프로젝트 코드에서 _delay_ms()가 위치한 라인을 모두 check_button_press() 함수로 교체하면 된다.
check_button_press() 함수는 다음과 같이 구현한다.
int check_button_press(void)
{
int ret = 0;
if (portb->pin & PUSH_BTN)
ret = 0;
else
ret = 1;
_delay_ms(PATTERN_DELAY);
return ret;
}
check_button_press() 함수는 int 값을 반환하도록 되어 있다. 만약 버튼이 눌린 상태라면 1을 리턴하고, 버튼이 눌러지지 않으면 0을 리턴한다.
각각의 LED 패턴 함수는 다음과 같이 수정한다.
void led_pattern1(void)
{
int i;
while (1)
{
for (i=0; i<8; i++)
{
if (check_button_press())
return;
portd->port = 1 << i;
}
for (i=0; i<8; i++)
{
if (check_button_press())
return;
portd->port = 1 << (7-i);
}
}
}
void led_pattern2(void)
{
int i;
while (1)
{
for (i=0; i<8; i++)
{
if (check_button_press())
return;
portd->port = (1 << i) | (1 << (7-i));
}
}
}
void led_pattern3(void)
{
int i,j,val;
while (1)
{
val = 0;
for (i=0; i<4; i++)
{
val = (1 << (1<<(3-i)))-1;
for (j=0; j<i; j++)
{
val |= val << (1 << (4-i));
}
portd->port = val & 0xFF;
if (check_button_press())
return;
portd->port = (~val) & 0xFF;
if (check_button_press())
return;
}
}
}
void loop(void)
{
led_pattern1();
led_pattern2();
led_pattern3();
}
모든 LED 패턴 함수는 while(1)을 이용하여 무한루프로 동작되도록 한다. 그리고 그 안에서 PORT 레지스터에 값을 쓰기 전에 버튼이 눌러졌는지 확인하고 안눌러 졌으면 LED를 업데이트 한다. 만약 버튼이 눌려 졌으면 함수를 빠져 나가도록 만들어 다음 LED 패턴으로 들어가도록 한다.
이번글은 큰 어려움없이 이해할 수 있을것이다.
그러나 check_button_press() 함수에 대해서 좀더 생각해볼 점이 있다. 리턴값으로 돌려주는 값은 1 아니면 0이다. 즉 참과 거짓에 해당된다고 볼 수 있다. 이런 특징을 boolean 값이라고 부른다. 이러한 boolean값을 알기 위하여 조건문을 이용하는데, 조건문을 구현하는 방법이 몇가지 된다.
가장 간단한 방법이 이미 코드에 보이는 것처럼 if 문을 사용하는 것이다. 그러나 boolean 연산의 경우 좀더 간단히 표현할 수 있다.
ret = portb->pin & PUSH_BTN ? 0 : 1;
비교적 간단하게 코드를 수정하였다. 그러나 이보다 더 간단하게 만들수도 있다.
ret = !(portb->pin & PUSH_BTN);
위의 코드와 반대의 경우에 대해서도 설명하도록 하겠다. 다음과 같은 코드를 몇가지 방법으로 표현할 수 있다.
if (portb->pin & PUSH_BTN)
ret = 1;
else
ret = 0;
이 코드는 다음과 같이 조건연산자로 표현할 수 있다.
ret = (portb->pin & PUSH_BTN) ? 1 : 0;
그리고 더 간단하게는 다음과 같이도 할 수 있다.
ret = !!(portb->pin & PUSH_BTN)
만약 이번 프로젝트에서와 같이 check_putton_press()가 확실하게 boolean값을 리턴한다는 것이 명확하면 ret 값은 다음과 같이 단순화해도 된다.
ret = portb->pin & PUSH_BTN;
어차피 0인지 0이 아닌지만 판단하면 되므로 굳이 1의 값으로만 리턴할 필요가 없기 때문이다. 0이 아닌 값은 모두 참이므로 1이나 10이나 boolean 값은 모두 참이 되기 때문이다.
임베디드 시스템 프로그램에서는 이러한 boolean 조건에 따라 동작되는 경우가 많으므로 앞의 여러가지 코딩 기법을 잘 활용하면 코드가 단순해 질뿐 아니라 성능도 좋아지는 수가 있다.
'입문' 카테고리의 다른 글
LED 온도계 2 (5) | 2016.03.22 |
---|---|
LED 온도계 1 (6) | 2016.03.20 |
푸쉬 버튼과 LED제어 연동 1 (0) | 2016.03.12 |
LED 제어 - 부록 (3) | 2016.03.07 |
푸쉬 버튼 감지 2 (3) | 2016.03.06 |