Miobot's Story


   AVR 기초 강좌 5-5 : 부록

(Tip4 Servo 제어)


Created Date: 2013.11.01
Modified Date: 2013.11.01
revision 1

키워드 : AVR, SERVO, WINAVR, AVR Studio

1. Servo Motor란?
DC Motor의 한 종류로서, PWM 제어 입력으로 특정 각 만큼 회전 후 위치를 유지하는 제어가 가능하다. 이는 모터 내부에 위치한 포텐셜미터(가변저항)를 포함한 컨트롤러가 PWM을 해석 후, 회전축에 연결된 포텐셜미터의 값이 그 와 같아질 때까지 모터를 회전시킴으로서 이루어진다.

일반적으로 0-180도(물론 360도 회전 가능한 것도 있다.) 회전하며, 이는 주기 20ms PWM 파형의 +Duty Pulse Width를 0.7-2.3ms 변화 시킴에 따라 비례, 제어된다.(1.5ms 에서 90도 회전)

 

(주의 : 주기 또는 최대, 최소 펄스폭의 크기가 위의 숫자에서 벗어날 수록 하모닉에 의한 소음, 진동 발생)

 

2. Servo Motor Control
우선, 개발환경은 Target : Atmega-128 16Mhz,  Compiler: WINAVR GCC,  IDE: AVR Studio 4.18 + SP3 임을 밝혀둔다.
 
20ms 주기의, 0.7-2.3ms 범위에서 펄스 폭을 가변 할 수 있는 코드를 작성해보자.
가장 손쉬운 방법은 TIMER0 오버플로우 인터럽트를 이용하는 방법이다. (TIMER에 관련된 설명은 앞서 표윤석님의 강좌 http://cafe.naver.com/openrt/14 를 참고하자.)
 
그럼 주기 20ms의 PWM을 0.1ms단위로 제어한다면 0.7-2.3까지 16단계로 밖에 제어가 되지 않는다. 좀더 세밀한 제어가 가능하려면 이보다 작은 단위로 제어가 이루어져야 한다. 20ms = 20,000us 이므로 10us 단위의 제어를 한다면 0.7-2.3ms → 700us-2300us. 160단계 제어가 가능해진다. 그렇다면 인터럽트의 주기는  10us 가 적당하겠다.
 
주파수 분주비 1을 사용할 경우, 1clk당 소요 시간(주기)은 1/16000000=0.0000000625초=0.0625us 이다.
0.0625×16=1us. 따라서 타이머가 16번 count에 1us가 소요되므로, 그 열 배인 160번 count에는 10us가 소요된다. 그렇다면 255-160+1=96(0x60)부터 160번 count하면, 159번 째 count값은 255, 160번 째 count에 오버플로우 인터럽트가 발생 할 것이다.(Timer0는 8bit, 0에서 2의 8제곱 - 1 까지 셀 수 있다.) 이 때 인터럽트서비스루틴 안에 1씩 증가하는 counter변수가 있다면, 그값이 70-230동안 High, 그 이 후 2000이 될 때까지 Low를 어디론가 출력하여, 서보의 입력으로 주면 될 것이다.
 
정리해보자면,
 
* 타이머 설정 : 주기 10us - 분주비 1, 카운트시작값 96(0x60)
 
* ISR(I nterrupt Service Routine )의 내용
1. 카운트시작값 96(0x60) 재설정.
2. 카운터 변수 +1
3. 카운터 변수의 값이 70-230이 될 때 까지 PORTA 0번 bit에 1 출력(임의의 사용가능한 아무 포트)
4. 그 이후 2000이 될 때까지 PORTA 0번 bit에 0 출력.
 
* main() : UART입력에 의해 펄스 폭을 가변하는 루틴 작성.
 
그럼 서보모터 제어 프로그램을 작성해보자.
3. 예제 코드
아래 코드의 1-7행의 주석은 위의 내용을 정리한 것으로 처음엔 define에 반영 사용해 왔으나 오실로스코프로 측정해 본 결과 오차가 발생함을 발견. 서보제어에는 문제가 없었지만, 측정값을 반영, 거의 오차없는 버젼을 아래 기록했음을 밝혀둔다.(오차범위 0.5% 이내) 
  1. // T_PWM : 20 ms
  2. // p_width : 0.7-2.3 ms
  3. // 20.0 ms = 10 us x 2000 ← PERIOD
  4. //  0.7 ms = 10 us x 70 ← MIN
  5. //  1.5 ms = 10 us x 150 ← 90˚
  6. //  2.3 ms = 10 us x 230 ← MAX
  7. // use timer0, uart1, PORTA
  8.  
  9. #include <stdio.h>             // 4 using printf()
  10. #include <avr/io.h>
  11. #include <avr/interrupt.h>
  12. #define PERIOD 1729           // T_pwm = 20 ms
  13. #define MAX 198               // MAX pulse width 2.3 ms
  14. #define MIN 60                // MIN pulse width 0.7 ms
  15. #define CENTER 129            // 90˚pulse width 1.5 ms
  16.  
  17. volatile unsigned int p_width = 0;
  18. volatile unsigned int duty = CENTER;
  19.  
  20. ISR(TIMER0_OVF_vect)
  21. {
  22.     TCNT0 = 0x60;            // (time/ 1 count)=0.0625 us, 0.0625 x 16 = 1us
  23.                              // 10us = 0.0625 x 16 x 10 = 0.0625 x 160
  24.      p_width++;         
  25.      if(p_width <= duty) PORTA |= 0x01; // output high until p_width = duty
  26.      else PORTA &= ~(0x01);             // output low until p_width = PERIOD
  27.  
  28.       if(p_width >= PERIOD) p_width = 0;
  29. }
  30.  
  31. void init_timer0(void)
  32. {
  33.      TCCR0 = 0x00; // stop
  34.      ASSR = 0x00;  // set async mode
  35.      TCNT0 = 0x60; // set count start from 96 to 255 + 1
  36.      TCCR0 = 0x01; // Precaler=1/1, 16,000,000/1=16000,000Hz T=1sec/16000,000=0.0625us
  37.                    // 0.0625us×16=1us, 10us=0.0625us×160
  38.      TCNT0 = 0xfe// after count twice, TIMER0 OVF
  39. }                                      
  40.  
  41. static int putch_uart1(char message, FILE *stream) // 4 using printf()
  42. {
  43.     if (message == '\n')
  44.     putch_uart1('\r', stream);
  45.     while((UCSR1A & 0x20) == 0x00);
  46.     UDR1 = message;
  47.     return 0;
  48. }
  49.  
  50. int getch_u1(void)
  51. {
  52.     while ((UCSR1A & 0x80) == 0);
  53.     return UDR1;
  54. }
  55.  
  56. void init_port(void)
  57. {
  58.     PORTA = 0x00; DDRA = 0x00; // Port A Initialize
  59.     PORTB = 0x00; DDRB = 0x00; // Port B Initialize
  60.     PORTC = 0x00; DDRC = 0x00; // Port C Initialize
  61.     PORTD = 0x00; DDRD = 0x00; // Port D Initialize
  62.     PORTE = 0x00; DDRE = 0x00; // Port E Initialize
  63.     PORTF = 0x00; DDRF = 0x00; // Port F Initialize
  64.     PORTG = 0x00; DDRG = 0x03; // Port G Initialize
  65. }
  66. void init_uart1(void)          // UART1 initialize. baud rate: 9600
  67. {                              // data: 8 bit, parity: Disabled
  68.     UCSR1B = 0x00;             // disable while setting baud rate
  69.     UCSR1A = 0x00;
  70.     UCSR1C = 0x06;
  71.     UBRR1L = 0x67;             //set baud rate lo
  72.     UBRR1H = 0x00;             //set baud rate hi
  73.     UCSR1B = 0x18;
  74. }
  75. void init_devices(void)
  76. {
  77.     cli();
  78.     init_port();
  79.     init_uart1();
  80.     init_timer0();
  81.     fdevopen(putch_uart1,0);        // 4 using printf();
  82.     TIMSK = 0x01;
  83.     sei();
  84. }
  85.  
  86. int main(void)
  87. {
  88.     unsigned int duty_ctrl = CENTER; // 90 degree
  89.     char ch;
  90.     init_devices();
  91.     DDRA = 0xff; // PortA Output
  92.     printf("\nServo Motor test....\n");
  93.     printf("type '<' or '>' to control servo\n");
  94.     while(1)
  95.     {
  96.         ch = getch_u1();
  97.         if((ch == '.') || (ch == '>'))   duty_ctrl++;
  98.         if((ch == ',') || (ch == '<'))   duty_ctrl--;
  99.         if(duty_ctrl >= MAX) duty_ctrl = MAX;
  100.         if(duty_ctrl <= MIN) duty_ctrl = MIN;
  101.         duty = duty_ctrl;
  102.         printf("duty : %3d\n", duty_ctrl);
  103.     }
  104. }

  지난  7월 한 달 윤석님의 이 강좌로 AVR에 대해 많이 배웠습니다.  핵심만 추려 설명한 강좌이다 보니, 그 당시 이런 예제는 타카페를 뒤져 참고했던 기억도 나고, 지금 서보모터를 만지느라 소스 찾아서 보다가 생각났을 때, 몇 자 적어 봅니다. 틈틈이 몇 가지 더 정리되는 대로 올려 보도록 하겠습니다.

 

End.

written by Ground Zero


이 저작물은 크리에이티브 커먼즈 저작자표시-비영리 3.0 Unported 라이선스에 따라 이용할 수 있습니다.


Posted by Miobot

AVR 기초 강좌

AVR 기초 강좌 5-4 : 부록 (Tip3 EEPROM 사용법) 


EEPROM


2013.01.01

 1. EEPROM 활용


처음에 AVR공부하면서 EEPROM의 소중함을 몰랐다. 왜냐하면 예전 8051처럼 EEPROM에 프로그램을 구워서 사용할 일이 없기 때문이다. ISP라는 강력한 기능에 눌려 현재 거의 사용을 안 하다가 개발 2년 만에 처음으로 내장 EEPROM을 사용해 보았다.
 
우선 사용하게 된 이유는 휴머노이드 로봇의 기본 자세를 EEPROM에 저장하기 위해서이다. 로봇의 동작을 넣기 전 초기에 기본자세를 잡아 EEPROM에 저장한 후 모션 에디팅을 하면 편하기 때문이다. EEPROM은 사용자의 특정한 데이타를 저장하기에 딱 맞는 멋진 녀석이다. 물론 ATmega128에는 4kByte의 eeprom이 들어가 있다.
 
자세한 내용은 소스를 참고해 보길 바란다. 참 쉽다~ 
 
참고로  EEPROM의 데이터를 사용하다가 ISP로 새로 프로그램을 다운로드하면 기존 EEPROM 데이타가 지워지는 경우가 있는데 이는 퓨즈비트 체크를 설정해야 된다. 자세한 내용은 [Tip1 락비트와 퓨즈비트 설정]를 참고해 주길 바란다.  (결론은 ...   EESAVE를 체크해야 한다.)

 2. EEPROM 실습


#include <iom128.h>
#include "../define.h"
#include "eeprom.h"
 
//------------------------------------------------------------------------------
//     ===== EEPROM_Write =====
//     :사용자가 지정된 주소의 eeprom에 지정한 데이타를 저장한다.
//------------------------------------------------------------------------------
void EEPROM_Write(U16 Address, U08 Data)
{
        while(EECR & (1<<EEWE));    // Wait for completion of previous write
       
        EEAR = Address;             // Set up address and data registers
        EEDR = Data;
 
        EECR |= (1<<EEMWE);         // Write logical one to EEMWE        
        EECR |= (1<<EEWE);          // Start eeprom write by setting EEWE
}
 
//------------------------------------------------------------------------------
//     ===== EEPROM_Read =====
//     :사용자가 지정된 주소의 데이타를 읽어봐 반환한다.
//------------------------------------------------------------------------------
U08 EEPROM_Read(U16 Address)
{
       
        while(EECR & (1<<EEWE));    // Wait for completion of previous write
       
        EEAR = Address;             // Set up address register
       
        EECR |= (1<<EERE);          // Start eeprom read by writing EERE
       
        return EEDR;                // Return data from data register
}


 [ 참고자료 ]


[1] Atmel Corporation, ATmega128(L) Datasheet, http://www.atmel.com/devices/ATMEGA128.aspx?tab=documents


End.

written by Yoonseok Pyo
http://robotpilot.net/
http://cafe.naver.com/openrt


Posted by Miobot

AVR 기초 강좌

AVR 기초 강좌 5-3 : 부록 (Tip2 CSTACK / RSTACK / HEAP) 


CSTACK / RSTACK / HEAP 

2013.01.01

 1. 이건 무슨 에러야?


▶ 질문

: ATmega128 프로그래밍 도중 사용되는 변수가 많아서 이런 에러 메시지가 뜬 적이 있었다.

 

Error[e16]: Segment NEAR_Z (size: 0x2da align: 0) is too long for segment definition. At least 0x270 more bytes needed. The problem occurred while processing the segment placement 

command "-Z(DATA)NEAR_I,NEAR_Z=_..X_SRAM_BASE-_..X_SRAM_END,_..X_EXT_SRAM_BASE:+_..X_EXT_SRAM_SIZE", where at the moment of placement the available memory 

ranges were "DATA:1096-10ff,DATA:10ff--1"

   Reserved ranges relevant to this placement:

   DATA:100-13f         CSTACK

   DATA:140-15f         RSTACK

   DATA:160-10ff        NEAR_I

 

그래서, CSTACK / RSTACK / HEAP 이 무엇인지 알고 넘어가야 하겠다는 생각을 했다과연 무엇일까?

 

▶ 간단한 답변

: 마이크로프로세서에서 (물론 CPU도 마찬가지사용하는 메모리 중 하나로서 RAM 구간에 STACK 공간을 잡아두어 임시변수나 함수호출 공간을 확보하는 컴파일러 셋팅이다. 자세한 내용은 아래의 설명을 참조하자.



 2. 스택 (Stack)


스택 (Stack)

자료 구조의 하나로자료의 삽입과 삭제가 끝에서만 일어나는 선형 목록밑이 막힌 통을 세워 놓은 것으로 생각하면 된다자료의 삽입삭제가 일어나는 곳을 스택의 톱(top)이라고 하며 자료를 스택에 넣는 것을 푸시(push), 스택에서 자료를 꺼내는 것을 팝(pop)이라고 한다스택에서는 나중에 들어간 자료가 먼저 꺼내지는 후입 선출(LIFO) 방식을 사용한다스택은 주로 어떤 내용을 기억시켰다가 다시 신속히 이용하고자 할 때 사용되며컴퓨터 알고리즘에서 자주 쓰이는 중요한 자료 구조이다

이런 스택 구조가 있기 때문에 마이크로프로세서에서 변수를 사용하거나 함수 호출이 가능한 것이다.

너무 당연한가좋아그렇다면 본격적으로 Cstack, Rstack 을 알아보도록 하자.

 

 Cstack

- Data Stack 이라고도 한다.

지역변수함수매개변수임시변수(인터럽트)를 저장하는 공간

보통 ATmega128 에서는 0x20으로 설정한다.

부족하게 설정할 경우 변수 값이 OverWrite 되어 예상할 수 없는 에러가 발생된다.

   (그러므로 적절한 공간 설정이 필요하다.)

 

 Rstack

- Return Stack 이라고도 한다.

함수 호출 시 Return Address 저장공간

하나의 함수 호출 시 2byte의 공간이 필요하다

부족하게 설정할 경우 변수 값이 OverWrite 되어 예상할 수 없는 에러가 발생된다.

   (그러므로 적절한 공간 설정이 필요하다.)



 3. 힙 (Heap)


힙 (Heap)
프로그램을 사용할 수 있는 자유 메모리프로그램 실행 시에 함수로 보내는 데이터 등을 일시적으로 보관해 두는 소량의 메모리와 필요 시 언제나 사용할 수 있는 대량의 메모리가 있다이때소량의 메모리를 ‘스택’이라 하고 대량의 메모리를 ‘힙’이라 한다.이 ‘힙’이 없어지면 메모리 부족으로 ‘이상 종료’하게 된다.

사전에서는 저렇게 말하고 있다하지만 우리가 여기서 말할 Heap 공간은 저거랑은 약간의 차이가 있다저건 우리가 일반적으로 쓰는 PC에 해당되는 내용이구지금 우리가 알아야 할 것은 MCU이기 때문이다.

 

2.1 Heap

- Dynamic Memory Allocation 공간 설정이다.(기본 0x10 size)

- IAR EW에서 CLIB를 사용시 printf, scanf 에서 사용되는 공간을 설정하는 부분이다.

- C 라이브러리의 malloc free 사용에 해당되는 내용이다.

, CLIB printf, scanf 사용하지 않을시 고려하지 않아도 된다.

  

갑작스러운 질문 한가지 더 ~~~!!

 

Q)  MCU 작업중 위에 처럼 STACK을 적절히 조절했는데 불구하고 부족하다는 메세지가 뜬다면 여러분은 어떻게 해결 할 것인가?

 

A) 별 수 없다과감히 변수들을 다이어트 하듯이 줄이던가 외부램을 달아줘라~ RAM 다는 건 진짜 별거 아니다관련 데이터시트를 참조하자.



 [ 참고자료 ]


