AVR 연습포스팅을 4개월 만에 쓰네요.. 다른 포스팅 보다 이것이 더 중요해 보임에도 말이죠...
사실 이제 여러가지로 포스팅이 어려워져서 비 주기적으로 포스팅 하게 되었습니다.
따라서 부족한점이 많더라도 이해 부탁드립니다.^
그래서 4개월전 포스팅인 소프트웨어 PWM에 이어 하드웨어 PWM 사용법을 올려봅니다.
바로 Studio와 Vision 코드를 확인해 보도록 하지요..!
사용된 회로도를 볼까요!
회로도의 변화는 거의 없는 상태이고 이 회로에서 사용되어지는 LED는 OC0A라고 Netlist되있는 LED7번과 OC0B라고 Netlist되있는 LED5번 입니다.
이에 따른 차이점은 소프트웨어 PWM의 경우 타이머/카운터로 시간을 조절해서 입출력으로 출력하기 때문에 모든 포트에서 PWM을 사용할수 있지만, 하드웨어 PWM의 경우 AVR 내부에 설계되어져 출력으로 설계되어 있는 포트만 하드웨어 PWM 기능을 사용할 수 있습니다.
Attiny2313은 8비트와 16비트의 하드웨어 PWM을 지원하고, 8비트는 OC0A와 OC0B로 각각 PB2, PD5번 핀으로 사용할수 있고 16비트는 OC1A, OC1B로 PB3, PB4핀에서 사용 할 수 있습니다.
CodeVisionAVR용 소스코드
#include <tiny2313.h> // Tiny2313의 입출력 관련 헤더파일을 포함합니다.
#include <delay.h> // 지연함수 관련 헤더파일을 포함합니다.
unsigned char i=0; // 반복용으로 사용하기 위한 변수 i를 생성합니다.
void main(void) // 메인함수를 호출합니다.
{
DDRB=0x04; // 포트B의 2번핀만 출력으로 사용합니다.
PORTB=0x00; // 포트B의 2번핀의 초기값을 0V (논리0)으로 설정합니다.
DDRD=0x20; // 포트D의 5번핀만 출력으로 사용합니다.
PORTB=0x00; // 포트D의 5번핀의 초기값을 0V (논리0)으로 설정합니다.
/*-- WGM02, WGM01, WGM00 비트가 011로 Fast PWM모드로 설정합니다.
그리고 COM0A1, COM0A0 비트가 10 이므로 OCR0A값과 TCNT0값이 같을 때 OC0A핀에
5V가 출력되게 됩니다. 같은 방식으로 OC0B도 동일하게 동작합니다. */
TCCR0A=(1<<COM0A1) | (0<<COM0A0) | (1<<COM0B1) | (0<<COM0B0) | (1<<WGM01) | (1<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (1<<CS00);
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
while (1) // 아래구문을 무한 반복합니다.
{
for(i=0;i<255;i++) // 변수i를 255가 될때까지 아래 구문을 반복합니다.
{
OCR0A=i; // 변수 i 값을 OCR0A 레지스터에 입력합니다. (PWM은 변수i / 255)
OCR0B=i; // 변수 i 값을 OCR0B 레지스터에 입력합니다. (PWM은 변수i / 255)
delay_ms(5); // 위 상태를 약 5mS간 유지합니다.
}
for(i=255;i>0;i--) // 255가 된 변수i가 0이 될때까지 아래 구문을 반복합니다.
{
OCR0A=i; // 변수 i 값을 OCR0A 레지스터에 입력합니다. (PWM은 변수i / 255)
OCR0B=i; // 변수 i 값을 OCR0B 레지스터에 입력합니다. (PWM은 변수i / 255)
delay_ms(5); // 위 상태를 약 5mS간 유지합니다.
}
}
}
AVR Studio용 소스코드
#include <avr/io.h> // 입출력 관련 헤더파일을 포함합니다.
#define F_CPU 8000000UL // 사용하는 크리스탈 주파수를 상수로 설정합니다.
#include <util/delay.h> // 지연함수 관련 헤더파일을 포함합니다.
unsigned char i=0; // 반복용으로 사용하기 위한 변수 i를 생성합니다.
int main(void) // 메인함수를 호출합니다.
{
DDRB=0x04; // 포트B의 2번핀만 출력으로 사용합니다.
PORTB=0x00; // 포트B의 2번핀의 초기값을 0V (논리0)으로 설정합니다.
DDRD=0x20; // 포트D의 5번핀만 출력으로 사용합니다.
PORTB=0x00; // 포트D의 5번핀의 초기값을 0V (논리0)으로 설정합니다.
/*-- WGM02, WGM01, WGM00 비트가 011로 Fast PWM모드로 설정합니다.
그리고 COM0A1, COM0A0 비트가 10 이므로 OCR0A값과 TCNT0값이 같을 때 OC0A핀에
5V가 출력되게 됩니다. 같은 방식으로 OC0B도 동일하게 동작합니다. */
TCCR0A=(1<<COM0A1) | (0<<COM0A0) | (1<<COM0B1) | (0<<COM0B0) | (1<<WGM01) | (1<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (1<<CS00);
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
while (1) // 아래구문을 무한 반복합니다.
{
for(i=0;i<255;i++) // 변수i를 255가 될때까지 아래 구문을 반복합니다.
{
OCR0A=i; // 변수 i 값을 OCR0A 레지스터에 입력합니다. (PWM은 변수i / 255)
OCR0B=i; // 변수 i 값을 OCR0B 레지스터에 입력합니다. (PWM은 변수i / 255)
_delay_ms(5); // 위 상태를 약 5mS간 유지합니다.
}
for(i=255;i>0;i--) // 255가 된 변수i가 0이 될때까지 아래 구문을 반복합니다.
{
OCR0A=i; // 변수 i 값을 OCR0A 레지스터에 입력합니다. (PWM은 변수i / 255)
OCR0B=i; // 변수 i 값을 OCR0B 레지스터에 입력합니다. (PWM은 변수i / 255)
_delay_ms(5); // 위 상태를 약 5mS간 유지합니다.
}
}
return 0; // 메인함수에 0을 리턴합니다. (프로그램 정상종료)
}
코드 분석
하드웨어 PWM도 일반적인 타이머/카운터와 동일하게 동작하고 비교매치 인터럽트와 비슷한 구조로 PWM을 만들어 냅니다. 먼저 하드웨어 PWM은 두가지 종류가 있는데 Fast PWM과 Phase Correct PWM 두가지가 있습니다.
Fast PWM은...
TOP값 256으로 타이머, 카운터가 꾸준히 계산중일때 OCR0x레지스터와 비교해 동일한 지점에서 COM0A0과 COM0A1 레지스터에 따라 해당 지점에서 5V가 출력되거나 0V가 출력되 PWM의 기능을 하게되는 방식입니다.
Phase Correct Pwm은...
원리는 동일하나 카운팅 소스가 조금 특이합니다.
초기에는 업 카운팅하여 256지점까지 올라간 다음, 다운 카운팅해서 Bottom값 까지 내려값니다.
이 때 OCR0x 값과 비교해서 삼각파에서 잘린 두지점 사이에 5V가 출력되거나, 0V가 출력되 PWM 기능을 하게 되는 방식입니다.
이렇게 PWM 기능은 동일하나 방식에 따라 차이가 있을수 있습니다. 저는 연습용으로 Fast PWM을 해본것이 위 소스입니다. 그래서 설명하자면 TOP값은 이미 256로 지정되있고, 타이머 카운터는 계속 연산하는 와중에 저는 OCR0A, B값을 1씩 증가시키고 감소 시키면서 256 등분된 PWM출력을 이루게 되는것입니다.^
동작 영상
하드웨어 PWM 끝!!! 뭔가 부실한 느낌인데요.
'AVR > AVR 연습, Tutorial' 카테고리의 다른 글
AVR UART 비동기 통신 사용자 함수 문자 비교 LED ON/OFF 제어하기 - AVR 연습 (18) | 2013.10.14 |
---|---|
AVR USART(RS232) 동기형/비동기형 직렬통신 제어 레지스터 - AVR 이론 (15) | 2013.09.15 |
AVR 타이머/카운터 비교매치 인터럽트로 0.5초 마다 LED 깜박이기 - AVR 연습 (6) | 2013.04.07 |
AVR 타이머/카운터 인터럽트 응용 소프트웨어 PWM DC모터 속도 제어하기 - AVR 연습 (39) | 2013.02.28 |
AVR과 BA6208 모터드라이버로 DC모터 정회전, 역회전 제어하기 - AVR 연습 (19) | 2013.02.14 |