본문 바로가기
코스웨어/15년 스마트컨트롤러

20150304-27번-임현수-회로기초 시험, ATmega128A LED켜기 실습

by 알 수 없는 사용자 2015. 3. 4.
728x90
반응형
■ 회로 기초

- 필기, 실기시험

■ 시스템 제어

ATmega128 데이터시트

우리는 메모리 A모드를 사용한다.

코딩할때 I/O 레지스터를 사용한다. 20번지 아래는 건드리지 않는다.
즉 0020번지~ 00FF번지만 사용하면 된다.

그런데 레지스터가 왜 메모리안에 있을까? 사실은 그림만 같이 그려놓은 것이다.
(ATmega128의 메모리는 4K인데 그림의 메모리크기를 계산해보면 4K를 넘어간다는 것을 보면 알 수 있다.)

32 Registers 부분은 GPR(General Purpose Register)들이다. 어셈블리로 접근은 할 수 있지만, 건드리지 않는다.

I/O 레지스터를 모두 더해보면 총 224개. 그렇다고 모두 사용하는 것들인가?
항구에 200자리잇다고 배가 다 들어차있는게 아닌것 처럼, 중간중간 비어있는 것도있다.(안쓰는 것도 있다.) 

Register Summary의 표에서 Address열의 괄호안에있는 주소를 참조하면 된다 - A모드

▲ PINF라는 레지스터는 Bit7~0까지 값이 들어 있으므로 1바이트(8비트) 레지스터

▲ 반면 EECR이라는 놈은 3~0까지만 사용하므로 4비트 레지스터

12.4 Register Description에서 PINF를 찾아 살펴보면,



■ PA0를 사용해서 LED 켜기 실습

◀ LED의 다리긴쪽은 +극, 짧은쪽은 -극

LED의 다리길이가 (긴쪽이 잘려서)같아져버리면 극성을 못알아본다
그럴때는 어떻게 아느냐?
매의 눈으로 안을 들여다 보면 머리가 큰쪽과 작은쪽이 사선으로 나뉘어져있다.
머리가 큰쪽이 - 작은쪽이 +

 우리는 PA0 를 제어하여 LED를 켜고 끌 것이다.




위의 논리를 바탕으로 AVR에서 5V또는 0V의 전압을 내보내서 LED를 제어한다. 이제 코딩으로 2단계를 거쳐야한다.
  1. 레지스터 DDRA($3A)를 제어해서 PA7~PA0 각각을 입력으로 쓸거냐 출력으로 쓸거냐를 결정(0이면 입력, 1이면 출력)
  2. 레지스터 PORTA($3B)를 제어해서 출력 전압을 0V로 보낼 것이냐 5V로 보낼 것이냐를 결정(0이면 0V, 1이면 5V)
int main(void)
{
  *(volatile unsigned char*)0x3= 0x01// 레지스터가 1바이트니까 char.
                                         // 0000 0001 : PA0만 출력으로 쓰겠다.

  *(volatile unsigned char*)0x3= 0x00// 0V를 출력하겠다.          
                                         // 0000 0000 : PA7~PA0에 0V를 넣어주겠다.


  return 0;
}


결과 : PA0에 0V가 들어오니까 전위차에 의해 전류가 흐르고 LED가 켜진다.

volatile을 써야되는 이유 1.
휘발성데이터이니까 날라갈지도모르니까 빨리 써라, 재빨리 PA0를 출력용으로 만들어라.(기차표 예매하는 것 처럼 중복예매 방지)


■ PA0와 PA7을 이용해 LED2개 번갈아 깜빡이기 실습

반복문을 이용해서 LED 점등을 구현해야 되는데, 너무 빨라서 깜빡이는지 아닌지 구분할 수 없다.
그래서 중간중간에 다른작업(60,000 카운트)을 시켜서 LED가 껏다가 켜질 시간을 벌어준다.



#define DDRA (*(volatile unsigned char*)0x3A)
#define PORTA (*(volatile unsigned char*)0x3B) 
// 매크로를 사용하면 알아보기 쉽다.

int main(void)
{
  volatile unsigned int uiCnt; 
// 잔머리굴리지말고(최적화) 하나하나 카운트하라고
                               // volatile을 붙여줘야 한다.

  DDRA = 0x81;                 // 1000 0001 : PA7, PA0을 출력으로 쓰겠다.
  while(1)
  {
    for(uiCnt=0; uiCnt<60000; ++uiCnt); 
// volatile이 없으면 잔머리 굴려서
                                        // uiCnt를 60000으로 바로변경해버리는 경우가 발생
                                        // (알아서 최적화)

    PORTA = 0xFE;                       // 1111 1110 : PA0에 0V를넣어주겠다⇒ PA0만 켜진다

    for(uiCnt=0; uiCnt<60000; ++uiCnt);
    PORTA = 0x7F;                       // 0111 1111 : PA7에 0V를넣어주겠다⇒ PA7만 켜진다
  }

  return 0;
}

결과 : PA0만 켜짐
 ⇒ 60,000카운트 ⇒ PA7만 켜짐 ⇒ 60,000카운트 ⇒ PA0만 켜짐을 무한반복하며 LED가 번갈아 깜빡인다.

volatile을 써야되는 이유 2.
for문을 금새 빠져나가려는 잔머리를 굴리지마라.(최적화를 하지마라)

ATmega내에서 int는 2바이트이기 때문에 2^16(65,536)까지 표현할 수 있다는것을 염두해야한다.(그래서 60,000까지만 카운트했다)

for문의 간략화
for(){}; ⇒ for(); 

 ⇒ 


728x90