[1] Atmel Corporation, ATmega128(L) Datasheet, http://www.atmel.com/devices/ATMEGA128.aspx?tab=documents
[2] 네이버지식백과, http://terms.naver.com/


End.

written by Yoonseok Pyo
http://robotpilot.net/
http://cafe.naver.com/openrt


Posted by Miobot

AVR 기초 강좌

AVR 기초 강좌 5-2 : 부록 (Tip1 락비트와 퓨즈비트 설정)


Setting of lock and fuse bit

2013.01.01

 1. 락비트와 퓨즈비트 란?


우리는 아래 그림과 같은 설정 화면을 많이 봤을 것이다. 하지만 나도 후배들에게 그랬지만 선배들은 하나같이 모두 "Clear로 설정하고 쓰면 돼~ " 라고 말했을 것이다. 맞는 말이다. 우리가 어느 정도 ATmega128을 사용하냐에 틀리겠지만 90% 맞다. 허나 이 내용을 모르고 지나가면 나중에 벽에 부딪히는 순간이 다가오기에 오늘 알고 넘어가 보자!


위 화면이 ponyprog2000 화면(다른 프로그램도 상관 없음)인데 여기서 Memory Lock Bit & Fuse Bit 설정을 해주게 된다주의할 점은 해당 설정 박스를 체크해주면 비트 “0” 값을체크해주지 않으면 비트 “1” 값을 나타냄을 반드시 유의해야 한다왜냐하면 잘못 설정된 값으로 인하여 프로그램을 다운로드 못하는 상황과 같은 돌이킬 수 없는 상태를 만들어 낼 수도 있기 때문이다.

 

 체크 안 함

unprogrammed

비트 1

R 체크 함

programmed

비트 0

 

뭔가 혼돈이 오지 않는가그렇다 우리가 생각하던 비트 설정과는 다르게 반대로 되어있다잘 모르겠으면 무조건 기존 생각의 반대로 생각해라.( 1 CLEAR 이고 0 SET 이라 생각해라~ ) 최근에 다른 프로그램에서는 이와 반대로 된 표기법도 있으니 주의하길 바란다.

 

※ 일반적으로 외부 크리스탈로 16Mhz를 사용할 경우 다음 그림과 같이 “CKOPT” 비트만 체크를 하여 사용하면 된다그러나 어떠한 환경에서 작업할지 모르기 때문에 다음 장부터 하나씩 살펴 볼 것이다.





 2. 락비트와 퓨즈비트 관련 레지스터


 Memory Lock Bit  (Datasheet : p.254, 278~279)

Bit

7

6

5

4

3

2

1

0

 

-

-

BLB12

BLB11

BLB02

BLB01

LB2

LB1

Initial

1

1

1

1

1

1

1

1

 

 Extended Fuse Byte  (Datasheet : p.4, 5, 279)

Bit

7

6

5

4

3

2

1

0

 

-

-

-

-

-

-

M103C

WDTON

Initial

1

1

1

1

1

1

0

1

 

 Fuse High Byte  (Datasheet : p. 38, 48, 253~254, 287, 295, 309, 345)

Bit

7

6

5

4

3

2

1

0

 

OCDEN

JTAGEN

SPIEN

CKOPT

EESAVE

BOOTSZ1

BOOTSZ0

BOOTRST

Initial

1

0

0

1

1

0

0

1

 

 Fuse Low Byte  (Datasheet : p.38, 39, 47, 50, 52)

Bit

7

6

5

4

3

2

1

0

 

BODLEVEL

BODEN

SUT1

SUT0

CKSEL3

CKSEL2

CKSEL1

CKSEL0

Initial

1

1

1

0

0

0

0

1

 

 

 Memory Lock Bit

Bit

7

6

5

4

3

2

1

0

 

-

-

BLB12

BLB11

BLB02

BLB01

LB2

LB1

Initial

1

1

1

1

1

1

1

1

 

 Lock Bit

▪ 외부에서 메모리를 프로그램 하는 것을 보호하는 설정

LB2

LB1

설명

1

1

메모리 락 기능을 설정하지 않는다.

1

0

메모리(FLASH, EEPROM)에 프로그래밍 하는 것(병렬프로그래밍/SPI/JTAG/퓨즈설정)을 금지한다.

0

0

메모리(FLASH, EEPROM)에 프로그래밍 하는 것(병렬프로그래밍/SPI/JTAG/퓨즈설정)을 금지한다. Verify 금지

 

 Boot Lock Bit 0

▪ 실행프로그램에서 응용프로그램 섹션을 액세스하는 것을 보호하는 설정

BLB02

BLB01

설명

1

1

LPM / ELPM / SPM 모두 허용,

1

0

SPM 명령어 사용 금지

0

1

LPM / ELPM 명령어 사용 금지

0

0

SPM 명령어 사용 금지

 

 Boot Lock Bit 1

▪ 실행프로그램에서 부트로더 섹션을 액세스하는 것을 보호하는 설정

BLB12

BLB11

설명

1

1

LPM / ELPM / SPM 모두 허용,

1

0

SPM 명령어 사용 금지

0

1

LPM / ELPM 명령어 사용 금지

0

0

SPM 명령어 사용 금지

 

 Extended Fuse Byte

Bit

7

6

5

4

3

2

1

0

 

-

-

-

-

-

-

M103C

WDTON

Initial

1

1

1

1

1

1

0

1

 

 WDTON

 WDTON = 0       : Watchdog Timer를 동작하게 한다.

 

 M103C

 M103C = 0        : ATmega103 호환모드로 동작하게 한다.

 

 Fuse High Byte

Bit

7

6

5

4

3

2

1

0

 

OCDEN

JTAGEN

SPIEN

CKOPT

EESAVE

BOOTSZ1

BOOTSZ0

BOOTRST

Initial

1

0

0

1

1

0

0

1

 

▶ OCDEN

 OCDEN = 0       :  On Chip Debug Enable (AVR ASM  break 명령어 사용가능)

 

 JTAGEN

 JTAGEN = 0      :  JTAG Enable (JTAG 장비로 디버깅 사용가능)

 

 SPIEN

 SPIEN = 0       :  SPI Enable (SPI 방법으로 프로그램 다운로드 가능 / ISP장비를 의미한다.)

 

