Embedded 실습/ATmega 2560

ATmega2560으로 LED 깜빡이기

중동콜링 2013. 5. 29. 00:11

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의 두개의 레지스터로 각각 핀의 LOWHIGH를 설정하던 것과는 다르게 

각 비트에 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는 켜지지 않는다.