2.6 pwm 기능으로 서보모터 제어하기     c{mpy0206}


서보모터는 R/C카의 조향장치나 마이크로로봇의 구동장치로 쓰이는 모터로서 신호선 한 가닥으로 0도~180도의 각도를 조절할 수 있는 것이다.


[그림] 서보 모터의 외형


위 그림에서 보듯이 전원선인 Vcc/GND와 신호선 세 가닥이 인터페이스의 전부이다. 모터축의 각도는 신호선으로 인가되는 펄스폭으로 조정된다.


[그림] 서보 모터의 신호선으로 인가되는 펄스(pulse)


위 그림에 서보모터의 신호선으로 인가되는 펄스를 도시하였다. 주기 B는 3ms~20ms 의 범위를 가지며 주기가 짧을 수록 모터축의 회전 속도가 빨라진다. 펄스의 폭 A는 1.5ms 일때 중심각도인 0도를 가리키게 되고 1ms(최소값 0.7ms)일때 –90도, 2ms(최대값 2.3ms)일 때 +90도를 갖는다. 즉, 이 펄스폭을 조절하여 –90도에서 90도 사이의 원하는 각도를 가지도록 제어할 수 있다.

이것을 pwm기능으로 구현하려면 다음과 같이 하면 된다. 일단 주기는 50 Hz~330Hz 정도의 범위를 가지며 주파수가 높을 수록 회전속도는 빨라진다. 만약 50Hz를 사용한다면 펄스폭이 20ms이므로 1.5ms를 만드려면 듀티를 77(정확한 값은 76.8)로 설정하면 되며 40~115의 값을 주면 정해진 각도로 회전하게 된다.



[표] freq=50일경우 duty에 따른 회전각

duty

회전각

40

-90도

77

0도

115

+90도




만약 gpio12에 서보모터의 신호선이 연결되어 있다면 다음과 같이 PWM객체인 servo를 생성하여 제어할 수 있다.


from machine import Pin, PWM
servo=PWM(Pin(12), freq=50)

만약 0도로 맞출려면 다음과 같이 하면 된다.


servo.duty(77)

단 주파수가 바뀌면 각도를 제어하기 위한 duty값도 다시 계산하여 사용해야 한다.

'하드웨어 > ESP8266' 카테고리의 다른 글

WeMos d1 mini 보드  (0) 2016.10.13
MicroPython으로 아날로그입력 받기  (0) 2016.10.12
NodeMCU를 이용한 LED의 fading 예제  (0) 2016.10.11
NodeMCU보드에서 PWM파형 생성하기  (0) 2016.10.05
ESP8266 외부인터럽트  (0) 2016.10.04
Posted by 살레시오
,



 ESP8266의 0,2,4,5,12,13,14,15 번 핀 모두 PWM 파형을 만들 수 있다. 단, 모두 같은 주파수를 가지며 주파수의 범위는 1~1000Hz 이다. 즉, 각각의 PWM파형이 서로 다른 주파수를 가질 수 없다.


 PWM파형을 만들기 위해서는 먼저 Pin객체를 생성해야 한다.


import machine
p5 = machine.Pin(5)

이것을 이용해서 PWM객체를 만들 수 있다.


pwm5=machine.PWM(p5)

이제 이 객체의 freq()메서드와 duty()메서드를 이용하여 주파수와 듀티비를 설정할 수 있다. 듀티비는 0~1023의 범위를 가진다.


pwm5.freq(500) #500Hz
pwm5.duty(512)

위와 같이 하면 주파수는 500Hz에 듀티비는 50%이다. 만약 freq()함수와 duty()함수를 인수 없이 호출하면 현재 설정값을 반환한다.


메서드

기능

비고

PWM(PinObj, freq=500, duty=0)

PWM클래스의 생성.


pwm.freq(n)

pwm.freq()

주파수를 n으로 설정

주파수값 반환

n은 [1,1000]범위의 정수

pwm.duty(m)

pwm.duty()

듀티비를 m으로 설정

현재 듀티비를 반환

m은 [0,1023]범위의 정수

pwm.deinit()

PWM 중단



좀 더 간략하게 작성된 프로그램은 다음과 같다.


from machine import Pin, PWM
pwm5 = PWM(Pin(5), freq=500, duty=512) #PWM객체 생성, 주파수는 500Hz

