본 내용은 http://mil.ufl.edu/~achamber/servoPWMfaq.html에 있는
Generating PWM signals using Timers in the ATMega chip라는 글을
적당히 우리말로 번역한 것임.
(해석안돼는 것은 적당히 마음대로 의역했음... 사실 대부분 거의 의역했음. OTL~)
본인 공부를 위해서 번역한 것이기 때문에
오역에 의해 일이 아주 잘 못되더라도 절대 책임 지지 않겠음.
--------------------------------------------------------------------------------
ATmega chip에 있는 Timer를 이용해 PWM 신호를 발생하기
이 글은 ATMega8 칩의 Timer1을 이용해 멀쩡한 서보모터 (unhacked servos)를 제어하는 가이드이다.
이는 ATmega128이나 다른 Timer를 사용하더라도 기술과 아이디어는 상황에 따라 쉽게 적용 가능할 것이다.
서보 모터 제어에 대한 기초 이론 :
서보 모터에는 아래와 같이 선이 세 가닥 있다.
- 빨강 = Vcc (4.8V ~ 6V, 데이터시트를 참고하라)
- 검정 = 접지
- 흰색 = PWM 입력
서보 모터의 PWM 입력 핀에 PWM (Pulse Width Modulation) 신호를 줘서 제어 할 수 있다.
서보 모터는 입력 받은 신호와 현재 위치를 비교해서 적절히 위치를 조절한다.
서보모터의 내부 회로는 지속적인 50Hz의 PWM 신호를 요구한다.
(50Hz 신호는 매 20ms마다 반복 된다는 의미다.)
- 1/50 Hz = 20 ms
서보모터에 줄 신호는 High (5V)로 1 ~ 2 ms 이고 Low (0V)로 20ms 주기의 나머지이다.
High 신호의 길이로 서보 모터의 위치를 결정한다.
서보 모터는 위치를 유지하기 위해서 지속적으로 신호를 받아야 함을 명심하자.
- 1.0ms = full left
- 1.5ms = middle
- 2.0ms = full right
만약 90도 회전을 할 수 있는 서보 모터를 사용한다고 하자.:
- full left = 0도
- middle = 45도
- full right = 90도
다른 회전 범위를 갖는 다른 서보 모터는 full left, middle, and full right가
다른 각에 대응할 것이다.
이때, 전체 범위를 활용하기 위해서 2.0ms 보다 크거나 1.0ms 보다 작은
High Pulse를 필요 할 것이다.
Phase and Frequency Correct mode:
1 ~ 2ms의 High 신호를 가진 50Hz의 신호를 발생하기 위해서,
Atmel의 ATMega 칩에있는 Timer의 Phase and Frequency Correct mode를 사용할 것이다.
Phase and Frequency Correct mode에서 Timer는 0에서 시작해서,
ICRn (n은 타이머 번호, 여기에서는 Timer1을 사용하기 때문에 ICR1이다)으로 불리는
사용자가 지정한 값까지 증가한 후 다시 0으로 감소한다.
50Hz 신호를 발생하려면 Count 증가/감소가 20ms가 되어야 한다.
ICR1 값을 결정하기 위해서는, 두가지를 알아야 한다.:
- System clock speed
- Timer clock speed
다행이도 system clock speed는 이미 알고 있는 요소이다.
만약 MDMicro Maveric board를 사용한다면, 대부분 16MHz이다.
Timer clock speed는 Prescaler에 의해 나누어진 system clock speed이다.
Presclaer는 TCCRn 레지스터에 있는 CSn2:0 비트로 선택한다(n은 Timer Number이다.).
예를들면, Timer1의 속도는 TCCR1B 레지스터에 있는 CS1 비트로 결정한다.
아래 그림은 ATMega8의 데이터시트에서 얻은 것이다.
Clock Section 비트는 TCCR1B 레지스터의 마지막 세 비트이다.
clkIO는 system clock을 의미한다.
예를들면 system clock가 16MHz라면
Timer는 Prescaler에 따라 16 MHz, 2 MHz, 250 KHz, 62.5 KHz, 15.625 KHz가 될 수 있다.
ATmega의 데이터시트에는 원하는 주파수를 발생하는 아래 식을 제공한다.
이 식은 system clock frequency(fclk_I/O), prescaler (N = 1, 8, 64, 256, or 1024),
ICR1(TOP) 그리고 발생하는 PWM frequency (fOCnxPFCPWM) 사이의 관계를 보여준다.
16MHz의 system clock frequency에서 50Hz를 발생하기 위한 Prescaler와
TOP(ICR1)의 관계는 다음과 같다.
- Prescaler N = 1 then TOP(ICR1) = 160000
- Prescaler N = 8 then TOP(ICR1) = 20000
- Prescaler N = 64 then TOP(ICR1) = 2500
- Prescaler N = 256 then TOP(ICR1) = 625
- Prescaler N = 1024 then TOP(ICR1) = 156.25
주의: 여기서 Prescaler로 1이나 1024는 16MHz에서
주의: 50Hz PWM을 발생하기위해 사용 할 수 없다.
주의: 이유는 Prescaler 1은 160000은 TCR1에 대입하는데 너무 크기 때문이다.
주의: TCR1는 16비트 레지스터로 0부터 65535까지 값을 가질 수 있다.
주의: Prescaler 1024는 ICR1에 소수를 입력할 수 없기 때문에 사용할 수 없다.
본인은 prescaler를 8로, ICR1을 20000으로 하는 것을 추천한다.
그 이유는 1 ~ 2 ms High pulse를 얻기위해 OCR1A를 1000에서 2000까지
변화 시킬 수 있기 때문이다.
OCRxn은 무엇인가?
PWM 발생에대한 ATMega 데이터시트를 읽어 봤다면,
OCRxn이 무엇이며 ICRn과의 차이가 무엇인지 궁금할 것이다.
면서 OCRxn에서 x는 Timer number를 정의하고 n은 제어할 서보 모터를 정의 한다.
대부분의 Timer는 여러개의 서보 모터를 제어 할 수 있다.
예를들면 Timer1에서는 OCR1A, OCR1B 그리고 때때로 OCR1C를 설정 할 수 있다.
(각각의 Timer가 얼마나 많은 서보 모터를 제어 할 수 있는지에 대해서 궁금하면
데이터시트를 읽어라.)
OCRxn과 ICRn에 대해서 간단히 설명하자면:
ICRn는 서보 모터를 제어하기위해 50Hz PWM 신호를 발생한다.
OCRxn은 서보 모터의 실제 움직임을 제어한다.
일단 ICRn (Timer1에서는 ICR1)을 설정하면, 값을 변경하면 안된다.
반면, OCRxn (Timer1에서는 OCR1A)은 서보 모터 위치 제어를 위해 변화 시켜줘야 한다.
여기 ATMega8 데이터시트에서 가져온 그림은
OCRxn 값이 어떻게 신호 길이를 변화 시키는지 보여준다.
이 그림은 우리 목적에 약간 헤깔리는데,
CRn이 변하고 다양한 주파수의 신호를 발생하기 때문이다.
지속적인 50Hz 신호를 원하기 때문에 절대 ICRn값을 한번 설정한 이후 바꿔줘서는 안된다.
OC1A를 어떻게 사용할 것인가를 보여 주는 것이다.
TCNT1 (Timer Counter 1)은 Timer1의 count 값 이다.
TCNT1은 0에서 시작해 ICR1 (Input Compare Register 1) 값 까지 증가한 후
다시 0으로 감소한다.
TCNT1이 증가하는 동안 OCR1A (Output Compare Register 1A)와 같아지면,
OC1A (Output Compare 1A)이라 불리는 출력 핀은 High가 된다.
TCNT1이 감소하는 동안 OCR1A (Output Compare Register 1A)와 같아지면
OC1A는 Low가 된다.
TCNT1 = OCR1A가 되는 순간 OC1A의 논리값이 바뀐다고 생각해도 된다.
비슷한 이름의 레지스터와 출력 핀 때문에 이것이 헤깔릴것이라 생각한다.
그래서 아래에 정리 해 두었다.
- TCNT1 = Timer1의 값
- ICR1 = Timer1의 최대값 설정 (50 Hz 신호 발생)
- OCR1A = Sets when the PWM 신호가 바뀌는 시점을 설정.
- OC1A = PWM 신호가 나오는 출력 핀. 어디 있는지는 데이터시트를 보도록...
서보 모터 위치 제어를 위해서는, OCR1A 값을 1000부터 2000까지 변화시키면 된다.
C언어를 예로 들면:
OCR1A = 1500;
혹은 모든 가능한 서보모터 제어 위치를 보기 위해서는 for 문을 쓸 수 있다.:
for( OCR1A = 1000; OCR1A != 2000; OCR1A++ )
{
delay_ms(1);
}
나는 이 글로 당신이 ATMega128이나 ATmega8 칩을 이용해
서보 모터 제어 하는 것을 이해하기를 바란다.
Timer에 내장된 PWM 발생 장치를 이용하는 장점은 다음과 같다.
- 일단 모든 레지스터를 정확하게 해 두면 코드가 간단해 진다.
- 서보 모터 제어에 처리시간이 필요 없다.
- 서보 모터 성능이 다른 인터럽트나 무거운 프로그램 계산에 영향을 받지 않는다.
단점은 다음과 같다.
- 타이머마다 제한된 서보 모터만 제어할 수 있다.
보통 2개에서 3개이다. 그러나 여러 타이머는 PWM 발생기를 내장하고 있다.
- 그 외에 생각할 수 있는 장점은 없는 듯...
문제 해결:
만약 당신이 여전히 서보 모터를 제어 못하고 있다면:
서보 모터가 망가졌는가? 서보 모터가 이미 작동됨을 확인한 다른 보드로 테스트 해 보아라.
또 VCC나 GND에 연결 했을 경우 서보 모터가 떨릴 수 있다.
그게 아니면 서보 자체에 무언가 문제가 있다.
정확한 OC1A 출력 핀을 찾았고 당신의 코드에 출력으로 설정해 두었는가?
좋은 방법으로는 오실로스코프로 50Hz 신호와 정확한 High와 Low 펄스가 발생하는지
OC1A 핀을 측정해 보는 것이다.
만약 신호가 기대했던 것과 다르다면 system clock speed를 확인해 보아라.
Fuse Bit가 종종 ATMega의 내부 클럭인 1MHz clock로 되어 있을 수도 있다.
Guide to generating PWM Servo control code with CodeVision
(번역자 曰 : 본인은 CodeVision을 안 쓰기 때문에
이 녀석은 번역하지 않겠음. 혹 링크가 깨어졌다면 첨부된 문서를 참조 할 것)
Last updated July 30, 2006. Please email me with any corrections or areas that need clarification.
Andrew Chambers (achamber at mil dot ufl dot edu)
원문.pdf