[임베디드/C] PWM
PWM
예전에 동아리에서 아두이노만질 때, PWM 핀으로 LED 밝기를 조정한 적이 있다.
위키피디아에 PWM치면 나오는 사진인데, 듀티사이클을 조정해서 50%로 하면 LED의 밝기가 절반이 된것 같은 착각을 줌으로써 아날로그 데이터를 표현할 수 있다. PAM, PCM같은 펄스 변조방식이 있긴한데, PWM은 펄스의 폭으로 아날로그 데이터를 디지털로 변환한다고 보면 된다. 아날로그 데이터를 샘플링하고 그 값들 각각을 듀티사이클로 표현하는 것인데, 100이라는 샘플을 그냥 이진수 배열로 내보내는 다른 방식과 다르게 진짜 비트를 100번 찍어내는 방식때문에 저장공간이 많이 필요하다. 그래서 데이터 저장이나 전송으로는 잘 사용하지 않고 LED 밝기 제어나 모터 속도 제어같은 곳에 많이 쓰인다.
LED 밝기 조정 예제
#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>
#define LED_TIME 20
void turn_on_LED_in_PWM_manner(int dim)
{
int i;
PORTB = 0x01;
for(i = 0; i < 256; ++i) {
if(i>dim) PORTB = 0x00;
_delay_us(LED_TIME);
}
}
int main()
{
DDRB = 0x01;
int dim = 0;
int direction = 1;
while(1) {
turn_on_LED_in_PWM_manner(dim);
dim += direction;
if(dim == 0) direction = 1;
if(dim == 256) direction = -1;
}
return 0;
}
위 코드의 경우, turn_on_LED_in_PWM_manner함수가 cpu 클럭의 거의 대부분을 차지하게 되어 다른 작업을 할 수 있는 여지가 없어진다. 하드웨어에 PWM 신호출력을 맡길 수가 있는데, ATmega128에도 아두이노처럼 PWM 신호출력을 파형 생성기에 맡길 수가 있다. 타이머/카운터에 비교일치 인터럽트가 생길 경우, 파형생성기를 통해 신호를 출력할 수가 있는데 이를 이용하면 된다.
8bit Timer/Counter PWM
고속 PWM과 위상 교정 PWM모드가 있다. 이 둘의 차이는 주파수와 해상도인데, 고속 PWM에서의 PWM주파수는 타이머/카운터에 공급되는 주파수를 (TOP+1)값으로 나눈 값이다. $f_FPWM = {f_osc \over {N \cdot (TOP + 1)}} = {f_osc \over {N \cdot 256}}$ 위상 교정 PWM에서의 PWM주파수는 $f_PCPWM = {f_osc \over {N \cdot (2 \cdot (TOP + 1) - 2)}} = {f_osc \over {2 \cdot N \cdot TOP}} = {f_osc \over {N \cdot 510}}$ 이다.
둘의 파형을 비교해보면, 고속모드의 경우 펄스들이 시작점에서 일치하도록 정렬되어있지만 위상교정모드의 경우 펄스들의 중심이 공급 주파수의 중심과 일치하도록 되어있다.
관련된 레지스터는 TCCRn 레지스터이고 WGM 비트를 설정하여 파형 생성 모드를, COM 비트로 비교일치 시 어떻게 동작할 것인지를 결정한다.
16bit Timer/Counter PWM
고속, 위상 교정, 위상 및 주파수 교정 모드가 있다. TCCRnA와 TCCRnB 레지스터로 모드 선택과 파형 생성 설정을 한다.
고속 PWM 모드
총 다섯 가지가 있고 최소 해상도 2비트, 최대 해상도 16비트이다. TOP값을 0x00FF, 0x01FF, 0x03FF로 설정하면 각각 8비트, 9비트, 10비트의 해상도를 가질 수 있고 ICRn이나 OCRnA 레지스터에 TOP값을 직접 지정할 수 있는 두 모드의 경우 2비트에서 16비트 중 자유롭게 선택할 수 있다. 나머지는 8비트 타이머/카운터의 경우와 같다
위상 교정 PWM 모드
7, 8, 9 비트의 고정 해상도를 가지는 3개의 모드와 가변 해상도를 가지는 2개의 모드 총 5개의 모드가 있다.나머지는 8비트의 경우와 같다.
위상 및 주파수 교정 PWM 모드
16비트 타이머/카운텅ㅔ서만 사용할 수 있는 모드다. 위상 교정모드와의 차이점은 OCRnx레지스터와 TOP값을 업데이트하는 시점이다. 위상 교정모드의 경우 TOP에서, 위상 및 주파수 교정 모드의 경우 BOTTOM에서 업데이트한다. 그래서 위상 교정모드에서는 TOP에서 다음 TOP까지를 하나의 주기로, 위상 및 주파수 교정 모드의 경우 BOTTOM에서 다음 BOTTOM까지를 하나의 주기로 한다. 이 경우, TOP이 바뀌었을 때, 위상 및 주파수 교정모드는 한 주기 내에서 항상 대칭이 된다.
카운터를 이용한 LED 점멸 예제
0번 타이머의 고속 PWM모드로 led의 밝기를 변경해보자.
#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>
int main()
{
int dim = 0;
int direction = 1;
DDRB |= (1 << PB4);
TCCR0 |= (1 << WGM01) | (1 << WGM00);
TCCR0 |= (1 << COM01);
TCCR0 |= (1 << CS02) | (1 << CS01) | (1 << CS00);
while(1) {
OCR0 = dim;
_delay_ms(10);
dim += direction;
if(dim == 0) direction = 1;
if(dim == 255) direction = -1;
}
return 0;
}
끝
댓글남기기