서로 다른 핀에서 발생하는 PWM파형일지라도 모두 같은 주파수로 동작한다는 사실에 유의해야 한다.


Posted by 살레시오
,

 PWM이라는 것은 구형파의 듀티비(duty ratio)를 조절하는 것을 의미한다. 듀티비란 구형파의 주기와 ‘1’이 되는 구간의 시간비율을 의미한다. 다음 [그림 1]에서 T는 주기, t1은 한주기에서 ‘1’이 되는 시간을 표기하는데 듀티비는 t1/T 로 정의된다.


[그림 1] PWM과 듀티비


ATmega8(A)의 T/C2는 두가지 PWM발생 모드를 가지고 있는데 하나는 고속PWM모드이고 다른 하나는 위상교정PWM 모드이다. 이 두 가지에 대해서 각각 알아보겠다.

고속 PWM 모드

 고속 PWM모드는 TCNT2레지스터가 노멀모드에서와 같은 동작을 한다. 즉, 0x00에서 0xFF까지 1씩 증가하다가 그 다음 사이클에서 다시 0x00으로 클리어된 후 다시 1씩 증가한다. 이 때 ① TOV2 플래그가 세트되며 ②비교매치시 OC2 플래그도 세트된다. OC2 핀은 COM21:0 비트들의 설정에 따라서 동작이 결정되는데 ①의 경우에 세트되고 ②의 경우에 리셋 되거나 혹은 반대의 동작을 취할 수 있다.([표 1] 참조) 데이터쉬트에서 [그림 1]에 고속 PWM모드의 타이밍 다이어그램을 발췌하였다.


[그림 2] 고속 PWM 모드에서의 타이밍 다이어그램


[표 1] 고속 PWM 모드일 때 비교 출력핀(OC2핀) 동작

COM21

COM20

OC2핀의 동작

0

0

포트핀(PB3)으로 동작

0

1

-

1

0

TCNT2=0x00일때 OC2핀 셋,

비교매치시 OC2핀 리셋

1

1

TCNT2=0x00일때 OC2핀 리셋,

비교매치시 OC2핀 셋


OC2핀으로 발생하는 PWM파형의 주기는 다음 식과 같이 계산할 수 있다.

여기서 N 은 분주수를 나타내며 1, 8, 32, 64, 128, 256, 1024 중 하나이고, fTC2는 T/C2에 인가되는 클럭 주파수이다.


 한 가지 유용한 사실은 오버플로우 인터럽트와 비교매치 인터럽트를 이용하면 임의의 포트핀에 PWM파형을 발생시킬 수 있다는 점이다. 즉 해당하는 ISR() 함수 내부에서 원하는 포트핀을 셋시키거나 리셋시켜서 OC2핀 뿐만 아니라 임의의 포트핀에 PWM파형을 발생시킬 수 있다.


위상 교정 PWM 모드

 위상교정PWM 모드가 고속PWM 모드와 다른 점은 TCNT2레지스터가 0에서 0xFF값에 도달한 후(업-카운팅) 0x00으로 클리어되는 것이 아니고 1씩 감소하여 다시 0x00이 된다(다운-카운팅)는 점이다. 이때 비교매치는 두 가지 경우인데 업 카운팅의 경우와 다운 카운팅의 경우이다. PWM파형은 업-카운팅에서 비교매치가 일어난 경우 OC2핀을 ‘1’로, 다운-카운팅에서 비교매치가 일어난 경우 OC2핀을 ‘0’으로 설정하여 PWM파형을 발생시킨다. (혹은 그 반대의 모양으로 발생시킬 수 있다.)


[그림 3] 위상 교정 PWM 모드의 타이밍 다이어그램


OC2핀으로 발생하는 PWM파형의 주파수는 고속 PWM의 경우보다 두 배 줄어들며 다음 식과 같이 계산할 수 있다.

여기서 N은 분주수를 나타내며 1, 8, 32, 64, 128, 256, 1024 중 하나이다.


[표 2] 위상 교정 PWM 모드일 때 비교 출력핀(OC2핀) 동작

COM21

COM20

OC2핀의 동작

0

0

포트핀(PB3)으로 동작

0

1

reserved

1

0

업카운팅에서 비교매치시 OC2핀 리셋

다운카운팅에서 비교매치시 OC2핀 셋

1

1

업카운팅에서 비교매치시 OC2핀 셋

