ATmega2560으로 LED 깜빡이기
ATmega 시리즈는 ATMEL사에서 직접 설계한 AVR 프로세서를 사용하는 MCU로
8비트 구조로 설계되어있다.
ARM과 같이 롬라이터 없이 프로그램을 삽입할 수 있는 In-System Programmable Flash를 장착하고 있으며,
ARM의 SAM-BA보다 훨씬 사용하기 편리하다.
GNU에서 만든 GCC컴파일러인 WinAVR을 설치하고 그 Makefile만 가져다 코딩하면 될 정도로 사용이 무척 간편하다.
우선 WinAVR의 Makefile을 살펴보자.
43 # MCU name
44 MCU = atmega2560
47 # Processor frequency.
48 # This will define a symbol, F_CPU, in all source code files equal to the
49 # processor frequency. You can then use this symbol in your source code to
50 # calculate timings. Do NOT tack on a 'UL' at the end, this will be done
51 # automatically to create a 32-bit value in your source code.
52 # Typical values are:
53 # F_CPU = 1000000
54 # F_CPU = 1843200
55 # F_CPU = 2000000
56 # F_CPU = 3686400
57 # F_CPU = 4000000
58 # F_CPU = 7372800
59 # F_CPU = 8000000
60 # F_CPU = 11059200
61 # F_CPU = 14745600
62 # F_CPU = 16000000
63 # F_CPU = 18432000
64 # F_CPU = 20000000
65 F_CPU = 16000000
68 # Output format. (can be srec, ihex, binary) 실행파일 형식
69 FORMAT = ihex
수정해줄 부분은 44, 65라인의 MCU 명과 그에 맞는 클럭속도만 손봐주면 된다.
그리고 69라인에서 컴파일된 실행파일은 .hex파일인 것을 확인 할 수있다.
#define PORTA (*((volatile unsigned char *)0x22))// 데이터 출력시 사용하는 레지스터
#define DDRA (*((volatile unsigned char *)0x21))// 입출력 방향 지정 레지스터(1: 출력, 0: 입력)
#define PINA (*((volatile unsigned char *)0x20))// 데이터 입력시 사용하는 레지스터
int main()
{
volatile unsigned int uiCnt1; // int 크기 : 16bit (0 ~ 65535)
volatile unsigned int uiCnt2; // delay 루프를 위한 변수
DDRA = 0xFF; // PA0~PA7 모두 출력으로
PORTA = 0xFF; // PA0~PA7 출력값을 모두 HIGH로 지정
while(1)
{
// int가 16비트라 이중 for문으로 만들어 줌
for(uiCnt1 = 0; uiCnt1 < 10000; ++uiCnt1)
for(uiCnt2 = 0; uiCnt2 < 100; ++uiCnt2);
PORTA = 0; // ON : low가 되야 전압차가 생겨서 켜짐
for(uiCnt1 = 0; uiCnt1 < 10000; ++uiCnt1)
for(uiCnt2 = 0; uiCnt2 < 100; ++uiCnt2);
PORTA = 0xFF; // OFF : High - High가 되므로 OFF
}
while (1); // main() 종료 방지를 위한 코드
return 0;
}
위의 소스에서 define문으로 정의한 세 레지스터는 다음과 같은 기능을 한다.
#define PORTA(*((volatile unsigned char *)0x22))// PORTA의 주소
#define DDRA (*((volatile unsigned char *)0x21))// 입출력 방향 지정 레지스터(1: 출력, 0: 입력)
#define PINA (*((volatile unsigned char *)0x20))
PORTA 레지스터는 ATMEGA2560의 PORTA핀에서 데이터를 출력할 때 사용하는 레지스터로
주소는 0x22로 정의되어 있고 각 비트는 각 핀 번호를 제어한다.
ARM에서 PIO_CODR과 PIO_SODR의 두개의 레지스터로 각각 핀의 LOW,
HIGH를 설정하던 것과는 다르게
각 비트에 1을 대입하면 HIGH로 세팅되고(5V) 0은 LOW(0V)로 세팅된다.
DDRA 레지스터는 이름처럼 PORT A 핀의 데이터의 방향을 설정하는 레지스터로
1은 데이터 출력을, 0은 데이터 입력을 의미한다.
여기서 PORT A란 아래의 PA0~PA7번 핀을 모두 묶어서 말하는 것이다.
PINA 레지스터는 PA0~PA7 핀에서부터 데이터를 입력받을 때 사용하는 레지스터로 시작 주소는 0x20 이다.
DDRA = 0xFF; // PA0~PA7 모두 출력으로
PORTA = 0xFF; // PA0~PA7 출력값을 모두 HIGH로 지정
우선 LED를 점등시키려면 PA0~7번 핀을 출력으로 지정하고
PORTA의 값을 모두 HIGH로 세팅해준다.
// int가 16비트라 이중 for문으로 만들어 줌
for(uiCnt1 = 0; uiCnt1 < 10000; ++uiCnt1)
for(uiCnt2 = 0; uiCnt2 < 100; ++uiCnt2);
위의 시간 지연용 반복문은 ARM에서왕는 다르게 이중 for문으로 구성되어 있는데,
이는 주석에서처럼 int형으로 변수를 선언하더라도 8비트 MCU인 관계로 16비트로
인식되므로 그 표현한계가 0~65535 밖에 안된다.
그러므로 사람의 눈으로 인식할 정도의 시간을 끌려면 위와 같이 이중for문을 이용한다.
PORTA = 0; // ON : low가 되야 전압차가 생겨서 켜짐
......
PORTA = 0xFF; // OFF : High - High가 되므로 OFF
PORTA를 0으로 클리어하면 LOW로 세팅되서 전류가 흘러 LED를 켜는 역할을 하고
1로 세팅하면 HIGH가 되므로 전압들어오는 LED의 VCC와 GND의 전압이 같아지므로
전류가 흐르지 않아 LED는 켜지지 않는다.