( ponyprog2000 에서는 이 비트가 설정하지 못하도록 되어 있다그 이유는 혹시 사용자중 ATmega128  '메모리 락 비트와 퓨즈 비트설정을 잘못하여 Lock Bit 비트를 설정과 동시에 이를 0으로 설정하면 다시는 프로그램을 writing 할 수 없기 때문이다.이때에 흔히 크리스탈 대신 오실레이터로 인공호흡을 시켜 해주기도 한다.)


 CKOPT

 CKOPT = 0        :  발진회로 증폭기가 동작하도록 설정한다. ( 16Mhz 크리스탈 사용시 필수 사항)

 

 EESAVE

 EESAVE = 0      :  Erase 할 때 EEPROM 내용 보호

 

 BOOTSZ        : 부트 사이즈 설정

BOOTSZ1

BOOTSZ0

부트 사이즈

응용 프로그램 섹션

부트로더 섹션

1

1

512 WORD

0x0000 ~ 0xFDFF

0xFE00 ~ 0xFFFF

1

0

1024 WORD

0x0000 ~ 0xFBFF

0xFC00 ~ 0xFFFF

0

1

2048 WORD

0x0000 ~ 0XF7FF

0xF800 ~ 0xFFFF

0

0

4096 WORD

0x0000 ~ 0xEFFF

0xF000 ~ 0xFFFF

 

 BOOTRST      : RESET Vector

 BOOTRST = 0   :  Reset  0x0000 번지부터 프로그램을 실행한다.

 BOOTRST = 1   :  Reset 시 부트로더 번지부터 프로그램을 실행한다.

 

 Fuse Low Byte

Bit

7

6

5

4

3

2

1

0

 

BODLEVEL

BODEN

SUT1

SUT0

CKSEL3

CKSEL2

CKSEL1

CKSEL0

Initial

1

1

1

0

0

0

0

1

 

 BODLEVEL

 BODLEVEL = 0  :  Brown Out Detector  level 4.0V 로 설정한다.

 BODLEVEL = 1  :  Brown Out Detector  level 2.7V 로 설정한다.

 

 BODEN

 BODEN = 0       :  Brown Out Detector Enable (BOD 기능을 활성화 시킨다.)

 

 CKSEL0  /  SUT1 /  SUT0   : Start-Up Time 설정

CKSEL0

SUT1

SUT0

Start-Up Time

리셋의 경우 추가 지연시간

사용이 권장되는 응용분야

0

0

0

258 CLK

4.1 ms

세라믹 레조네이터 (Fast rising power)

0

0

1

258 CLK

65 ms

세라믹 레조네이터 (Slowly rising power)

0

1

0

1024 CLK

-

세라믹 레조네이터 (BOD 사용)

0

1

1

1024 CLK

4.1 ms

세라믹 레조네이터 (Fast rising power)

1

0

0

16384 CLK

65 ms

세라믹 레조네이터 (Slowly rising power)

1

0

1

16384 CLK

-

크리스탈 오실레이터(BOD 사용)

1

1

0

16384 CLK

4.1 ms

크리스탈 오실레이터(Fast fising power)

1

1

1

16384 CLK

65 ms

크리스탈 오실레이터(Slowly rising power)

 Start-Up Time : CPU가 파워다운 모드에서 클럭이 재발생 되어 명령을 수행할 수 있는 상황까지의 지연시간

 

 CKOPT / CKSEL3  /  CKSEL2  / CKSEL1           : 자신의 AVR보드의 클럭의 사용 종류를 결정한다.

 AVR에서는 외부크리스탈 / 외부 세라믹 레조네이터 / 외부 저주파크리스탈 / 외부 RC 오실레이터 / 내부 RC 오실레이터 / 외부 클럭을 자신의 클럭으로 이용할 수 있지만 우리는 일반적인 외부크리스탈 설정법을 알아보자.

 

▪ 외부 크리스탈을 사용할 때의 동작 모드

CKOPT

CKSEL3 ~ 1

주파수 범위

권장 캐패시터( C1, C2 )

1

101

0.4 ~ 0.9 MHZ

-

1

110

0.9 ~ 3.0 MHZ

12pF ~ 22pF

1

111

3.0 ~ 8.0 MHZ

12pF ~ 22pF

0

101, 110, 111

1.0 ~ 16.0 MHZ

12pF ~ 22pF

※ 우리는 일반적으로 ATmega128에서는 16MHz 를 사용하니 CKOPT = 0 , CKSEL3 ~ 1 = 111로 맞추어 사용하면 된다.




 [ 참고자료 ]


[1] Atmel Corporation, ATmega128(L) Datasheet, http://www.atmel.com/devices/ATMEGA128.aspx?tab=documents


End.

written by Yoonseok Pyo
http://robotpilot.net/
http://cafe.naver.com/openrt


Posted by Miobot

ATmega128(L) Complete.pdf


ATmega128(L) Summary.pdf


AVR 기초 강좌

AVR 기초 강좌 5-1 : 부록 (레지스터)


Register

2013.01.01

 1. 레지스터


여러 종류의 MCU를 사용하면서 공통점으로 느낌점은 비슷하다는 것이다. 물론 기능면이나, 용량면이나 여러가지 특색들이 있지만 결국은 연산 및 제어 목적으로 나왔으며, 프로그램할때 가장 우선 레지스터 설정을 설정한 후, 그 후 자신만의 목적에 맞는 프로그램을 하는 것으로 연결된다. 즉, MCU 프로그래밍은 각 사용하는 MCU의 레지스터를 잘~~ 설정한 후 프로그램 하게 되어있다. 처음에는 좀 어렵게 느껴지는 작업이지만, 지속적으로 사용하다보면 레지스터의 사용법을 MCU 종류, 제조회사에 상관없이 사용할 수 있다. 그런 의미로 ATmega128의 레지스터를 부록으로 올린다. 외울필요없다!!! 그냥 눈으로 봐두고 필요할 때 잘 설정만 해주면 된다.

ATmega128 데이타 시트 >> atmega128(l) datasheet.pdf
레지스터 요약집 >> register summary.pdf

 2. ATmega128의 레지스터







 [ 참고자료 ]


[1] Atmel Corporation, ATmega128(L) Datasheet, http://www.atmel.com/devices/ATMEGA128.aspx?tab=documents


End.

written by Yoonseok Pyo
http://robotpilot.net/
http://cafe.naver.com/openrt


Posted by Miobot

AVR 기초 강좌

4. ATmega128의 기능 및 제어 6


ATmega128's function (SPI)

2013.01.01

 1. SPI 제어


(1) SPI 란?
: SPI(Serial Peripheral Interface)는 Motorola사에 의하여 개발된 근거리용 직렬통신 규격으로서, MOSI, MISO, SCK, /SS의 4개 통신선을 이용하는 고속 동기식 직렬통신 방식이다. 이는 UART 통신 규격에 비하여 빠른 속도와 멀티 통신이 지원되며, I2C 통신 규격에 비하여 빠르며 간단한 제어가 장점으로 꼽힌다. 그래서 최근 SD메모리나 EEPROM 같은 외부 디바이스들이 SPI통신을 지원하기 시작했다.
 
※ SPI통신은 장치간에 1:1 통신 중 근거리에서 빠른 속도의 데이터 전송이 요구될 때 사용하는 것을 추천한다.
 
① SPI 특징
• MOSI, MISO, SCK, /SS 의 4선을 사용하는 직렬 동기식 통신
• 전이중 통신이 가능.
• 항상 Master와 Slave 사이에서 직렬로 데이터를 송수신.
• 클럭은 항상 Master가 발생
• LSB(최하위비트) or MSB(최상위비트)에서 전송 가능
• 수 MHz의 통신 가능 및 7가지 전송속도 중 선택 사용
• 전송완료 인터럽트 발생
• Wake-Up : 슬립모드 해제기능
• 직렬통신뿐만 아니라 사용자 프로그램을 다운로드 하는 ISP로서도 이용 가능
 
② SPI 구성
 

 
※ SPI는 마스터/슬레이브 모드에 따라 데이터의 입출력이 변경시켜야 하는데 데이터시트에 의하면 유저정의도 가능하나 데이터의 충돌을 피하기 위해서는 위 표의 입출력사항을 지켜줘야 한다.

 
(2) SPI의 전체 블록도


 
(3) SPI 관련 레지스터
: SPI를 제어하기 위해서는 SPI 관련 레지스터( SPCR, SPSR, SPDR)의 사용법을 알아야 한다
 
① SPCR(SPI Control Register)


• Bit 7 - SPIE : SPI Interrupt enable
▪ SPIE = 1 : SPI 인터럽트 기능 활성화
 
• Bit 6 - SPE : SPI Enable
▪ SPE = 1 : SPI 동작 활성화
 
• Bit 5 - DORD : Data Order
▪ DORD = 1 : 데이타 워드중 LSB가 먼저 전송된다.
▪ DORD = 0 : 데이타 워드중 MSB가 먼저 전송된다.
 
• Bit 4 - MSTR : Master/Slave Select
▪ MSTR = 1 : 마스터 모드
▪ MSTR = 0 : 슬레이브 모드
 
• Bit 3 - CPOL : Clock Polarity
▪ CPOL = 1 : IDLE 상태일 때 SCK = High
▪ CPOL = 0 : IDLE 상태일 때 SCK = Low


• Bit 2 - CPHA : Clock Phase
▪ 데이터 샘플링 동작이 수행되는 SCK의 위상 결정

 
※ SPI의 수신 데이터를 인식하는 동작은 위 비트3(CPOL)과 비트2(CPHA)의 조합에 따라 아래와 같이 4가지로 구분된다.
 


 
 
 
• Bit 1,0 - SPR1, SPR0 : SPI Clock Rate Select 1 or 0
 
▪ 이 두비트는 마스터로 선택된 장치의 SCK의 속도를 조정한다. SPR1과 SPR0는 슬레이브에게는 영향을 주지 않는다.
 
 
② SPSR(SPI Status Register)



• Bit 7 - SPIF : SPI Interrupt Flag
▪ SPIF = 1 : 시리얼 전송이 완료되면 SET
 
• Bit 6 - WCOL : Write COLision Flag
▪ WCOL = 1 : SPI데이터 레지스터가 전송 중에 쓰여질 때(written) Set 된다.
 
• Bit 0 - SPI2X : 2배속 SPI 비트
▪ SPI2X = 1 : 마스터 모드일 때 SPI의 속도( SCK 주파수)는 2배가 된다.
 
 
③ SPDR(SPI Data Register)


• SPDR은 SPI가 송신할 데이터를 저장하거나 수신한 데이터를 저장하게 된다. 사용자는 이 레지스터에 데이터를 쓰는 것으로서 SPI 송신을 수행하게 되며 읽는 것으로서 SPI 수신이 이루어지게 된다.
 
 
(4) SPI 동작 순서
 
❑ 마스터 모드
① /SS, SCK, MOSI 단자를 출력으로 설정, MISO 단자를 입력으로 설정
 
② /SS 신호를 LOW로 출력하여 슬레이브 선택
 
③ SPDR 레지스터에 전송할 바이트를 라이트 하여 송신 시작
 
④ SCK클럭 발생하고 하드웨어적으로 데이터를 8Bit만큼 시프트하여 슬레이브로 전송
 
⑤ 1바이트 전송이 끝나면 클럭이 정지되고 SPIF 비트가 1되면서 SPI 전송완료 인터럽트 요청
 
⑥ 이 후 SPDR 레지스터에 바이트를 라이트 하면 그 다음의 전송이 시작
 
⑦ 데이터 패킷을 종료하려면 /SS 단자에 HIGH 신호 출력
 
 
❑ 슬레이브 모드
① /SS, SCK, MOSI 단자를 입력으로 설정, MISO 단자를 출력으로 설정
 
② SPI가 슬레이브로 동작 시 /SS 단자가 자동으로 입력핀으로 동작
 
③ /SS 신호가 LOW 상태로 입력된 경우에 SPI는 슬레이브로 동작이 유효하게 된다.
 
④ 만약 /SS 신호가 HIGH 상태로 입력되면 모든 SPI 신호가 3스테이트 또는 입력 상태로 변함
 
⑤ /SS 신호가 LOW 상태로 입력되고 외부에서 입력된 SCK 신호에 의하여 데이터 레지스터의 1바이트가 전송되고 나면 SPIF 비트가 1로 되면서 SPI전송완료 인터럽트가 요청.
 
⑥ SPI 전송완료 인터럽트를 체크하여 수신데이터를 보낸다.


 2. SPI 제어 실습


ATmega128 2개를 이용하여 마스터에서 대문자를 보내면 소문자로 변환하여 리턴 해주는 프로그래밍을 작성하자.

(참고로 아래 소스의 내용은 UART도 함께 사용하였기에 UART의 설정도 함께 포함되어 있으니 주의하도록 하자. UART 설정이 필요하지 않는 경우에는 관련 설정을 삭제하도록 하자.)

[Example 01]
: SPI 마스터 모드 프로그램

// <SPI  마스터  모드>

#include "iom128.h"

#define sbi(PORTX , BitX) PORTX |= (1 << BitX)  //  비트  SET  명령  정의
#define cbi(PORTX , BitX) PORTX &= ~(1 << BitX) //  비트  CLEAR  명령  정의

void Init_Main(void);
void Uart_Putch(unsigned char PutData);
unsigned char SPI_TxRx(unsigned char Data);

void main(void)
{  
    Init_Main ();
    cbi(PORTB, 0);                  // /SS Low  출력  (SPI통신  시작)
    Uart_Putch(SPI_TxRx(“A”));      // 0xFF  값이  예상된다.
    Uart_Putch(SPI_TxRx(“B”));      // a  값이  예상된다.
    Uart_Putch(SPI_TxRx(“C”));      // b  값이  예상된다.
    Uart_Putch(SPI_TxRx( 0xFF));    // c  값이  예상된다.
    sbi(PORTB, 0);                  // /SS High  출력  (SPI통신  종료)
}

void Init_Main (void)
{    
    cbi(SREG,7);                    // 모든 인터럽트 비활성화
    UBRR0H = 0; UBRR0L = 16;        // 57600bps (16MHz)
    UCSR0A = (0<<RXC0)|(1<<UDRE0);  // 수신,송신 상태비트 초기화
    UCSR0B = (1<<RXEN0)|(1<<TXEN0); // 수신,송신 기능 활성화
    UCSR0C = (3<<UCSZ00);           // START 1비트/DATA 8비트/STOP 1비트
    cbi(DDRE, 0);                   // RXD1 핀 입력으로 설정
    sbi(DDRE, 1);                   // TXD1 핀 출력으로 설정
    sbi(DDRB, 0);                   // /SS 출력으로 설정
    sbi(DDRB, 1);                   // SCK 출력으로 설정
    sbi(DDRB, 2);                   // MOSI 출력으로 설정
    cbi(DDRB, 3);                   // MISO 입력으로 설정
    SPCR = 0x50;                    // SPE, Mastar Mode, SPI Mode0, SCK=fosc/4
    sbi(SREG,7);                    // 모든 인터럽트 활성화
}

void Uart_Putch(unsigned char PutData)  // 시리얼로부터 1바이트 값을 보내는 함수
{    
    while(!(UCSR0A&(1<<UDRE0)));        // 데이터가 빌 때까지 기다린다. 
    UDR0 = PutData;                     // 데이터를 전송한다. 
}

unsigned char SPI_TxRx(unsigned char Data)
{    
    SPDR = Data;                // Data 송신
    while(!(SPSR & (1<<SPIF))); // 송신 확인
    return SPDR;                // 수신 받은 데이터 반환
}


[Example 02]
: SPI 슬레이브 모드 프로그램

// <SPI  슬레이브  모드>

#include "iom128.h"

#define sbi(PORTX , BitX) PORTX |= (1 << BitX)  // 비트 SET 명령 정의
#define cbi(PORTX , BitX) PORTX &= ~(1 << BitX) // 비트 CLEAR 명령 정의

void Init_Main(void);
void Uart_Putch(unsigned char PutData);
unsigned char SPI_TxRx(unsigned char Data);

void main(void)
{  
    Init_Main ();
    while(1)
    {
        while(!(SPSR & (1<<SPIF))); // 송신 확인
        {
            SPDR=SPDR + 0x20;
        }
    }
}

void Init_Main (void)
{    
    cbi(SREG,7);                    // 모든 인터럽트 비활성화
    UBRR0H = 0; UBRR0L = 16;        // 57600bps (16MHz)
    UCSR0A = (0<<RXC0)|(1<<UDRE0);  // 수신,송신 상태비트 초기화
    UCSR0B = (1<<RXEN0)|(1<<TXEN0); // 수신,송신 기능 활성화
    UCSR0C = (3<<UCSZ00);           // START 1비트/DATA 8비트/STOP 1비트
    cbi(DDRE, 0);                   // RXD1 핀 입력으로 설정
    sbi(DDRE, 1);                   // TXD1 핀 출력으로 설정
    cbi(DDRB, 0);                   // /SS 입력으로 설정
    cbi(DDRB, 1);                   // SCK 입력으로 설정
    cbi(DDRB, 2);                   // MOSI 입력으로 설정
    sbi(DDRB, 3);                   // MISO 출력으로 설정
    SPCR = 0x40;                    // SPE, Slave Mode, SPI Mode0, SCK=fosc/4
    SPDR = 0xFF;                    // SPDR=0xFF으로 초기화
    sbi(SREG,7);                    // 모든 인터럽트 활성화
}

void Uart_Putch(unsigned char PutData)  // 시리얼로부터 1바이트 값을 보내는 함수
{    
    while(!( UCSR0A & (1<<UDRE0))  );   // 데이터가 빌 때까지 기다린다. 
    UDR0 = PutData;                     // 데이터를 전송한다. 
}

unsigned char SPI_TxRx(unsigned char Data)
{    
    SPDR = Data;                // Data 송신
    while(!(SPSR & (1<<SPIF))); // 송신 확인
    return SPDR;                // 수신 받은 데이터 반환
}



 [ 참고자료 ]


[1] Atmel Corporation, ATmega128(L) Datasheet, http://www.atmel.com/devices/ATMEGA128.aspx?tab=documents


End.

written by Yoonseok Pyo
http://robotpilot.net/
http://cafe.naver.com/openrt


Posted by Miobot

AVR 기초 강좌

4. ATmega128의 기능 및 제어 5


ATmega128's function (AD Convertor)

2013.01.01

 1. A/D 컨버터 제어


ATmega128에는 8채널의10비트 A/D 컨버터를 가지고 있다.
 
(1) A/D Convertor (ADC) 란?
: 연속적인 신호인 아날로그 신호를 부호화된 디지털 신호로 변환하는 일. 아날로그 디지털 변환을 수행하는 기계 장치를 아날로그 디지털 변환기(AD Convertor)라고 하는데, 이 장치는 온도, 압력, 음성, 영상 신호, 전압 등의 실생활에서 연속적으로 측정되는 신호를 컴퓨터에 입력하여 디지털화시키는 장치이다.



ADC = 펀칭머신
펀칭머신을 생각해 보자. 자신의 주먹으로 힘껏 내리쳐서 내 힘이 얼마나 되는지 점수로 계산된다. ADC도 마찬가지이다. 힘이라는 아날로그를 점수라는 디지털로 변환해 주는 것이다. 이를 이용하면 각종 센서를 이용하여 온도, 기울기, 속도, 조도 등을 디지털값으로 변환가능하다.

① A/D 컨버터의 특징
- 8채널/ 내부 아날로그 멀티플렉서 탑재
- 10비트 분해능
- 축차비교형(변환시간 수십us의 종속형A/D Convetor)
- 샘플/홀드회로 탑재로 인하여A/D 동작 동안 전압 고정화
- 단극성 아날로그 입력/ 차등입력 선택
- 차등입력에서10배~200배의 증폭A/D 가능
- 포트F는 아날로그 비교기 기능으로도 사용 가능
- 변환시간(65us~260us - 50kHz~200kHz)
 
② A/D 컨버터의 구성
- 범용PORTF의 특수 기능
  ▪ ADC0 ~ ADC7 : 8채널10비트A/D 컨버터의 아날로그 입력단자
- ADC 정확도 성능 향상을 위한 독립 전원 구성
  ▪ AVCC : Analog Supply Voltage(VCC의 전압의 ±0.3V 유지 해야함)
  ▪ AGND : Analog Ground (반드시GND와 연결)
  ▪ AREF : Analog Reference Voltage
- 입력 전압의 범위
  ▪ 일반 모드 입력전압의 범위(0V ~ Vref)
  ▪차동입력 모드 입력전압의 범위(-Vref~ Vref)
- Vref의 범위
  ▪ 전원전압VCC를 초과할 수 없다.(VREF=VGND~VCC, 내부기준전압2.56V)
  
③ A/D 변환 오차



1) 양자화 오차(Quantization error)
 - 아날로그 값을 디지털 값으로 변환하면서 생기는 변환의 한계
 - 대처방안: 분해능이 높은ADC사용으로 극복