다운카운팅에서 비교매치시 OC2핀 리셋


고속 PWM모드에서와 마찬가지로 두 개의 인터럽트를 이용하면 위상교정 PWM파형도 임의의 포트핀으로 내보낼 수 있다. 단, 이번에는 앞의 경우와 달리 비교매치 인터럽트가 업-카운팅에서 발생했는지 다운-카운팅에서 발생했는지를 판별해야 할 것이다. 이것을 위해서 [그림 3]을 살펴보면 오버플로우 인터럽트는 다운-카운팅에서 0x00에 도달한 경우에 발생하는 것을 알 수 있다. 따라서, 오버플로우 인터럽트가 발생한 이후 첫 번째 비교매치 인터럽트는 업-카운팅에서, 두 번째 비교매치 인터럽트는 다운-카운팅에서 발생한 것으로 판정해야 하므로 조건 검사를 하는 코드가 앞의 경우에 비해서 더 추가가 되어야 할 것이다.




Posted by 살레시오
,

Due보드의 PWM 개요

 아두이노 두에 (arduino due) 의 PWM 핀은 다음 그림의 핀맵에 나온 바와 같이 같이 D2부터 D13까지 12개를 사용할 수 있다. 따라서 우노보다 더 많은 핀을 PWM출력으로 사용할 수 있다.


[그림 1] 아두이노 두에의 핀맵


단순히 핀 수만 많은 것이 아니라 우노와 달리 최대 해상도를 12비트까지 지정해 줄 수 있다. 따라서 우노는 [0, 255]범위의 출력(8비트)을 사용했었는데 두에의 숫자 범위는  [0, 4095] 이다.


 PWM의 해상도를 조절하려면 다음과 같은 함수를 사용해야 한다.


analogWriteResolution(nBits);


입력인수는 몇 비트를 사용할 것인가를 지정해주면 되며 기본값은 8비트이다. 만약 12비트로 해상도를 높이고 싶다면 다음과 같이 하면 된다.


analogWriteResolution(12);


그런 다음 analogWrite()함수를 사용하면 된다. 예를 들어서


analogWrite(6, 4095); // 6번핀에 4095값을 내보낸다.


 만약 어떤 아날로그 센서의 입력이 [0, 1023] 범위의 값인데 이것을 [0. 4095]범위의 값으로 변환하고 싶다면 map()이라는 함수를 사용하면 된다.


map(sVal, sMin, sMax, cMin, cMax);


이 함수는 sVal 값을 원래의 범위인 [sMin, sMax] 에서 변환하고자 하는 범위 [cMin, cMax]에 해당하는 값으로 바꾸는 함수이다. 만약 (0, 1023)범위의 센서값을 [0,4096]값으로 바꾸고 싶다면 다음과 같이 하면 된다.


map(sVal, 0, 1023, 0, 4095);


이 함수들을 사용해서 PWM을 12비트 해상도로 변경하고 [0,1023]범위의 센서값을 PWM 으로 매핑하는 예는 다음과 같다.


analogWriteResolution(12);

analogWrite(12, map(sensorVal, 0, 1023, 0, 4095));


여기서 sensorVal 변수에는 10비트 아날로그 센서값이 저장되었다고 가정한다.

PWM 주파수 변경

 아두이노 Due의 PWM 주파수는 1KHz 로 정해져 있다. 그런데 응용 분야에 따라서 이 주파수를 변경해 주어야 하는 경우가 있다. 하지만 아두이노에서 PWM의 주파수를 바꿔주는 공식 API 는 없어서 무척이나 불편하다. 그래도 AVR 계열의 아두이노에서는 이런 불편을 해소하기 위해서 사용자가 작성한 라이브러리 (PWM.h)라도 있는 것 같은데 Due의 경우에는 아직까지 그런 라이브러리는 없는 것 같다.


 구글링을 해본 결과 아주 방법이 없는 것은 아니었다. 일단 다음의 헤더 파일을 연다.(윈도의 경우)


Program Files > Arduino > hardware > arduino > sam > variants > arduino_due_x > variant.h


64비트 윈도라면 Program Files(x86) 폴더 밑을 뒤져야 한다. 이 파일을 열면 다음과 같이 정의된 부분이 나온다.


/*
* PWM
*/
#define PWM_INTERFACE PWM
#define PWM_INTERFACE_ID ID_PWM
#define PWM_FREQUENCY 1000
#define PWM_MAX_DUTY_CYCLE 255
#define PWM_MIN_DUTY_CYCLE 0
#define PWM_RESOLUTION 8


