본문 바로가기
전자공학/아두이노

아두이노 PWM 실습2: analogWrite() 함수 수정

by 블랜드 2022. 2. 10.
반응형

 이전 글을 보고 오면 더 이해하기 수월할 것이다.

 

아두이노 PWM 실습1: analogWrite() 시뮬레이션

Fast PWM(5, 6번 핀) vs Phase Correct PWM(3, 9, 10, 11번 핀) ※ x = 비교 값 = Fast PWM에서의 Ton 클럭수 (범위: 0~255) 파형 모드 디지털 핀 PWM 주기 PWM 주파수 Duty Cycle Fast PWM 5, 6 256 클럭 976.56..

recall.tistory.com

analogWrite(255)

analogWrite(255) 시뮬레이션 결과: 5번 핀, 9번 핀

 5번 핀: Vavg = 255 / 256 x 5V= 4.98V

 9번 핀: Vavg = 255 / 255 x 5V= 5.00V

  analogWrite(255)일 때 digitalWrite(HIGH)로 설정되어 Fast PWM에 해당하는 5번 핀이 위 평균전압 계산식과 같이 4.98V로 안 나오고 5V로 출력되는 문제를 아래 코드를 통해 해결하였다. 원래 analogWrite() 함수 정의에서 조건 하나만 바꿔줌으로써 해결한 것이다. analogWrite() 함수와 이름이 겹치는 것을 방지하기 위해 analogWriteNew()라는 이름으로 새롭게 정의하였다.


analogWriteNew() 함수 소스코드

#include "wiring_private.h"
#include "pins_arduino.h"

void setup()
{
  Serial.begin(9600);
  analogWriteNew(9, 255);
  analogWriteNew(5, 255);
}

void loop()
{
  Serial.print(OCR1A); // 9번 핀: 16비트 타이머 비교값(PC PWM)
  Serial.print("\t");
  Serial.print(OCR1AH); // 9번 핀: 8비트 타이머 상위 비교값(PC PWM)
  Serial.print("\t"); 
  Serial.print(OCR1AL); // 9번 핀: 8비트 타이머 하위 비교값(PC PWM)
  Serial.print("\t");
  Serial.println(OCR0B); // 5번 핀: 8비트 타이머(Fast PWM)
}


void analogWriteNew(uint8_t pin, int val)
{
	// We need to make sure the PWM output is enabled for those pins
	// that support it, as we turn it off when digitally reading or
	// writing with them.  Also, make sure the pin is in output mode
	// for consistenty with Wiring, which doesn't require a pinMode
	// call for the analog output pins.
	pinMode(pin, OUTPUT);
	if (val == 0)
	{
		digitalWrite(pin, LOW);
	}
	else if (val == 256)
	{
		digitalWrite(pin, HIGH);
	}
	else
	{
		switch(digitalPinToTimer(pin))
		{
			case TIMER0A:
				// connect pwm to pin on timer 0, channel A
				sbi(TCCR0A, COM0A1);
				OCR0A = val; // set pwm duty
				break;

			case TIMER0B:
				// connect pwm to pin on timer 0, channel B
				sbi(TCCR0A, COM0B1);
				OCR0B = val; // set pwm duty
				break;

			case TIMER1A:
				// connect pwm to pin on timer 1, channel A
				sbi(TCCR1A, COM1A1);
				OCR1A = val; // set pwm duty
				break;

			case TIMER1B:
				// connect pwm to pin on timer 1, channel B
				sbi(TCCR1A, COM1B1);
				OCR1B = val; // set pwm duty
				break;

			case TIMER2A:
				// connect pwm to pin on timer 2, channel A
				sbi(TCCR2A, COM2A1);
				OCR2A = val; // set pwm duty
				break;

			case TIMER2B:
				// connect pwm to pin on timer 2, channel B
				sbi(TCCR2A, COM2B1);
				OCR2B = val; // set pwm duty
				break;

			case NOT_ON_TIMER:
			default:
				if (val < 128) {
					digitalWrite(pin, LOW);
				} else {
					digitalWrite(pin, HIGH);
				}
		}
	}
}

analogWriteNew() 함수 코드 분석

#include "wiring_private.h"
#include "pins_arduino.h"

 이 헤더파일들은 원래의 analogWrite() 정의 안에 있는 함수인 sbi()를 사용하기 위해 선언되었다. 이게 헤더파일들이 선언이 안 되어 있으면 새로 정의한 analogWriteNew() 함수는 사용할 수 없다. 무조건 코드 맨 위에 두 헤더파일을 선언해 줘야 한다.

 

	if (val == 0)
	{
		digitalWrite(pin, LOW);
	}
	else if (val == 256)
	{
		digitalWrite(pin, HIGH);
	}

 analogWriteNew(pin, val)에 들어가는 val 값이 0이면 LOW를 무조건 출력해준다. 이건 analogWrite()일 때와 바뀐 게 없다. 중요한 것은 val 값이 256일 때 HIGH 값을 주도록 코드를 바꿨다는 것이다. analogWriteNew() 함수는 analogWrite() 함수 코드 중에서 이 부분만 바꾼 것이다. 이렇게 조건을 수정해주면 5번 핀에 쓰이는 Fast PWM에서 val 값이 255일 때에 해당하는 Duty Cycle = 255 /256로 제대로 된 평균전압을 출력할 수가 있다.


analogWriteNew(255)

analogWriteNew(255) 시뮬레이션 결과: 5번 핀, 9번 핀

 5번 핀: Vavg = 255 / 256 x 5V= 4.98V

 9번 핀: Vavg = 255 / 255 x 5V= 5.00V

 위 시뮬레이션 결과는 analogWrtieNew(255)일 때의 출력 평균전압 값을 보여준다. 원래 평균전압 계산식과 똑같이 나온 것을 알 수 있다. 이로써 analogWrite()의 불완전한 부분을 수정함으로써, 255까지밖에 출력을 못 하던 Fast PWM을 256까지도 아날로그 출력을 낼 수 있도록 만들었다. 

반응형

댓글