2) 오프셋 오차(Offset error)
 - 변환 결과가 이상적인 디지털 값에서 일정한 양만큼 벗어난 상태
 - 대처방안: 변환된 디지털 값에 일정치 값을 더하거나 뺴서 교정한다.

3) 이득 오차(Gain error)
 - 변환 결과가 이상적인 디지털 값에서 일정한 비율만큼 벗어난 상태
 - 대처방안: 변환된 디지털 값에 일정치 값을 곱하거나 나누어서 교정한다.

4) 비선형 오차(Integral non-linearity error)
 - 변환 결과가 교정될 수 없는 상태
 - 대처방안 없음

5) 차등 비선형 오차(Differential non-linearity error)
 - 변환 결과가 교정될 수 없는 상태
 - 대처방안 없음
      
 
④ A/D Convertor 잡음 제거 방법
: A/D Convertor의 경우에는 노이즈에 매우 민감하기 때문에ATmega128 내에서도AVCC, AREF, AGND와 같은ADC 전원 구성도 따로 하였으며 사용자 또한 몇 가지 사항을 주의하여 사용해야 한다.
-      AVCC = 독립적인 아날로그 회로 전원 단자
-      AREF = 기준 전원 입력 단자
-      AGND = 아날로그 회로 접지 단자
 
1) 아날로그 입력선은 최소한으로 짧게 하고 잡음의 영향이 없도록 회로를 구성한다.
2) 아날로그 전원단자 AVCC에 VCC를 인가할 때는LC필터를 거쳐 안정하 시킨다.
3) 아날로그 회로의 모든 접지는 AGND에 접지하여 한 포인트에서만 GND와 접속한다.
4) ADC 동작중에는 병렬I/O 포트의 논리상태를 스위칭 하지 않는다.
5) 잡음에 민감한 아날로그 소자의ADC의 경우에는 Adc Noise Reduction mode를 사용한다.
6) 잡음이 심하여 결과값의 변동이 심하면 디지털 필터를 사용하거나 평균치를 구하여 사용한다. 




(2) A/D Convertor 블록도


 
(3) A/D 컨버터 관련 레지스터
: A/D 컨버터를 제어하기 위해서는ADC 관련 레지스터( ADMUX, ADCSRA, ADCH/L)의 사용법을 알아야 한다.

①ADMUX(ADC Multiplexer Selection Register)