이 상수값들을 변경하면 PWM의 주파수나 기본 분해능을 설정할 수 있다고 한다. 예를 들어서 주파수를 10KHz로 변경하고 싶다면 PWM_FREQUENCY 를 10000 으로 바꾸면 된다.


[그림 3] dc모터 실험 (2V 이상 인가되어야 회전이 시작됨)


조그만 장난감 모터는 1KHz 주파수로도 충분하다. 필자가 가지고 있는 모터는 조금 용량이 큰데 (12V/12.9W) 이 정도만 되도 주파수를 조금 키워야 한다. 몇 번 실험해보니 12KHz 정도가 적당한 것 같다.



Posted by 살레시오
,

 아두이노 우노의 경우 PWM주파수가 980Hz (5,6번 핀)와 490Hz(3, 9, 10, 11번 핀)로 고정되어 있다. 보통의 경우(LED의 밝기를 제어한다든가 소형 모터를 돌릴 때)에는 이 주파수를 사용하는 것에 별 문제는 없다.

[표 1] 아두이노 우노의 pwm 주파수

핀 번호

PWM 주파수

5, 6

980Hz

3, 9, 10,11

490Hz

하지만 중소형 이상의 DC모터를 구동하는 경우에는 보통 10KHz 이상의 PWM 주파수를 사용하므로 아두이노에서 제공하는 기본 주파수로는 DC모터를 구동하기에 적절하지 않다. 이 주파수가 중요한 이유는 만약 PWM주파수가 너무 낮다면 모터의 속도를 정밀하게 제어할 수 없으며 모터에서 소음이 발생하는 경우도 있기 때문이다.

 

 이런 경우에 PWM 주파수를 변경해야 하는데 아두이노의 표준 API에는 아쉽게도 PWM의 주파수를 조절할 수 있는 함수를 제공하지 않지만 사용자가 만들어 놓은 라이브러리가 있다. 아래의 페이지에 자세하게 설명되어 있다.

다운로드 받은 파일의 압축을 풀면 세 개의 폴더가 있는데 이 중 PWM 폴더를 아래의 폴더에 복사하여 붙여넣는다.

<아두이노 IDE 설치 폴더>\Arduino\libraries

윈도우즈 시스템에서는 보통 아래의 폴더이다.

C:\Program Files\Arduino\libraries

그러면 아두이노 IDE에 다음 [그림 6.6.1]과 같은 항목이 생성된다. 이 항목을 선택하면 텍스트 에디터에 다음과 같이 인클루드문이 추가된다.

#include <PWM.h>

이것으로 이 라이브러리를 사용할 준비가 된 것이다.


[그림 1] pwm.h를 메뉴에서 인클루드하는 방법

이 라이브러리에서는 다음과 같이 다섯 개의 전역 함수를 제공한다.


[표 1] pwm.h에서 제공하는 전역 함수들

함수명

기능

InitTimers()

Initializes all timers. Needs to be called before changing the timers frequency or setting the duty on a pin

InitTimersSafe()

Same as InitTimers() except timer 0 is not initialized in order to preserve time keeping functions

pwmWrite(uint8_t pin, uint8_t val)

Same as 'analogWrite()', but it only works with initialized timers. Continue to use analogWrite() on uninitialized timers

SetPinFrequency(int8_t pin, int32_t frequency)

Sets the pin's frequency (in Hz) and returns a bool for success. 주파수 범위는 31Hz~2MHz 사이이다.

Sets the pin's frequency (in Hz) and returns a bool for success. 주파수 범위는 31Hz~2MHz 사이이다.

SetPinFrequencySafe(int8_t pin, int32_t frequency)

Same as SetPinFrequency except it does not affect timer 0. 주파수 범위는 31Hz~2MHz 사이이다.


여기서 보면 InitTimers() 와 SetPinFrequency() 함수는 함께 사용되는데 이 함수들은 내부적으로 timer0번을 초기화시킨다. 따라서 시간 관련 함수인 millis(), micros(), delay(), delayMicroseconds() 함수들이 정상 동작하지 않는다. 그리고 3, 5, 9, 10번 핀을 PWM 핀으로 사용할 수 있다.

 반면 InitTimersSafe()와 SetPinFrequency() 함수는 역시 쌍으로 사용되는데 timer0를 초기화시키지 않으므로 시간 관련 함수들이 정상적으로 동작한다. 그리고 3,9,10번 핀을 PWM으로 사용할 수 있다. 두 경우 모두 PWM값을 쓰기 위해서는 analogWrite()함수 대신 pwmWrite()함수를 사용한다.


