본문으로 바로가기

ATmega128 타이머를 이용한 DC모터 제어

category MCU/AVR 2019. 8. 13. 01:29
반응형

오늘 포스팅할 내용은 ATmega128 타이머를 이용한 DC 모터 제어 방법입니다. 우선 모터를 제어하기 전에 PWM(Pulse Width Modulation)을 알아보겠습니다.


PWM을 말 그대로 펄스폭 변조로 디지털 출력 핀을 사용하여 비례 제어 신호를 외부 장치에 적용하는데 사용되는 일반적인 방법입니다. 펄스폭을 조절하면 평균 전압을 제어를 할 수 있으며 이를 이용해 DC 모터에 속도를 조절할 수 있게 됩니다. 여기서 Duty라는 개념이 나오는데 한 주기 동안에 ON(High)이 되어 있는 시간 Duty라고 하며 Duty/Period의 비율을 Duty Ratio라고 합니다.


Duty Ration = t1/T




타이머 카운터

- 타이머 카운터는 펄스의 수를 카운터를 해주는 기능을 갖고 있습니다. 타이머는 시스템 클럭을 카운터하고, 카운터는 외부 입력을 카운터 합니다. 타이머에는 종류가 여러 개가 있고 타이머에 따라 기능이 다른데, 그중에 저희가 사용할 기능은 타이머 카운터 0를 이용한 PWM 기능입니다.



ATmega128 타이머 카운터 핀


- 타이머 0을 쓰면 출력 OC0

- 타이머 1을 쓰는 경우 출력 OC1A, OC1B, OC1C

- 타이머 2을 쓰면 출력 OC2

- 타이머 1을 쓰는 경우 출력 OC3A, OC3B, OC3C



ATmega128 타이머 카운터 종류




타이머 카운터 0 레지스터


TTCR0 : 동작 모드 및 분주비 설정 레지스터

- CS02/CS01/CS00 : 분주비를 결정합니다.

- COM01/COM00 :  OC0 핀의 동작을 제어하며, 기능은 WGM의 Bit 설정에 따라서 달라진다.


-   WGM1/WGM0 : 어떤 형식의 Waveform Generation을 사용할 것인지 결정합니다.



TCNT0 : 카운터 값을 저장하고 있는 레지스터



OCR0 : TCNT0와 비교하기 위한 카운터 값을 저장하고 있는 레지스터

- TCNT0의 값과 계속 비교한다.



ASSR : 외부 비공기 입력 유/무를 설정하는 레지스터

- AS0 : '0'이면 동기 모드 '1'이면 비동기 모드로 동작한다.



TIFR : 타이머 카운터 0, 1, 2의 인터럽트 Flag를 저장하는 레지스터



TIMSK : 인터럽트 요청 가능/불가능을 결정하는 레지스터



타이머를 이용해 1초 만드는 법


외부 크리스탈을 16MHz 사용하고 있기 때문에 1024분주(CS02 = '1', CS01 = '1', CS00 = '1')를 하면 다음과 같다.


16MHZ/1024 = 0.015625MHz


시간(T) = 1/f(주기)


주기에 0.015625MHz를 대입하면 0.000064초가 된다. TCNT0에서 125회 카운트를 하게 되면 다음과 같다.


0.000064 X 125 = 0.008초


이후 인터럽트를 125회 발생시키면 0.008초 X 125 = 1초가 된다.





위상 보정 PWM의 이해



고속 PWM 모드와 달리 위상 보정 PWM모드는 양쪽 경사면을 사용하여 낮은 주파수에서 동작하며, 높은 해상도를 제공해준다. 이러한 구조로 인해서 모터 제어에 적합합니다.


위상 보정 PWM에서 TCNT0의 경우 값이 고정이 되어있어 0x00 -> 0xFF 업 카운트와 0xFF -> 0x00 다운 카운트를 반복하며, 업 카운트에서 OC0가 '0'이 되고 다운 카운트에서 OC0가 '1'이 됩니다.




위에 공식을 보면 Fast PWM과 비교했을 때 1/2의 주파수 특성을 갖고 있습니다.