▪Bit 7, 6 – REFS1, REFS0 (Reference Selection Bit)
           • ADC에서 사용하는 기준전압을 설정한다.

REFS1

REFS0

기준전압

0

0

외부의AREF 단자로 입력된 전압을 사용한다.

0

1

외부의AVCC 단자로 입력된 전압을 사용한다.

1

0

-

1

1

내부의2.56V를 사용한다.

▪Bit 5 – ADLAR (ADC Left Adjust Result)
          •ADLAR = 1 : 변환결과값을ADCH/L에 저장할 때 좌측으로 끝을 맞추어 저장된다.
▪Bit 4,3,2,1,0  – MUXn (Analog Channel and Gain Selection Bit) 




② ADCSRA(ADC Control and Status Register A)
 

▪ Bit 7 – ADEN (ADC Enable)
          •ADEN = 1 : ADC 활성화
 
▪ Bit 6 – ADSC (ADC Start Conversion)
          •ADSC = 1 : ADC의 변환이 시작된다.
          ( 단일 변환모드일떄 단 한번만 작동/ 프리런닝모드일떄 변환동작반복)
 
▪ Bit 5 – ADFR (ADC Free Running Select)
          •ADFR = 1 : 프리런닝모드
          •ADFR = 0 : 단일변환모드
 
▪ Bit 4 – ADIF (ADC Interrupt Flag)
          •ADC변환완료 인터럽트가 요청되고 그 상태를 이 비트에 표시한다.
 
▪ Bit 3 – ADIE (ADC Interrupt Enable)
          •ADIE = 1 : ADC Interrupt 활성화
 
▪ Bit 2,1,0 – ADPS 2~0 (ADC Prescaler Select Bit)
              •ADC에 인가되는 클럭의 분주비를 설정한다.

ADPS2

ADPS1

ADPS0

분주비

0

0

0

2

0

0

1

2

0

1

0

4

0

1

1

8

1

0

0

16

1

0

1

32

1

1

0

64

1

1

1

128



③ ADCH/L (ADC Data Register)


- ADC의 변환결과를 저장한다.


(4) A/D 컨버터의 동작
 
   - 단일변환모드(Single conversion mode)           : ADC 동작을 한번만 수행하게 된다.
   - 프리런닝모드(Free running mode)                  : ADC 동작을 반복적으로 수행하게 된다.
 
   ① A/D 컨버터 초기화 설정
       ▪ ADC 활성화(ADEN=1)
       ▪ ADC 클럭설정(ADPS 2~0)
       ▪ ADC 기준전압설정(REF 1~0)
       ▪ ADC 입력채널설정(MUX 4~0)
       ▪ ADC 동작모드설정(ADFR)
       ▪ ADC 변환 완료 인터럽트 활성화(ADIE)
 
   ② A/D 컨버터 스타트
       ▪ ADC 시작신호(ADSC)
 
   ③ A/D 변환
       ▪ ADC 변환 결과
           

      
   ④ A/D 변환 완료
       ▪ ADC 변환이 완료되면 변환값을ADCH/L 에 저장하게 된다.
 
   ⑤ A/D 변환 완료 인터럽트 요청
       ▪ ADC Conversion Complete Interrupt 요청
 
   ⑥ ADC 상태플래그 셋
       ▪ ADIF = 1
 
   ⑦ ADC 다음 동작 결정
       ▪ 단일/연속동작인지 구분하여 다음 동작 수행을 결정한다. (ADFR)


 2. A/D 컨버터 실습


[Example 01]
: ADC1번핀(60번:PF01)에 센서를 연결하고 그 센서 값의ADC 변환 값을 출력하라.

#include "iom128.h"

#define sbi(PORTX , BitX)   PORTX |=  (1 << BitX)   // 비트SET 명령정의
#define cbi(PORTX , BitX)   PORTX &= ~(1 << BitX)   // 비트CLEAR 명령정의
 
void Main_Init(void);
void Uart_Putch(unsigned char PutData);
void Uart_U16Bit_PutNum(unsigned int NumData );
unsigned int Read_ADC(unsigned char ADC_Input);
 
void main(void)
{      
    Main_Init();

    while(1)
    {                             
        Uart_U16Bit_PutNum (Read_ADC (1));    // 키보드로부터 받은 데이터를 송신한다.
    }
}
 
void Main_Init(void)
{   
    cbi(SREG,7);                    // 모든인터럽트비활성화
    UBRR0H = 0; UBRR0L = 16;        // 57600bps (16MHz)
    UCSR0A = (0<<RXC0)|(1<<UDRE0);  // 수신,송신 상태비트 초기
    UCSR0B = (1<<RXEN0)|(1<<TXEN0); // 수신,송신 기능 활성화
    UCSR0C = (3<<UCSZ00);           // START 1비트/DATA 8비
    cbi(DDRE,0);                    // RXD1 핀 입력으로 설정
    sbi(DDRE,1);                    // TXD1 핀 출력으로 설정
    ADMUX = 0x00;                   // ADC 초기화
    ADCSRA = 0x87;                  // ADC Enable, 분주비=1
    cbi(DDRF,1);                    // ADC1 핀 입력으로 설정
    sbi(SREG,7);                    // 모든 인터럽트 활성화
}
 
void Uart_Putch(unsigned char PutData)  // 시리얼로부터1바이트값을보내는함수
{   
    while(!( UCSR0A & (1<<UDRE0)));     // 데이터가빌때까지기다린다.
    UDR0 = PutData;                     // 데이터를전송한다.
}
 
void Uart_U16Bit_PutNum(unsigned int NumData )
{      
    unsigned int TempData;
    TempData =  NumData/10000;
    Uart_Putch( TempData+48 );          // 10000    자리출력
    TempData = (NumData%10000)/1000;
    Uart_Putch( TempData+48 );          // 1000     자리출력
    TempData = (NumData%1000)/100;
    Uart_Putch( TempData+48 );          // 100      자리출력
    TempData = (NumData%100)/10;
    Uart_Putch( TempData+48 );          // 10       자리출력
    TempData =  NumData%10;
    Uart_Putch( TempData+48 );          // 1        자리출력
}
 
unsigned int Read_ADC(unsigned char ADC_Input)
{   
     ADMUX        = ADC_Input;          // 사용자설정 -> ADC값 입력
     ADCSRA      |= 0x40;               // ADC START Conversion
     while( (ADCSRA & 0x10) == 0 );     // ADC interrupt flag check
     return      ADC;                   // ADC 값반환
}


 [ 참고자료 ]


[1] Atmel Corporation, ATmega128(L) Datasheet, http://www.atmel.com/devices/ATMEGA128.aspx?tab=documents


End.

written by Yoonseok Pyo
http://robotpilot.net/
http://cafe.naver.com/openrt


Posted by Miobot

AVR 기초 강좌

4. ATmega128의 기능 및 제어 4


ATmega128's function (USART)

2013.01.01

 1. USART 제어


ATmega128에는 같은 기능을 가지는 USART0, USART1 통신 관련 회로를 가진다.
USART = Universal Synchronous and Asynchronous serial Receiver and Transmitter
UART = Universal Asynchronous serial Receiver and Transmitter
 
(1) UART 란?
: UART는 컴퓨터의 비동기 직렬 통신을 처리하는 프로그램으로서 보통 마이크로칩으로 실현되며, RS-232C 를 제공하여, 모뎀이나 기타 다른 직렬 장치들과 통신하거나 데이터를 주고받을 수 있게 하는 것이다. 예전에는 PC의 COM Port, 56Kbps 속도 이하 모뎀 등에서 이용되었으나 현재 PC에서는 USB가 그 뒤를 이어나가 대체되고 있는 실정이다. 하지만 아직까지는 막강한 표준력과 호환성을 자랑하여 MCU등에 표준적으로 사용하는 통신 방법이다.

UART = 컨베이어벨트 시스템
공장의 컨베이어 벨트를 생각해보자. 제품이 만들어지면 컨베이어 벨트에 실어서 저~ 멀리 다른 작업자나 창고에 차곡차곡 쌓이는게 상상되는가? UART도 마찬가지이다. 내가 보내고자 하는 데이타를 컨베이어벨트 시스템과 같은 UART에 실어서 상대방에게 보내는 것이다. 물론, 반대 방향도 가능하다.

① USART 특징
- 동기모드    : Master(내부클럭), Slave(외부클럭:XCKn)
- 비동기모드  : 내부클럭사용
- 전이중 통신
- 멀티프로세서 통신
- 높은 정밀도의 보레이트발생기 내장
- 전송데이터 5~9비트 설정
- 스톱비트 1~2 설정
- 페리티비트 설정(사용, 미사용, 짝수패리티, 홀수패리티 선택)
- 에러검출기능 (페리티에러, 오버런에러, 프레임에러)
- 노이즈필터링(3번 샘플링 동작)
 
 
② USART 구성

 


⒜ 클럭발생부 : 보레이트발생기, 외부클럭입력 회로
- 비동기 일반모드   : 내부클럭으로 보레이트발생
- 비동기 2배속모드  : 내부클럭으로 2배의 보레이트발생
- 동기 마스터 모드 
- 동기 슬레이브 모드

⒝ 송신부 : 송신버퍼, 송신 시프트 레지스터, 패리티발생기
⒞ 수신부 : 수신버퍼, 수신 시프트 레지스터, 패리티검사기

③ USART 인터럽트
⒜ 수신완료 인터럽트
▪ 데이터가 수신되어 수신시프트레지스터에서 수신버퍼(UDRn) 레지스터로 전달될 때 인터럽트가 걸린다.
▪ 이 시점에서 사용자는 UDRn을 Read하면 수신데이터를 확인 할 수 있다.
 
⒝ 송신완료 인터럽트
▪ 송신 시프트 레지스터에 있는 송신데이터가 모두 전송되어 비어있고 송신버퍼(UDRn) 도 비어있을 때 인터럽트가 발생된다.
 
⒞ 송신데이터준비완료 인터럽트
▪ 송신 시프트 레지스터로 UDRn값이 전송되어 송신버퍼(UDRn)가 비어 있을 때 인터럽트가 발생한다.
▪ 이 시점에서 사용자는 UDRn에 새로운 데이터를 Write하면 송신할 수 있게 된다.
 
④ 전송데이터 포맷 

 

- ATmega128 의 USART는 전송데이터의 포맷을 여러 형태로 설정할 수 있도록 되어있다.
- Start bit   : 1                         (표준:1 bit)
- Data bit    : 5, 6, 7, 8 or 9       (표준:8 bit)
- Parity bit  : No, Even or Odd  (표준:0 bit)
- Stop bit    : 1 or 2                 (표준:1 bit)


⑤ 비동기모드에서의 1비트 샘플링

 

- 수신데이터의 정확한 검출을 위하여 1비트의 샘플링이 이루어진다.
- 검출을 하기 위해서 1비트당 16배 주파수(2배속모드 : 8배주파수)를 이용한다.
- 16배 주파수중 중앙부(8,9,10)에 3번 샘플링하여 2번 이상인 값으로 처리
 
 
(2) USART 블록도 

아래의 그림은 USART의 클럭발생부, 송신수, 수신부의 내부 블록도 이다. 각부의 동작원리를 이해하면 USART의 전체적인 동작을 이해할 수 있다.

 




(3) USART 관련 레지스터
: USART 0과 1을 제어하기 위해서는 USART 0 / 1 관련 레지스터( UDRn, UCSRnA, UCSRnB, UCSRnC, UBRRnH, UBRRnL )의 사용법을 알아야 한다.
 
① UDRn(Usart 0 I/O Data Register)

 