[표 2] pwm.h 의 두 함수 그룹 비교

함수 그룹

특징

장단점

적용 핀

InitTimers()

SetPinFrequency()

timer0

초기화

millis(), micros(), delay(), delayMicroseconds() 함수들이 정상 동작하지 않는다.

3,

5,

9,

10

InitTimersSafe()

SetPinFrequencySafe()

timer0

초기화

안함

millis(), micros(), delay(), delayMicroseconds() 함수들이 정상 동작한다.

3,

9,

10


시간 관련 함수들이 정상적으로 동작 하지 않는 것은 큰 문제이므로 InitTimersSafe() 과 SetPinFrequencySafe() 함수를 사용하는 것이 좋을 것이다.



Posted by 살레시오
,

 DC모터는 영구자석의 자기장과 그 자기장 속에 놓여 있는 도체에 흐르는 전류에 의해 발생한 전자력 간의 반발력으로 회전하는 구동기이며 DC전원을 사용한다. 기동 토크가 크며 인가되는 전압에 대해 회전 특성이 선형적으로 비례하며 가격이 저렴한 장점이 있는 반면에 구조상 브러시(brush)와 정류자(commutator)에 의한 기계적 점점이 있다는 단점이 있다. 이 접점으로 인해 회전 시 전기적인 불꽃이나 잡음이 발생하며 이는 uC로 제어할 때는 고려하여 제거하여야 한다. DC모터는 인가 전압의 극성을 바꾸어 인가하면 방향을 바꾸어 회전한다.


[그림 1] 다양한 DC모터들


 만약 아두이노의 전원이 PC의 USB에서만 공급된다면 DC모터를 직접 구동하는 것은 무리가 있다. DC모터는 보통 큰 전류가 필요하기 때문에 최대 공급 전류가 최대 500mA 정도인(노트북인 경우 공급 전류량은 더 작아진다.) USB로 직접 구동할 수는 없다. 그러나 구동 전류가 작은 초소형 모터의 경우 USB전원으로도 충분해 제어할 수 있으며 이 경우 높은 회전 속도나 큰 토크(회전력)을 기대할 수는 없다. 중형 DC모터를 아두이노로 제어하려면 전용 모터 제어 쉴드를 사용하는 것이 유리하다.


소형 DC모터의 제어

 실험을 위해서 [그림 2]와 같은 3V로 구동되는 소형 DC모터를 선택하였으며 드라이버 IC로는 소형 DC모터의 구동에 많이 쓰이는 BA6208을 사용하였다. 소전류로도 구동이 가능한 초소형 모터이므로 USB전원만으로도 제어하는데 충분하다.

[그림 2] 실험에 사용된 초소형 DC모터

BA6208은 소형 DC모터 구동 IC이다. SIP패키지의 BA6208 외형은 [그림 3]과 같다. 그림에서 보면 홈이 파인 쪽이 1번 핀이다. 논리부와 출력부로 구성되는데 논리부는 모터의 회전 방향을 제어하며, 출력부는 논리 제어에 따라 100mA까지 출력 전류를 공급할 수 있다. 공급 전압의 최대 값은 18V이다


[그림 3] BA6208의 외형과 핀 기능


다음 표는 BA6208의 논리 값에 따른 동작을 정리한 것이다.

[표 1] BA6208의 입력 신호에 따른 모터 동작 표


아두이노 우노의 5번과 6번 핀을 BA6208로 연결하여 모터를 제어하도록 하겠다. 결선도는 다음 그림과 같다. VCC는 아두이노 우노의 3.3V핀과 연결한다.

[그림 4] 아두이노와 BA6208 그리고 모터의 결선도

 한 가지 유의할 것은 DC모터가 회전하면서 발생하는 전기적인 잡음 때문에 전원이 불안정해질 가능성이 있으며 이것은 전체 시스템이 불안정하게 만드는 요인이 되기도 한다. 이를 억제하기 위해서 BA6208단의 VCC와 GND 사이에 커패시터(10uF)을 연결하여 전원을 안정시키는 것이 좋으나 아두이노 우노 보드를 사용하는 경우 전원을 안정화 시키는 회로가 포함되어 있으므로 별도로 커패시터를 달아 줄 필요는 없다.

 다음 예는 1초 간격으로 모터의 회전 속도를 바꾸는 예제이다.