이러한 특성을 이용해서 OC0을 특정한 duty ratio의 출력으로 만들 수 있습니다. 이제 모터 제어를 해보도록 하겠습니다. 저는 아래와 같이 회로 구성을 했습니다.



DC모터 회로 배치


<ATmega128 핀 할당>


<DC 모터 & 드라이버>


DC 모터란?

- 직류 전원으로 동작을 하며 속도 및 방향 제어를 쉽게 할 수 있고 저렴하기 때문에 많이 사용되는 모터입니다.


DC모터에 드라이버를 사용하는 이유?

- 모터를 TTL Level에서 제어가 가능하며, 모터의 방향을 제어 할 수 있게 됩니다. 또한 ATmega128의 Pin 전류는 40mA인데, 이를 보완해주는 역할을 합니다.




소스 코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#define F_CPU 16000000UL // 외부 크리스탈 16MHz
#include <avr/io.h>
 
 int main(void)
 {
     
    DDRA = 0xFF// 모든 포트 출력으로 설정.
    DDRB |= (1<<DDB4); // OC0
    
    TCCR0 = 0x64;
    TCNT0 = 0;
    
    OCR0 = 0x20// OCR0에 따라서 Ratio가 달라진다.
    
     /* Replace with your application code */
     while (1)
     {
         if((PINB&0x10== 0x10)
            PORTA =0x01;
        else    
            PORTA = 0x00
     }
     return 0;
 }


위에 소스는 OCR0에 따라서 DC 모터의 속도가 가변 하는 코드입니다. DC 모터가 PORTA에 있으니 출력으로 DDRA = 0xFF를 설정하고, PORTB 4번 핀이 OC0로 출력을 설정했습니다. 


OC0가 출력이 되면 모터가 정방향으로 회전, 출력이 아닌 경우에는 멈춰서 속도를 조절하고 있습니다. 타이머 레지스터를 확인해보겠습니다.


TCCR0 



- TCCR0를 0x64로 설정을 하였습니다. FOC0는 위상 보정 PWM 시 호환성을 위해 '0'을 사용하도록 Datasheet에 나와있습니다.



- COM01 = '1'이고 COM00 = '0'인 경우에 업 카운트시 OC0가 '0'이 되고 다운 카운트 시에는 '1'이 됩니다. 즉, 원래 순서대로 카운팅을 합니다. 참고로 COM의 설정은 타이머 카운터의 모드에 따라서 달라집니다.


- 위상 보정 PWM을 사용하기 위해 WGM01 = '1'이고 WGM00 = '0'입니다.



- 분주비를 64로 하기 위해서 CS02 = '1', CS01 = '0', CS00 = '0'를 설정하였습니다.


TCNT0


 - 초기값을 0으로 설정하여 0부터 카운팅을 시작합니다.



OCR0 


 - OCR0와 TCNT0 값이 일치하게 되면 업 카운트, 다운 카운트 조건에 따라서 OC0의 값이 High, Low가 됩니다.


간단하게 PWM으로 모터 속도를 조절했는데요, 사실 실제로 모터를 정밀 제어를 하기 위해서는 쉽지가 않습니다. 공식도 필요하고 엑셀 노가다도 필요하고 모터에 대한 지식도 어느정도 필요합니다. 아무튼 이상으로 마치겠습니다.



2019/05/11 - [MCU/AVR] - ATmega128 Delay함수 사용 방법

2019/04/22 - [MCU/AVR] - ATmega128 입출력 제어

2019/04/15 - [프로그래밍/C#] - C#을 이용한 시리얼 통신(포트 검색/연결/해제)

2019/04/08 - [프로그래밍/C#] - [Zedgraph] C# 그래프 라이브러리를 이용한 실시간 그래프

2019/04/05 - [MCU/AVR] - [atmel studio7]ATmega128 프로젝트 생성

반응형

'MCU > AVR' 카테고리의 다른 글

ATmega128 블루투스 제어(HC-06)  (1) 2019.11.24
ATmega128 Delay함수 사용 방법  (3) 2019.05.11
ATmega128 입출력 제어  (2) 2019.04.22
[atmel studio7]ATmega128 프로젝트 생성  (6) 2019.04.05