- UDRn 레지스터는 송/수신되는 데이터 값을 저장하는 버퍼역할을 하게 된다.
- UDRn은 TXBn(송신버퍼) / RXBn(수신버퍼) 레지스터로 구성되어 있는데 이는 I/O 같은 주소에 공유된 형태로 구성되어있으며 송/수신 이라는 다른 일을 하게 구성되어 있다.
- 송신할 때는 TXBn의 데이터를 전송한다.
- 수신할 때는 RXBn에 수신된 데이터를 저장하게 된다.
 
② UCSRnA (USART Control and Status Register A)

 

▪ Bit 7 – RXCn(USART Receive Complete)
          • RXCn = 1 : UDRn의 수신버퍼에 아직 안 읽은 데이터가 존재하는 상태
          • RXCn = 0 : UDRn의 수신버퍼를 읽어서 비워져 있는 상태
 
▪ Bit 6 – TXCn(USART Transmit Complete)
• TXCn = 1 : 송신 시프트 레지스터에 있는 송신데이터가 모두 전송되고
UDRn의 송신버퍼에 아직 새로운 송신데이터가 라이트되지 않은 상태
 
▪ Bit 5 – UDREn(USART Data Register Empty)
          • UDREn = 1 : 송신 버퍼가 비어있어서 새로운 송신 데이터를 받을 준비가 된 상태
 
▪ Bit 4 – FEn(USART Frame Error)
          • FEn= 1 : 수신할 때 프레임 에러가 발생한 상태
 
#프레임에러? - 수신문자의 첫 번째 스톱 비트가 0으로 검출되는 것
 
 
▪ Bit 3 – DORn(USART Data Overrun Error)
          • DORn = 1 : 수신할 때 오버런 에러가 발생한 상태
                      
#오버런에러? – 수신버퍼에 현재 읽지 않은 데이터가 들어있는 상태에서 수신 시프트 레지스터에 새로운 데이터가 수신 완료되고 다시 그 다음 수신 데이터인 3번째 데이터의 스타트 비트가 검출된 것
 
▪ Bit 2 – UPEn(USART Parity Error)
          • UPEn = 1 : 수신할 때 패리티 에러가 발생한 상태
 
#패리티에러? – 정보의 전달 과정에서 오류가 생겼는지를 검사하기 위해 원래의 정보에 덧붙이는 비트를 패리티비트라 하며 데이터비트와 패리티비트를 계산하여 짝수, 홀수를 판별하여 에러인지 아닌지 구분한다. (거의 쓰이지 않음.)
 
▪ Bit 1 – U2Xn(Double the USART Transmission Speed)
          • U2Xn = 1 : 비동기 모드에서만 유효한 것으로서 클럭의 분주비를 16에서 8로 절반만큼 낮추어 전송속도를 2배 높이는 기능을 수행한다.
 
▪ Bit 0 – MPCMn(USART Multi-Processor Communication Mode)
          • MPCMn = 1 : 멀티프로세서 통신모드로 설정한다.
 
 
③ UCSRnB (USART Control and Status Register B)
 

 

▪ Bit 7 – RXCIEn(USART RX Complete Interrupt Enable)
          • RXCn = 1 : 수신완료 인터럽트 활성화
 
▪ Bit 6 – TXCIEn(USART TX Complete Interrupt Enable)
          • TXCn = 1 : 송신완료 인터럽트 활성화
 
▪ Bit 5 – UDRIEn(USART Data Register Empty Interrupt Enable)
          • UDRIEn = 1 : 송신 데이터 레지스터 준비완료 인터럽트 활성화
 
▪ Bit 4 – RXENn(USART Receiver Enable)
          • RXENn = 1 : 수신부 동작 활성화
 
▪ Bit 3 – TXENn(USART Transmitter Enable)
          • TXENn = 1 : 송신부 동작 활성화
 
 
▪ Bit 2 – UCSZn2(USART Character Size)
          • UCSRnC의 UCSZn1~0 비트와 함께 전송 문자의 데이터 비트수를 설정한다.
 
▪ Bit 1 – RXB8n(USART Receive Data Bit 8)
          • 전송 데이터수가 9로 설정된 경우 수신된 9번째 데이터를 저장하게 된다.
 
▪ Bit 0 – TXB8n(USART Transmit Data Bit 8)
          • 전송 데이터수가 9로 설정된 경우 송신될 9번째 데이터를 저장하게 된다.
 

④ UCSRnC (USART Control and Status Register C)

 


▪ Bit 6 – USMSELn(USART Mode Select)
          • USMSELn = 1 :   동기전송모드
          • USMSELn = 0 : 비동기전송모드
 
▪ Bit 5, 4 – UPMn1, UPMn0 (USART Parity Mode)


UPMn1

UPMn0

패리티모드

0

0

패리티 체크 기능을 사용하지 않음

0

1

-

1

0

짝수 패리티 방식 활성화

1

1

홀수 패리티 방식 활성화

 

▪ Bit 3 – USBSn(USART Stop Bit Select)
          • USBSn = 1 : 스탑비트 2개로 설정
          • USBSn = 0 : 스탑비트 1개로 설정
 
▪ Bit 2, 1 – UCSZn1, UCSZn0 (USART Character Size)
          • UCSRnB의 UCSZn2 비트와 함께 전송 문자의 데이터 비트 수를 설정한다.
 

UCSZn2

UCSZn1

UCSZn0

전송 데이터 길이

0

0

0

5비트

0

0

1

6비트

0

1

0

7비트

0

1

1

8비트

1

0

0

-

1

0

1

-

1

1

0

-

1

1

1

9비트


▪ Bit 0 – UCPOLn(USART Clock Polarity)
          • 이 비트는 동기 전송 모드의 슬레이브 동작에서만 사용된다.
          • UCPOLn = 1 : 송신데이터는 XCKn 클럭의 하강에지에서 새로운 값이 출력
                          수신데이터는 XCKn 클럭의 상승에지에서 검출된다
          • UCPOLn = 0 : 송신데이터는 XCKn 클럭의 상승에지에서 새로운 값이 출력
                          수신데이터는 XCKn 클럭의 하강에지에서 검출된다
 
⑤ UBRRnH/L (USART Baud Rate Register)
 

 



          • USART의 송/수신 속도를 설정한다.
          • 원하는 통신속도 맞추기 위해 UBRR설정 시 아래의 그림4-45표를 참고하길 바란다.
          • 주의) UBRRnH 설정 후 UBRRnL를 나중에 라이트해야 한다.
 

 

 

 //통신속도 계산 방식(일반모드)
BAUD = fosc / 16 * (UBRR+1)

 

//관련 용어 정의
BAUD = Baud Rate (Bit Per Second, BPS)
Fosc = System Oscillator Clock frequency
UBRR = UBRR의 값 (0~4095)

 

//예제 (16MHz, 57600bps 속도의 UBRR구하기)
UBRR = ( fosc / 16 * UBRR ) – 1
      = (16000000 / 16 * 57600 ) -1
      = 17.36111 – 1
      = 16.36111
      ≒ 16 




 2. USART 실습


 RS232 회로구성

: UART 실습에 앞서 준비해야 할 사항은 UART 케이블을 만드는 것이다실제 ATmega128 UART PC COM 단자는 서로UART 통신이다그러나 바로 연결해서 사용할 수는 없다그 이유는 우리가 사용하고 있는 ATmega128에서의 UART 통신은0V~5V의 디지털방식이고 PC에서는 -12V ~ +12V 디지털 값을 사용하기 때문이다이를 연동하기 위해서는 ATmega128에서의 출력레벨과 PC의 출력레벨을 상호변환 가능하도록 만들어야 한다아래의 회로는 일반적으로 많이 사용하는 MAX232 IC를 이용한 데이터 레벨의 상호변환 회로이다.


 

[참고] RS232C

RS-232C Recommend Standard number 232 약어이고, C표준 규격의 최신판을 나타내는 것이다대부분의 PC의 시리얼 포트는 RS-232C의 서브 세트(9)가 표준 장비되어 전체 규격은 25-pin "D"형태 중 22핀을 통신에 사용한다그러나 보통의 PC 통신에서는 이들 대부분의 핀은 사용되지 않는다대부분의 최신 PC에는 통상 수컷(male) 9 "D" 타입 커넥터가 장비되고 있다.



[Example 01]
: USART0을 이용하여 키보드로부터 수신 받은 값을 다시 컴퓨터로 송신하는 프로그램

#include "iom128.h"
#define sbi(PORTX , BitX)   PORTX |=  (1 << BitX)   // 비트 SET 명령 정의
#define cbi(PORTX , BitX)   PORTX &= ~(1 << BitX)   // 비트 CLEAR 명령 정의
 
void Main_Init(void);
unsigned char Uart_Getch(void);
void Uart_Putch(unsigned char PutData);
 
void main(void)
{       
    Main_Init();
    while(1)
    {                                   // 키보드로부터 데이터를 수신 받는다.
        Uart_Putch( Uart_Getch() );     // 키보드로부터 받는 데이터를 송신한다.
    }
}
 
void Main_Init(void)
{     
    cbi(SREG,7);                        // 모든 인터럽트 비활성화
    UBRR0H = 0; UBRR0L = 16;            // 57600bps (16MHz)
    UCSR0A = (0<<RXC0)  | (1<<UDRE0);   // 수신,송신 상태비트 초기화
    UCSR0B = (1<<RXEN0) | (1<<TXEN0);   // 수신,송신 기능 활성화
    UCSR0C = (3<<UCSZ00);               // START 1비트/DATA 8비트/STOP 1비트
    cbi(DDRE,0);                        // RXD0 핀 입력으로 설정
    sbi(DDRE,1);                        // TXD0 핀 출력으로 설정
    sbi(SREG,7);                        // 모든 인터럽트 활성화
}
 
unsigned  char Uart_Getch(void)         // 시리얼로부터 1바이트 값을 받는 함수
{    while(!( UCSR0A & (1<<RXC0)) );    // 데이터가 올 때까지 기다린다.
     return UDR0;                       // 데이터를 돌려준다.
}
 
void Uart_Putch(unsigned  char PutData) // 시리얼로부터 1바이트 값을 보내는 함수
{    
    while(!( UCSR0A & (1<<UDRE0)) );    // 데이터가 빌 때까지 기다린다.
    UDR0 = PutData;                     // 데이터를 전송한다.
}




 [ 참고자료 ]


[1] Atmel Corporation, ATmega128(L) Datasheet, http://www.atmel.com/devices/ATMEGA128.aspx?tab=documents
[2] Wikipedia, "UART", http://en.wikipedia.org/wiki/UART


End.

written by Yoonseok Pyo
http://robotpilot.net/
http://cafe.naver.com/openrt


Posted by Miobot

AVR 기초 강좌

4. ATmega128의 기능 및 제어 3


ATmega128's function (Timer/Counter)

2013.01.01

 1. 타이머 / 카운터


ATmega128는4개의 타이머/카운터로 구성되어있으며, 이중 타이머/카운터0은8비트 구조로서 카운터로 이용될 때 타이머카운터0의 카운터입력이 TOC1과 0으로 받아 RTC기능을 가지는 것을 제외하고는 타이머/카운터2와 기능이 같으며 타이머카운터1은16비트 구조로서 타이머/카운터3과 기능이 같다.
 
(1) 타이머/카운터란?
: 타이머/카운터를 흔히 통칭해서 부르며 같은 기능이라고 생각하고 사용하지만 세분하여 볼 때는 타이머와 카운터는 엄연히 틀린 기능을 말하는 것을 알아 두어야 한다.