#define A_IN 5
#define B_IN 6
void setup() {
   pinMode(A_IN, OUTPUT);
   pinMode(B_IN, OUTPUT);
}
void loop() {
   digitalWrite(A_IN, HIGH); // 정회전
   digitalWrite(B_IN, LOW);
   delay(1000);
   digitalWrite(A_IN, LOW); // 역회전
   digitalWrite(B_IN, HIGH);
   delay(1000);
}


PWM을 이용한 속도제어

 이제 analogWrite() 함수를 이용하여 속도를 제어해보도록 하겠다. 다음 예제는 시리얼 통신으로 PC에서 -255~255 사이의 정수를 입력하면 그 값을 analogWrite()함수로 내보내어 모터의 속도를 조절하는 예제이다.


#define A_IN 5
#define B_IN 6
void setup() {
   Serial.begin(9600);
   Serial.setTimeout(100);
}
void loop() {
   if (Serial.available()) { // 만약 시리얼 버퍼에 데이터가 있다면
   // 정수로 해석하여 읽어들인다.
       short motorSpeed = Serial.parseInt();
       if (motorSpeed >= 0){
           analogWrite(A_IN, motorSpeed);
           analogWrite(B_IN, 0);
       } else {
           analogWrite(A_IN, 0);
           analogWrite(B_IN, -motorSpeed);
       }
   }
}


이전에 언급한 바와 같이 아두이노의 PWM 주파수는 490Hz, 980Hz인데 소형 모터를 제어하기에는 무리가 없다.



Posted by 살레시오
,

 고휘도 LED는 이전 실험에서 사용된 일반 LED보다 밝기가 대폭 개선된 LED이다.


[그림 1] 고휘도 LED

일반적인 LED와 외형은 큰 차이가 없지만 밝기가 획기적으로 개선된 것이고 전력 효율이 높아서 가정용 조명이나 신호등, 차량의 전조등 등으로 널리 사용된다.


 구동 회로는 일반 LED와 다르지 않게 저항을 직결하여 전원이 연결하면 되는데 문제는 저항값으로 어떤 값을 사용하는가이다. 데이터쉬트를 살펴보면 최대 허용 전류는 20mA 이고 (전류가 클수록 더 밝다.) 이 전류가 흐를 때 다이오드 양단의 전압 강하는 3.0~3.6V 이다. 따라서 만약 5V 전원을 사용하고 최대 전류를 흘릴 때 전압강하가 3.0V라고 가정하면 저항값은 오옴의 법칙에 의해서 다음과 같이 간단히 계산할 수 있다.



이 저항값이 허용되는 가장 최소 저항이므로 이것보다 큰 용량의 저항을 선택하면 구동하는데 무리가 없을 것이다. 실습에는 100 Ω의 저항을 선택했다.


첫 번째 실험

 첫 번째 예제로 서서히 밝아졌다가 다시 서서히 어두워지는 동작을 하는 프로그램을 작성해 보자.


#define HLED 5
void setup() {
   pinMode(HLED,OUTPUT);
}
void loop() {
   for (int k=0; k<256; k++) {
       analogWrite(HLED,k);
       delay(15);
   }
   for (int k=255; k>=0; k--) {
       analogWrite(HLED, k);
       delay(15);
   }
}


위 프로그램에서 delay(15) 함수를 이용하여 서서히 밝아지거나 서서히 어두워지는 효과를 내었다.


두 번째 실험

 두 번째로 스위치를 누르면 고휘도 LED가 서서히 켜지는 프로그램을 작성해 보자. 완전히 꺼진 상태에서 최고 밝기로 켜지는 시간은 4초로 설정한다. 버튼을 떼면 그 즉시로 고휘도 LED가 꺼져야 한다.

#define HLED 6
#define SW 3
void setup() {
   pinMode(HLED,OUTPUT);
   pinMode(SW,INPUT_PULLUP);
}
int iL=0;
void loop() {
   if (digitalRead(SW)==LOW) {
       analogWrite(HLED, iL++);
       if (iL>255) iL = 255;//❶
       delay(15);
   } else {
       digitalWrite(HLED,LOW);
       iL = 0;
   }
}

