본문 바로가기

Hacked Brain/embeddedland.net

80c196kc - (7) PWM( pulse width modulation )

출처 :
임베디드 커뮤니티 [W.O.E]
cafe.naver.com/okh0217
7..PWM(pulse width modulation)

이름에서 대충 집작할 수 있듯이 펄스를 주되 너비를 변화시켜주면서 뭘 어떻게 해보겠다는 것이다.

그럼 과연 무엇을 할수 있을까...
뭐 여러 가지가 있겠지만 모터를 동작시킬수도 있고 PWM출력단에 부가회로를 구성하여
D/A 컨버터로도 활용할 수 있다. 응용에 관한 것은 스스로 찾아보기바란다.
나두 뭐 별로 써먹어본건 없다...-.-
☞알아야할 단어 --->‘듀티비’펄스의 한주기중 high(5V)가 갖는 비율.
마이크로컨트롤러가 PWM 기능을 제공한다는 것은 별다른 회로를 설계할 필요없이 원하는
듀티비만 세팅해주면 고것에 맞게 알아서 사각파가 출력된다는 것을 말한다.
하지만 주파수는 고정되어 있어서(두가지중 하나를 선택해야함) 프로그래머가 정할수는 없는데
이건 80c196kc가 그렇다는것이지 그렇지 않은 기종(예를 들어 80c196MC/MD/MH)도 있다.
이제부터 어떻게 하는지 구체적으로 알아보자고 할것도 없이 그냥
PWMx_CONTROL (x=0~2) 레지스터에 값을 넣으면 알아서 듀티 사이클이 설정된다.
아주 간단하다. ^^

duty비 계산 = PWMx_CONTROL / 256

준비 과정 80c196kc는 P1.3 , P1.4 , P2.5를 PWM 출력으로 쓸 수 있고
IOC1, IOC3 레지스터로 설정해야한다.

먼저 카운터가 몇 state 마다 증가할것인지 IOC2 레지스터로 설정하고
PWMx_CONTROL 레지스터는 원하는 듀티비에 맞게 0~255의 범위로 설정한다.
(듀티사이클은 0% ~ 99.6%가 됨)

동작 과정

8비트 카운터값가 overflow되면 RS 플리플롭의 S가 1이 되어 Q에 연결된 PWMx 출력이 1이 되고 PWMx_CONTROL의 값이 홀딩 레지스터에 저장된다..
8비트 카운터는 계속해서 동작하는데 홀딩레지스터와 값과 같아지면
이번엔 RS FF의 R이 1이 되고 PWMx 출력은 0이 된다.
다음은 IOC2.2의 값에 따른 입력주파수의 선택과 그에 따른 PWM 출력주파수이다.

   기준(20Mhz)

IOC2.2 = 0

IOC2.2 = 1

8비트 카운터의

입력주파수

클럭입력주파수의 1/2이 입력됨

1/2분주기를 이용하여 클럭입력주파수의 1/4이 입력된다.

PWM주기

0~255 state 사이의 시간을 1로 할수 있다.

  ∴한 펄스의 주기는 256 state 즉25.6us

0~512 state 사이의 시간을 1로 할수 있다.

  ∴ 한 펄스의주기는 512 state 즉51.2us

(주파수를 2분할하므로 주기는 2배가 된다.)

PWM의 출력주파수

1/25.6us = 39.1Khz

1/51.2us = 19.5Khz

ex)PWM0_CONTROL=8AH  ->듀티비 

138/256 = 54%

총 25.6us 중에서 25.6×0.54=13.8us가 1이고 25.6-17.24=8.36us가 0이다

51.2×0.54=27.6us가 1이고 51.2-27.6=23.6us가 0이다.


◆예제 소스

/*

PWM을 주어 LED를 깜빡거리게하는 프로그램
output : P1.3 , P1.4 , P2.5*/
#pragma model(kc)
#include <80c196.h>
void delay(short i)
{
 while(i--);
}
void main(void)
{
 unsigned char reg1,reg2,reg3;
 reg1 = reg2 = reg3 = 0;
wsr = 0; ioc1 = 0x01;
/* P2.5를 표준 출력포트가 아닌 PWM0출력핀으로 설정 */
ioc2 = 0x04; /* PWM출력 주기를 2분주 허용 -> 512state*/
wsr = 0x01; /* PWM1,2 enable*/
timer2 = 0x0c; /* 80c196h에 ioc3가 없으므로 같은 번지를 차지하는 timer2로 대신함 */
/* IOC3.2 = 1 ,IOC3.3 = 1 -> P1.3,P1.4를 PWM출력단자로 설정한다. */
wsr = 0;
do{
 pwm_control = reg1;/* == PWM0_CONTROL 수평윈도우 0에서 write */
 pwm1_control = reg2; /* 수평 윈도우 1 R/W */
 ioc1 = reg3;/* == PWM2_CONTROL = reg3;*/
 delay(1000);
 reg1++;
 reg2 += 0x05;
 reg3 += 0x0a;
}while(1);