타이머/카운터 = 손목시계
인간은 흔히, 시간에 묶여산다고 한다.. 손목에 찬 시계를 항상 보며, 12시에 점심 식사를 하고, 정해진 시간에 퇴근하고, 잠을 잔다. 마이크로프로세서는 더욱이 실시간 응답성을 요구하는 물건이라, 인간보다 더욱 시간 개념이 철저한다. 이러한 시간을 재고, 정해진 시간내에 작업을 수행하는 기능을 가지고 타이머 / 카운터 기능이라고 한다.
① 타이머는MCU의 내부클럭(clkI/O>분주기>clkT)을 이용하여 일정시간 간격의 펄스를 만들어 내거나 일정시간 경과 후에 인터럽트를 발생시키는 기능을 말한다.

② 카운터는 외부 핀(TOSC1, TOSC2, T1, T2, T3)을 통해서 들어오는 펄스를 계수(Edge Detector)하여Event Counter로서 동작되는 것을 말한다. (펄스=사건, 카운터값=사건의 횟수)
  

 


이렇게 타이머와 카운터는 입력 받는 소스가 틀리면서 원리적인 차이가 있지만 그 사용 목적과 결과는 같은 이유로 혼용되어 부르며 사용되고 있다.

 



 2. 타이머/카운트0, 2 제어


타이머/카운터0과2는8비트 구조로서 OVERFLOW, PWM 비슷한 기능을 가지고 제어방식도 비슷하다. 차이점이 있다면 타이머/카운터0 은32.768kHz의 크리스탈을 접속하는TOSC1 및TOSC2 단자를 가지고 있어서RTC의 기능을 갖도록 할 수 있으며 다른 타이머/카운터와는 틀리게 내부 클럭을 사용하든 외부의 클럭을 사용하든 모두 프리스케일러의 분주기능을 사용할 수 있다는 것이다.

 

 


(1) 타이머/카운터0, 2의 특징
- 8비트( 0x00 ~ 0xff ) 구조
- 10비트(0x000 ~ 0x3ff) 프리스케일러
- Overflow와Output Compare Match 인터럽트
- Output Compare Match 할 때 타이머가 클리어 된다.(CTC모드)
- 타이머/카운터0의 경우 다른 타이머/카운터와는 색다른 기능을 가진다.
> RTC기능
> 타이머와 카운터 모두 프리스케일러를 사용
> I/O 클럭과 독립된 외부32.768kHz 크리스탈에 동작가능
 
(2) 타이머/카운터0, 2의 블록도
- 내/외부 클럭 중 하나를 선택하여 기준 클럭으로 삼는다.
- 타이머/카운터0, 2은0x00~0Xff까지Count하여Overflow되면OVF 인터럽트가 걸린다.
- 타이머/카운터0, 2은0x00~0Xff까지Count하다가 지속적으로TCNT값과OCR값을 비교하여 같으면COMP 인터럽트가 걸린다.
- 타이머/카운터0, 2은 동작을 알기 위해서는 아래의 그림들을 필히 이해해야 된다.

 

 

 

※용어설명
- BOTTOM : 카운터가 가질 수 있는 최소값0x00을 나타낸다.
- MAX : 카운터가 가질 수 있는 최대값0xff를 나타낸다.
- TOP : 각 동작모드에 따라 카운터가 실제로 도달하는 최대값을 나타낸다. (CTC모드의 경우TOP=OCR)
- COUNT : TCNT0의1씩 증가 또는 감소하는 것
- DIRECTION : COUNT의 증감/ 감소 설정
- CLEAR : Clear TCNTO
- CLKTO: 타이머/카운터 클럭


(3) 타이머/카운터0 관련 레지스터
타이머/카운터0을 제어하기 위해서는 상태레지스터(SREG)와 타이머/카운터0 관련 레지스터(TIMSK, TIFR, TCCR0, TCNT0, OCR0, ASSR, SFIOR)의 사용법을 알아야 한다.
 
① TIMSK(Timer/Counter Interrupt Mask Register)
: 타이머/카운터 0~2 에서 발생하는 인터럽트를 개별적으로 허용하는 기능을 수행하는 레지스터

 

•Bit 1 – OCIE0(Timer/Counter0 Output Compare Match Interrupt Enable)
▪ OCIE0 = 1 : Output Compare Match Interrupt 활성화
(COMP인터럽트를 사용하려면SREG의I=1인 상태여야 한다.)

•Bit 0 – TOIE0(Timer/Counter0 Overflow Interrupt Enable)
▪ TOIE0 = 1 : Overflow Interrupt 활성화
(OVF인터럽트를 사용하려면SREG의I=1인 상태여야 한다.)


② TIFR(Timer/Counter Interrupt Flag Register)

•Bit 1 – OCF0(Output Compare Match Flag)
▪OCF0 = 1 : TCNT0 = OCR0 경우1로Set되면서 출력비교 인터럽트가 요청된다.
(이 비트는 인터럽트 처리의 시작과 함께0으로Clear된다.)

•Bit 0 – TOV0(Timer/Counter0 Overflow Flag)
▪TOV0 = 1: Overflow가 발생되면1로Set되면서 출력비교 인터럽트가 요청된다.
(이 비트는 인터럽트 처리의 시작과 함께0으로Clear된다.)


③ TCCR0(Timer/Counter Control Register 0) : 동작모드설정/ 분주비 설정 등

•Bit 7 – FOC0(Force Output Compare)
▪ 강제로OSC0 단자에 출력비교 매치 신호를 출력
 
•Bit 3,6 – WGM01, WGM00 (Waveform Generation Mode) : 파형 출력 모드

 


•Bit 5,4 – COM01, COM00(Compare Match Output Mode) : 비교매치 출력 모드


Mode

COM01

COM00

설명

PWM모드가 아닌 경우

(<st1:place w:st="on"><st1:city w:st="on">Normal</st1:city></st1:place>/ CTC)

0

0

범용 입출력포트(OC0 출력 차단)

0

1

비교매치 →OC0 Toggle 출력

1

0

비교매치 →OC0 = 0 출력

1

1

비교매치 →OC0 = 1 출력

 

Mode

COM01

COM00

설명

FAST PWM

0

0

범용 입출력포트(OC0 출력 차단)

0

1

(reserved)

1

0

비교매치 →OC0 = 0 출력

오버플로우 →OC0 = 1 출력

1

1

비교매치 →OC0 = 1 출력

오버플로우 →OC0 = 0 출력

 

Mode

COM01

COM00

설명

Phase Correct

PWM

0

0

범용 입출력포트(OC0 출력 차단)

0

1

(reserved)

1

0

상향카운터 비교매치 →OC0 = 0 출력

하향카운터 비교매치 →OC0 = 1 출력

1

1

상향카운터 비교매치 →OC0 = 1 출력

하향카운터 비교매치 →OC0 = 0 출력

 

•Bit 2,1,0 – CS02~00(Clock Select)

 



④ TCNT0(Timer/Counter Register 0)

 

• 타이머/카운터0의 8비트 카운터 값을 저장하고 있는 레지스터
• 타이머/카운터0의 자동으로 값이 갱신된다.
 
 
⑤ OCR0(Timer/Counter Output Compare Register 0)


 

• 타이머/카운터0의 카운터 값인TCNT0과 비교하여OC0 단자에 출력신호를 발생하기 위한8비트 값을 저장하고 있는 레지스터
• 사용자가 설정해야 하는 값이다.
 
  
⑥ ASSR(Asynchronous Status Register)
: 타이머/카운터0의 외부클럭에 의하여 비동기 모드로 동작하는 경우에 관련된 기능 수행


 

•Bit 3 – AS0(Asynchronous Timer/Counter0)
▪AS0 = 0  : 내부클럭(ClkI/O)   동기모드
▪AS0 = 1  : 외부클럭(TOSC1)   비동기모드
 
•Bit 2– TCN0UB(Timer/Counter0 Update Busy)
 
•Bit 1– OCR0UB(Output Compare Register0 Update Busy)
 
•Bit 0– TCR0UB(Timer/Counter Control Register0 Update Busy)
 
 
⑦ SFIOR(Special Function I/O Register)


 

•Bit 7 – TSM(Timer/Counter Synchronization Mode)
▪ 모든 타이머/카운터들을 동기화시키는 기능을 수행한다.
 
