여기에서는 이전 포스트에 이어서 포트를 이용한 LED 실습을 진행한다.
LED실험 2
두 번째 LED실험도 앞의 실험과 비슷하다. 이번에는 다음과 같은 순서로 1→2→3→4→1→2→3→4→1→… 계속 시차를 두고 반복하는 실험이다.
[표 1] 두 번째 LED 실험
순서 | LED상태 | 이진수 | 16진수 |
1 | ●●●○○●●● | 0b00011000 | 0x18 |
2 | ●●○●●○●● | 0b00100100 | 0x24 |
3 | ●○●●●●○● | 0b01000010 | 0x42 |
4 | ○●●●●●●○ | 0b10000001 | 0x81 |
프로그램 예는 다음과 같다.
#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
#include "Am8USBasp.h"
int main(void) {
uchar ucA, ucaRelay[4] = {0x18, 0x24, 0x42, 0x81};
InitAM8();
while(1) {
for (ucA=0; ucA<4; ucA++) {
LED(ucaRelay[ucA]);
_delay_ms(200);
}
}
}
이 예를 보면 typedef 명령어로 unsigned char형은 byte형으로 재정의하였으며 앞으로도 이것은 계속 사용할 것이다. 그리고 LED로 순차적으로 내보낼 데이터는 배열로 처리하였음을 눈여겨 보기 바란다.
LED실험 3
다음 [표 2]에 설명한 바와 같이 1→2→ … →13→14→1→2→ … 의 순서로 14가지 패턴을 반복하면 마치 LED한개가 좌우로 왕복하는 듯이 보이는 예제이다. 이 세 번째 LED실험은 앞의 것들과 달리 조금 복잡해 보인다.
[표 2] 세 번째 LED 실험
순서 | LED상태 | 이진수 | 16진수 |
1 | ●●●●●●●○ | 0b00000001 | 0x01 |
2 | ●●●●●●○● | 0b00000010 | 0x02 |
3 | ●●●●●○●● | 0b00000100 | 0x04 |
4 | ●●●●○●●● | 0b00001000 | 0x08 |
5 | ●●●○●●●● | 0b00010000 | 0x10 |
6 | ●●○●●●●● | 0b00100000 | 0x20 |
7 | ●○●●●●●● | 0b01000000 | 0x40 |
8 | ○●●●●●●● | 0b10000000 | 0x80 |
9 | ●○●●●●●● | 0b01000000 | 0x40 |
10 | ●●○●●●●● | 0b00100000 | 0x20 |
11 | ●●●○●●●● | 0b00010000 | 0x10 |
12 | ●●●●○●●● | 0b00001000 | 0x08 |
13 | ●●●●●○●● | 0b00000100 | 0x04 |
14 | ●●●●●●○● | 0b00000010 | 0x02 |
이번 프로그램을 이전 실험과 같이 14개의 데이터를 포트에 순차적으로 내보내는 식으로 프로그램을 작성할 수도 있으나 그렇게 하면 너무 비효율적인 프로그램이 된다. 그래서 비트이동 연산자와 반복문을 이용하면 좀 더 간단하게 프로그램이 가능하다. 프로그램 예는 다음과 같다.
#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
#include "Am8USBasp.h"
typedef enum DIR {UP, DOWN} EDIR;
int main(void) {
uchar ucLed = 1;
EDIR eDir = UP;
InitAM8();
while(1) {
if (eDir == UP) {
ucLed <<= 1;
if (ucLed == 0x80)
eDir = DOWN;
} else { // if (eDir == DOWN)
ucLed >>= 1;
if (ucLed == 0x01)
eDir = UP;
}
LED(ucLed);
_delay_ms(200);
}
}
LED실험 4 : LED탑 쌓기
마지막으로 아래와 같은 패턴을 보여주는 프로그램을 작성해보자. 벽돌로 하나씩 탑을 쌓는 것처럼 보여서 ‘LED 탑 쌓기’실험이라고 이름을 붙여 보았다.
[표 3] 네 번째 LED 실험
순서 | LED상태 | 이진수 | 16진수 |
1 | ○●●●●●●● | 0b01111111 | 0x7F |
2 | ●○●●●●●● | 0b10111111 | 0xBF |
3 | ●●○●●●●● | 0b11011111 | 0xDF |
4 | ●●●○●●●● | 0b11101111 | 0xEF |
5 | ●●●●○●●● | 0b11110111 | 0xF7 |
6 | ●●●●●○●● | 0b11111101 | 0xFB |
7 | ●●●●●●○● | 0b11111110 | 0xFD |
8 | ●●●●●●●○ | 0b11111110 | 0xFE |
9 | ○●●●●●●○ | 0b01111111 |
|
10 | ●○●●●●●○ | 0b10111111 |
|
11 | ●●○●●●●○ | 0b11011111 |
|
12 | ●●●○●●●○ | 0b11101111 |
|
13 | ●●●●○●●○ | 0b11110111 |
|
14 | ●●●●●○●○ | 0b11111101 |
|
15 | ●●●●●●○○ | 0b11111110 |
|
16 | ○●●●●●○○ | 0b01111111 |
|
17 | ●○●●●●○○ | 0b10111111 |
|
18 | ●●○●●●○○ | 0b11011111 |
|
19 | ●●●○●●○○ | 0b11101111 |
|
20 | ●●●●○●○○ | 0b11110111 |
|
21 | ●●●●●○○○ | 0b11111101 |
|
22 | ○●●●●○○○ | 0b11111110 |
|
⋮ | ⋮ | ⋮ |
|
이 실험은 이제 포트에 데이터를 순차적으로 내보내는 식으로는 프로그램이 거의 불가능하다. 이번에도 역시 비트이동연산자와 반복문을 조합하여 프로그램을 작성할 수 있다.
#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
#include "Am8USBasp.h"
int main(void) {
uchar ucaLEDTower[8] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F };
uchar ucled, uck, ucl;
InitAM8();
while (1) {
for (uck=0;uck<8;uck++) {
ucled = 0x80;
for (ucl=0;ucl<8-uck;ucl++) {
LED( ucled | ucaLEDTower[uck] );
_delay_ms(200);
ucled >>= 1;
}
}
}
}
위 프로그램은 길이는 짧지만 한 줄씩 읽어가면서 분석해 볼 여지가 있다. 다중 반복문을 사용하고 있는데 내부 반복문에서는 LED가 위에서 아래로 한 칸씩 떨어지는 것을 비트쉬프트 연산자로 처리하고 있으며 이 때 PORTB로 내보내는 데이터를 배열 byaLEDTower[]과 OR연산을 하여 마치 벽돌이 쌓여 있는 듯한 효과를 내는 것이다. 배열 byaLEDTower[]은 벽돌이 쌓인 모양의 데이터를 가지고 있다. 바깥 반복문에서는 떨어지는 루틴을 8번 반복하게끔 하는데 떨어지는 곳의 높이를 점차로 높인다.
이번 포스트에서는 LED를 이용하여 간단한 예제들을 살펴보았다. 독자가 C언어의 문법을 잘 숙지하고 있다면 어떻게 동작이 되는지 쉽게 분석해 볼 수 있을 것이다.
'하드웨어 > ATmega8(A)' 카테고리의 다른 글
ATmega8(A) 인터럽트(interrupt) 개요 (2) | 2015.06.22 |
---|---|
ATmega8(A) 7세그먼트 실험 (Part 1) (0) | 2015.06.20 |
ATmega8(A) 포트를 이용한 LED 실험 (part 1) (0) | 2015.06.16 |
ATmega8(A)의 포트(port) 개요 (0) | 2015.06.16 |
AVR의 EEPROM에 데이터 읽고 쓰기 (0) | 2015.06.15 |