전술한 바와 같이 analogWrite()함수의 두 번째 인수의 범위는 0~255이다. 따라서 ❶에서 이 범위를 넘으면 (즉 256이 되면) 255값을 계속 가지도록 if 문으로 처리했음을 유의해서 보자.


세 번째 실험

 이전 실험에서는 스위치를 떼면 그 즉시 꺼졌지만 이번 예제에서는 서서히 꺼지는 부분을 추가해 보자. 꺼지는 속도는 완전히 켜졌을 때에서 완전히 꺼질 때까지의 시간이 4초 정도 되게 설정한다.


#define HLED 6
#define SW 3
void setup() {
   pinMode(HLED,OUTPUT);
   pinMode(SW,INPUT_PULLUP);
}
int iL=0;
void loop() {
   if (digitalRead(SW)==LOW) {
       analogWrite(HLED, iL++);
       if (iL>255) iL = 255; //❶
       delay(15);
   } else {
       analogWrite(HLED, iL--); //❷
       if (iL<0) iL = 0;
       delay(15);
   }
}


이 프로그램의 동작은 스위치를 누르고 있으면 서서히 켜지고 떼면 다시 서서히 꺼지게 된다. analogWrite()함수의 두 번째 인수의 범위는 0~255이다. 따라서 ❶과 ❷에서 이 범위를 넘으면 그 한계값을 계속 가지도록 if 문으로 처리했음을 유의해서 보자.



Posted by 살레시오
,

 아두이노의 디지털핀은 오직 HIGH(5V) 아니면 LOW(0V) 두 가지 신호 외에는 출력할 수 없으며 전압의 관점에서 보면 5V와 0V만 가질 수 있다. 하지만 PWM (pulse width modulation, 펄스 폭 변조) 기능을 이용하면 마치 아날로그 전압처럼 0V와 5V 사이의 전압으로 (예를 들면 2V, 3.5V 등) 출력을 낼 수 있다. 따라서 LED의 밝기를 제어한다든가 모터의 회전 속도를 제어하는데 사용할 수 있다.

 PWM은 진정한 의미의 아날로그 출력은 아니고 흉내를 내는 것인데 그 원리는 다음 그림과 같다. (출처 : arduino.cc)


[그림 1] PWM의 원리


이 그림에서 보면 주기적인 구형파를 발생하고 이 구형파의 폭을 조절하여 그 듀티비 (HIGH 구간 대비 LOW 구간의 비율)로 아날로그 전압값을 가지도록 한다. 이 구형파의 주기를 매우 빠르게 (아두이노 우노의 경우 490Hz 혹은 980Hz이다.) 하면 상대적으로 반응 속도가 느린 기계 장치(모터 등)는 이것을 아날로그 전압으로 인식하게 된다.


 예를 들어서 그림 1(b)의 경우 주기의 1/4동안만 on 이 되므로 평균 출력 전압도 5V * ¼ 인 1.25V 정도가 된다. 만약 LED가 연결되었다면 LED는 정확하게 on구간에서만 켜지고 off구간에서는 꺼진다. 하지만 눈으로 보기에는 이것이 인식하지 못 할만큼 고속으로 동작하므로 밝기가 다르게 보이는 것이다.


 아두이노의 모든 핀이 PWM 출력을 낼 수 있는 것은 아니고 아두이노 우노의 경우 3, 5, 6, 9, 10, 11번 핀이 PWM출력을 낼 수 있으며 이것은 정품 보드의 경우 다음 그림과 같이 ~로 표시되어 있다.


[그림 2] 아두이노 우노의 PWM 핀들

PWM의 동작 주파수는 다음과 같다.

  • 3, 9, 10, 11번 핀 - 490Hz

  • 5, 6번 핀 – 980Hz (5,6번 핀이 좀 더 고속으로 동작)


PWM기능을 사용하기 위해서는 다음과 같은 analogWrite()함수를 이용한다.


analogWrite(pin, value)

  • pin : 3, 5, 6, 9, 10, 11 중 하나 (아두이노 우노의 경우)

  • value : 0에서 255 사이의 정수.


그리고 PWM 기능을 사용하기 위해서는 해당 핀을 출력으로 설정하여야 한다.



Posted by 살레시오
,