•Bit 1 – PSR0(Prescaler Reset Timer/Counter0
▪ 타이머/카운터0의 프리스케일러를 리셋 시키며 동작 후에 자동적으로 클리어 된다.
 
  
(4) 타이머/카운터0 의 동작

① Normal Mode
▪ 일반적인 타이머 오버플로우 인터럽트가 필요할 때 사용
▪ 상향카운터
▪ 0x00 ~ 0xFF 계수동작 반복
▪ 카운트 도중Clear 없음
▪ 오버플로우(OVF) 인터럽트(MAX=0xFF값일 때 발생)
▪ 비교매치(COMP) 인터럽트(파형을 예상하지 못하기 때문에 추천하지 않음)
 
② CTC Mode(Compare Timer on Compare Match Mode)
▪ 주파수 분주 기능으로 주로 사용
▪ 상향카운터
▪ 0x00 ~ OCR0 계수 동작 반복
▪ OCR0값과TCNT0값이 같으면 카운트 도중Clear
▪ 오버플로우(OVF) 인터럽트
▪ (MAX=OCR0값일 때 발생, COMP인터럽트와 동일하게 작동되기 때문에 추천하지 않음)
▪ 비교매치(COMP) 인터럽트

 


③ FAST PWM
▪ 높은 주파수PWM 파형발생이 필요할 때 사용
▪ 상향카운터(Single-Slope Operation)
▪ 0x00 ~ 0xFF 계수 동작 반복
▪ TCNT0과OCR0의Compare Match되면OC0에LOW출력(COM0 1:0 = 2)
▪ 0xFF →0x00 오버플로우 되면OC0에HIGH출력(COM0 1:0 = 2)


 


④ Phase Correct PWM
▪ 높은 분해능의PWM출력 파형을 발생하는데 사용
▪ 상향카운터0x00 →0xFF
▪ 하향카운터0xFF →0x00
▪ 0x00 ~ 0xFF ~ 0x00 계수 동작 반복
▪ 상향카운터 비교매치 →OC0 = 0 출력(COM0 1:0 = 2)
▪ 하향카운터 비교매치 →OC0 = 1 출력(COM0 1:0 = 2)

 



 3. 타이머/카운트0 제어 실습



[Example 01]
: 아래의 내용은 타이머/카운터0을 이용하여LED가1초마다 ON/OFF 시키는 프로그램이다.

#include "iom128.h"
 
#define sbi(PORTX , BitX)   PORTX |=  (1 << BitX)   // 비트SET 명령정의
#define cbi(PORTX , BitX)   PORTX &= ~(1 << BitX)   // 비트CLEAR 명령정의
 
unsigned char count= 0;
 
#pragma vector=TIMER0_OVF_vect          // 타이머0 Overflow 인터럽트처리루틴
__interrupt void OVF_Interrupt(void)    // 8ms마다인터럽트루틴실행
{
    count++;

    if(count==125)          // 8ms*125=1sec
    {
        if(PINA==0x00)
        {
            PORTA= (0xFF);  // 1111 1111 (LED 전등)
        }             
        else if(PINA==0xFF)
        {
            PORTA= (0x00);  // 0000 0000 (LED 전멸)
        }             
        count = 0;
    }
    TCNT0= 131;             // 125 = 255-TCNT0+1
}
 
void Main_Init(void);
 
int main(void)
{
    Main_Init();
    while(1);
}
void Main_Init(void)
{
    cbi(SREG,7);        // 모든인터럽트비활성화
    PORTA   = 0xFF;     // 포트A 값초기화
    DDRA    = 0xFF;     // 포트A 출력으로설정
    TCCR0   = 0x07;     // 1024분주설정(clkt=16000000/1024=15625Hz)
    TCNT0   = 131;      // 1/clkt0 = 64us, 64us*125=8ms
    TIMSK   = 0x01;     // overflow 인터럽트인에이블
    sbi(SREG,7);        // 모든인터럽트활성화
}


[Example 02]
: 아래의 내용은 타이머/카운터 0을 이용하여 OC0핀에 PWM을 0/25/50/75/100% 듀티비를 나타내는 프로그램이다.

#include "iom128.h"
 
#define sbi(PORTX , BitX)   PORTX |=  (1 << BitX)   // 비트 SET 명령 정의
#define cbi(PORTX , BitX)   PORTX &= ~(1 << BitX)   // 비트 CLEAR 명령 정의
 
void Main_Init(void);           // 초기화 함수 선언
void delay(long time);          // 딜레이 함수 선언
 
int main(void)
{      
    Main_Init();
    while(1)
    {
        OCR0=0;        delay(10000000); // 0%듀티비
        OCR0=64;       delay(10000000); // 25%듀티비
        OCR0=128;      delay(10000000); // 50%듀티비
        OCR0=191;      delay(10000000); // 75%듀티비
        OCR0=255;      delay(10000000); // 100%듀티비
    }
}
void Main_Init(void)
{
    cbi(SREG,7);        // 모든 인터럽트 비활성화
    PORTA   = 0xFF;     // 포트A 값 초기화
    DDRA    = 0xFF;     // 포트A 출력으로 설정
    PORTB   = 0xFF;     // 포트B 값 초기화
    DDRB    = 0xFF;     // 포트B 출력으로 설정
    TCCR0   = 0x67;     // 1024분주설정(clkt=16000000/1024=15625Hz )
                        // Phase Correct PWM모드, COM0100=10설정
    TCNT0   = 0x00;     // 1/clkt0 = 64us, 64us*256=16.384ms
    OCR0    = 0x00;     // 0%듀티비
    TIMSK   = 0x02;     // COMP 인터럽트 인에이블
    sbi(SREG,7);        // 모든 인터럽트 인에이블
}
 
void delay(long time)   // 딜레이 함수 정의
{
    while(time--);
}



 [ 참고자료 ]


[1] Atmel Corporation, ATmega128(L) Datasheet, http://www.atmel.com/devices/ATMEGA128.aspx?tab=documents


End.

written by Yoonseok Pyo
http://robotpilot.net/
http://cafe.naver.com/openrt


Posted by Miobot

AVR 기초 강좌

4. ATmega128의 기능 및 제어 2


ATmega128's function (Interrupt)

2012.12.31

 1. 인터럽트(Interrupt)


ATmega128에는 리셋을 포함하여 모두 35종의 리셋 및 인터럽트 벡터를 가지고 있다. 이러한 인터럽트 구성은 외/내부 장치의 서비스 요청에 MCU가 가장 빠르게 대응할 수 있는 방법이기 때문에 사용자가 원하는 작업을 수행하는 중요한 수단이 된다.

(1) 인터럽트(Interrupt)란?
: CPU 외부의 하드웨어적인 요구에 의해서 정상적인 프로그램의 실행 순서를 변경하여 보다 시급한 작업을 먼저 수행한 후에 다시 원래의 프로그램으로 복귀하는 작업을 말한다.

인터럽트는 짱구다?

 



 



(2) 인터럽트의 종류
: ATmega128의 경우에는 35종의 리셋 및 인터럽트 벡터를 가지고 있는데 아래 그림과 같이 구성되어 있다.

 


▪ 리셋 및 인터럽트 벡터를 분류해보자.
RESET          1개
Ext.INT          8개
TIMER 0        2개
TIMER 1        5개
TIMER 2        2개
TIMER 3        5개
USART0        3개
USART1        3개
ADC             1개
기타             5개
  
▪ 인터럽트우선순위?
인터럽트의 요청이 중복될 수도 있는 경우를 대비하여 각 인터럽트 사이에는 하드웨어적으로 우선순위를 정해두었다. 이에 따라 인터럽트 발생이 동시에 될 경우 우선순위가 높은 인터럽트가 먼저 실행되게 된다.
 
(3) 인터럽트의 제어방법
: 위의 여러 인터럽트를 사용하기 위해서는 SREG 레지스터의 I비트를 Set시켜 모든 인터럽트를 허용 해야 하며 사용할 인터럽트의 개별적인 Enable 비트를 Set시켜야만 한다. 그 사용법에 대해서는 외부인터럽트제어 부분에서 예를 들어 설명하니 참고하기 바란다.


 2. 외부 인터럽트 제어


ATmega128에서 외부 인터럽트가 8개 지원되는데 이는 8개의 외부핀(INT 7~0)을 통해서 입력되는 신호에 의하여 발생하는 인터럽트를 말한다.
 
(1) 외부 인터럽트란?
: 위에서 인터럽트의 종류는 35가지 임을 알았다. 외부인터럽트는 이중 8개에 속하는 것으로서 내부적인 처리 및 연산에 의한 다른 인터럽트와는 달리 아닌 외부핀 INT0~INT7에 직접 입력되는 신호(High & Low)값을 입력 값으로 받아 인터럽트가 걸려 정해놓은 인터럽트 루틴을 실행하는 것을 말한다.

외부 인터럽트 = 달팽이 눈?
달팽이의 눈처럼 생긴 촉수는 외부와의 접촉의 순간, 잎사귀를 먹고 있던 도중이던, 이동 중 이던간에 무조건적으로 달팽이 관속으로 숨어 버린다. 이처럼, 외부인터럽트는 당팽이의 눈(촉수)와 같은 역할을 하여, 외부에서 신호가 들어오면 현재 진행중인 프로그램을 잠시 멈추고, 정해져 있는 일을 수행하게 된다. 

(2) 외부 인터럽트(INT 7~0)의 특징
- 외부 인터럽트는 INT 7~0 핀의 트리거 동작으로 인터럽트가 발생된다.
- LOW / 상승엣지 / 하강엣지 의 방식으로 트리거 신호를 선택할 수 있다.
- 외부 인터럽트는 INT 7~0 핀의 입/출력 방향에 관계없이 인터럽트가 발생된다.
(소프트웨어적으로 데이터를 출력하여 인터럽트를 요구 할 수도 있다.)
- INT 7~4 : I/O클럭이 있어야만 사용가능
- INT 3~0 : 비동기적 검출이 가능하다.( 슬립모드를 깨울 때 이용되기도 한다.)

 
(3) 외부 인터럽트 관련 레지스터
: 외부 인터럽트를 제어하기 위해서는 상태레지스터(SREG)와 외부 인터럽트 관련 레지스터(EIMSK, EICRA, EICRB, EIFR)의 사용법을 알아야 한다.
 
① SREG(Status Register)

 

▪ MCU의 현 상태 및 최근 수치 명령 실행에 대한 결과를 포함한다.
▪ 상태레지스터는 모든 ALU 연산을 수행 후 갱신된다.
▪ Bit7. I (Global Interrupt Enable) : 모든 인터럽트 활성화 비트


② EIMSK(External Interrupt Mask Register)

▪ Bit 7..0 – INT 7~0 Q 비트를 SET(1) 시키면 해당 외부 인터럽트 핀이 활성화 된다.
▪ 단, SREG의 I비트가 1로 SET된 상태여야 한다.


③ EICRA(External Interrupt Control Register A)

▪ 외부 인터럽트의 트리거 방식을 LOW / 상승엣지 / 하강엣지 중에 선택하는 레지스터

ISCn1

ISCn0

설명

0

0

INTn Low 신호시에 일반적인 인터럽트 요청을 한다.

0

1

(reserved)

1

0

INTn의 하강엣지 신호시에 일반 비동기적인 인터럽트를 요청한다

1

1

INTn의 상승엣지 신호시에 일반 비동기적인 인터럽트를 요청한다

 


④ EICRB(External Interrupt Control Register B)

 

▪ 외부 인터럽트의 트리거 방식을 LOW / 상승엣지 / 하강엣지 중에 선택하는 레지스터

ISCn1

ISCn0

설명

0

0

INTn의 Low 신호시에 일반적인 인터럽트 요청을 한다.

0

1

어떠한 신호의 변화에서든 일반적인 인터럽트 요청을 한다.

1

0

INTn의 두 샘플 신호간의 하강엣지 신호시에 일반적인 인터럽트를 요청한다

1

1

INTn의 두 샘플 신호간의 상승엣지 신호시에 일반적인 인터럽트를 요청한다

 


⑤ EIFR(External Interrupt Flag Register)

▪ Bit 7..0 – 외/내부로부터 INT7:0 핀에 인터럽트가 요청되면 해당 비트가 Set(1) 된다. 그 후에 인터럽트 루틴이 실행될 때 해당 비트가 Clear(0)된다.


(4) 외부 인터럽트 동작
①    인터럽트가 활성화(SREG.7 / EIMSK 해당 비트 활성화) 되어 있는 상태에서
②    외부INT의 동작 엣지나 논리신호에 의해 인터럽트가 요청되면
③    제일 우선 INTFn=1 상태로 플래그가 Set되고
④    실행 중이던 메인 프로그램의 프로그램카운터 값을 스택에 저장하게 된다.
⑤    그 후 해당 인터럽트 벡터로 점프하게 되며
⑥    지정된 인터럽트 루틴을 실행하는 동시에 INTFn=0 상태로 플래그가 Clear된다.
⑦    해당 인터럽트의 루틴이 처리된다.
⑧    해당 인터럽트의 루틴이 끝나게 되면 RETI 명령을 받는다.
⑨    스택으로부터 저장된 프로그램카운터 값을 로드 한다.
⑩    동작 중이던 프로그램 위치로 복귀하여 실행 중이던 부분부터 메인 프로그램이 재작동된다.
 
위의 내용은 외부인터럽트의 처리과정을 자세히 서술하여 설명한 것입니다. 이게 무슨 말인지 받아 들이기 어려운 것은 우선 모르는 용어가 많이 나왔을 것이며, 벡터 주소 값에 대한 이해가 부족한 탓이죠. 처음에는 어려울 수도 있으니 이해가 안 된다면 우선 넘어가고 후에 자세히 읽어 본다면 인터럽트의 이해가 쉬워 질 것입니다.
 
 


 3. 외부 인터럽트 실습




[Example 01]
: 아래의 소스는 아래의 그림과 같이 간단한 스위치회로를 구성하여 스위치를 눌렀을 때 외부인터럽트가 걸려 메인프로그램(LED ALL OFF)에서 인터럽트루틴(LED ALL ON)이 실행되기 위한 프로그램이다.

 


#include "iom128.h"
 
#define sbi(PORTX , BitX)   PORTX |=  (1 << BitX)   // 비트 SET 명령 정의
#define cbi(PORTX , BitX)   PORTX &= ~(1 << BitX)   // 비트 CLEAR 명령 정의
 
void delay(long time);                  // 딜레이 함수 선언
 
#pragma vector=INT0_vect                
__interrupt void INT0_Interrupt( void ) // INT0 인터럽트 처리 루틴(ISR)
{  
    PORTA = 0xFF;       // 1111 1111 (LED 전등)
    delay(1000000);     // 시간 지연 함수
}
void main(void)
{
    sbi(SREG,7);        // SREG I비트 SET
    sbi(EIMSK,INT0);    // EIMSK INT0비트 SET

    DDRA = 0xFF;        // PORTA 출력포트로 설정
    DDRD = 0x00;        // PORTD 입력포트로 설정
                        // PORTD는 출력으로 설정해도 무방하다.
    while(1)
    {
        PORTA= 0x00;    // 0000 0000 (LED 전멸)
    }      
}
 
void delay(long time)   // 딜레이 함수 정의
{
    while(time--);
}



 [ 참고자료 ]


[1] Atmel Corporation, ATmega128(L) Datasheet, http://www.atmel.com/devices/ATMEGA128.aspx?tab=documents


End.

written by Yoonseok Pyo
http://robotpilot.net/
http://cafe.naver.com/openrt


Posted by Miobot