[아두이노] [강좌] 14. analogRead()/analogWrite() 실습 - 조도 센서 + LED
analogRead() 함수와 analogWrite() 함수에 대해 모두 배웠으니, 이제 두 함수를 동시에 이용하는 예제를 실습해보자. 제목에 나와 있듯이, 조도 센서와 LED를 사용하는 예제.
조도 센서는 빛의 세기를 읽는 센서이고, LED는 빛을 내는 센서(? 뭐지? 센서는 아닌데 뭐라고 해야 할 지 모르겠는 이 느낌적인 느낌은?).
그래서 조도 센서의 값을 읽어서 주변 밝기에 따라 LED의 밝기를 조절하는 예제를 만들어보자.
센서(하나는 LED지만) 두 개로 실습하는 예제는 처음이라 두근두근.
조도 센서와 LED는 다음 그림과 같이 아두이노 보드와 연결하자. 조도 센서는 TEMT6000을 사용.
아.. 다른 사람이 선 연결 그려놓은거 보면 되게 깔끔하던데...
암튼, "강좌 10. analogRead() 함수"에서 설명했던 조도 센서와 "강좌 13. LED 밝기 조절하기"에서 설명한 LED 연결이 합해진 것 뿐, 새로 나온 건 없으므로 설명은 생략하고 지나간다.
그리고는 예제 소스를 열어보자. 스케치 툴의 "파일→예제→03.Analog→AnalogInOutSerial" 열기.
AnalogInOutSerial.ino |
const int analogInPin = A0; const int analogOutPin = 9; int sensorValue = 0; int outputValue = 0; void setup() { Serial.begin(9600); } void loop() { sensorValue = analogRead(analogInPin); outputValue = map(sensorValue, 0, 1023, 0, 255); analogWrite(analogOutPin, outputValue); Serial.print("sensor = " ); Serial.print(sensorValue); Serial.print("\t output = "); Serial.println(outputValue); delay(100); } |
마지막에 delay() 값을 100밀리초로 수정했다. 아두이노 보드도 힘드니까.
소스 중 대부분은 이미 설명했던 내용들이고, map()이라는 함수가 새로 나왔다. map() 함수는 일정 범위의 값을 비율에 맞춰 지정한 범위의 값으로 바꿔주는 함수이다. 음?
예를 들어 1~100 사이의 값들 중 50이라는 값을 1~1000 사이의 값들 중 같은 위치의 값으로 바꾸고 싶으면 어떻게 해야 할까? 즉, 1은 1로 그대로 두고, 100을 1000으로 늘렸을 때, 50은 얼마만큼 늘어날까? 수학, 수학!
보자.. 50:100=x:1000 이니까, 100x=1000*50 이고, 그럼 x=1000*50/100 이니까, 계산하면 '500'이군! 이정도 쯤이야. ㅋㅋㅋㅋㅋㅋ
자, 그럼 200~500 사이의 값들 중 300이라는 값을 500~1000 사이의 값들 중 같은 위치의 값으로 바꾸려면?? 음... 음?? 300:500 이긴 한데, 200부터 시작하니까........ 음?????????
(수학을 잘 하는 사람은 금방 계산 되겠지만, 난 안돼...)
이 계산을 해주는 함수가 바로 map() 함수이다. map() 함수의 매개 변수와 반환 값은 다음과 같다.
long map(value, fromLow, fromHigh, toLow, toHigh)
매개 변수 value : 같은 위치로 변환하고 싶은 값 fromLow : value 값이 위치하는 범위의 가장 낮은 값 fromHigh : value 값이 위치하는 범위의 가장 높은 값 toLow : 바꾸고 싶은 범위의 가장 낮은 값 toHgih : 바꾸고 싶은 범위의 가장 높은 값 |
반환 값 long 타입의 정수 : 바꾸고 싶은 범위에서 value 값과 동일한 위치의 값 |
그럼 위에서 예로 든 값을 구해볼까? 200~500 사이의 값들 중 300이라는 값을 500~1000 사이의 값들 중 같은 위치의 값으로 바꾸려면?
long value = map(300, 200, 500, 500, 1000); |
이라고 하면 되겠지. 아, 편리한 함수구먼.
다시 예제로 돌아가자. 소스를 잠깐 설명하자면,
const int analogInPin = A0; const int analogOutPin = 9; |
아날로그 입력 기능으로 사용하기 위한 핀 번호를 'analogInPin'이라는 변수에 저장하고(A0), 아날로그 출력(PWM) 기능으로 사용하기 위한 핀 번호를 'analogOutPin'이라는 변수에 저장하고 있다(9). 여기서 'const'가 앞에 붙은 건, 이 변수들의 값이 프로그램 도중에 변하지 않는 '상수' 값이라는 것을 의미. 핀 번호가 프로그램이 실행되는 중에 바뀔 일은 없으니 붙여준 듯.
음.. 'const'에 대한 설명은 또 줄줄이 사탕이 될 것 같으니 패스.
int sensorValue = 0; int outputValue = 0; |
그리고 또다른 변수 'sensorValue'와 'outputValue'를 선언한 후 0으로 초기화해주고.
void setup() { Serial.begin(9600); } |
setup() 함수에서는 시리얼 모니터 출력을 위해 Serial.begin() 함수를 호출한다. 보레이트는 9600.
시리얼 출력에 대한 내용이 예제에 자주 등장하는 것은, 센서들의 값이나 핀으로 입력되는 값들 등을 직접 눈으로 확인할 수 있는 가장 간단한 방법이기 때문인데, 다음 강좌에서 "Serial"에 대한 내용을 다루도록 하겠다. 그 동안 그냥 시리얼 모니터 출력을 위한 함수라고만 하고 넘어가서 계속 찜찜해쪄.
...
sensorValue = analogRead(analogInPin); outputValue = map(sensorValue, 0, 1023, 0, 255); analogWrite(analogOutPin, outputValue); |
loop() 함수의 내용이다. analogRead() 함수를 이용해서 조도 센서(조도 센서 실습인 거 잊어먹을 뻔..)의 값을 sensorValue 변수에 저장한다. 그리고는 조금 전에 배운 map() 함수.
기억하고 있을지 모르겠지만, analogRead() 함수에서 반환되는 값은 0~1023 사이의 값이다. 0V에서 5V의 구간을 1024개로 나눈다고 했으니까.
그리고 analogWrite() 함수에 듀티비를 나타내는 값으로 들어갈 수 있는 값은 0~255 사이의 값이었다. 0을 주면 0%의 듀티비를 가진 PWM 출력, 255를 주면 100% 듀티비를 가진 PWM 출력.
그래서, 조도 센서에서 읽은 값이 0이면 LED 밝기로 0을 주고, 조도 센서 값이 1023이면 LED 밝기로 255를 주고, 조도 센서 값이 그 중간 어딘가라면 그 중간 어딘가에 위치하는 밝기 값을 LED에 주기 위해서 map() 함수를 사용. 즉, 0~1023 사이의 값 중 sensorValue 값을 0~255 사이의 값으로 바꿈.
그리고 그 값을 'outputValue' 변수에 저장해서 analogWrite() 함수로 LED의 밝기를 조절한다.
Serial.print("sensor = "); Serial.print(sensorValue); Serial.print("\t output = "); Serial.println(outputValue); |
시리얼 모니터로도 그 값을 확인하기 위해 Serial.print() 함수와 Serial.println() 함수를 이용하여 출력. 매개 변수에 ""로 묶은 부분은 그 문자열 그대로 출력되고, 매개 변수에 변수가 들어가면 그 변수 값이 출력됨.
자, 업로드 해보자. 시리얼 모니터도 실행하고.
조도 센서를 손으로 가렸다가, 빛을 비췄다가 하면서 값을 바꿔보고, 그 값이 변하는 것에 따라 LED의 밝기가 변하는지도 확인하자.
오. 변한다.
조도 센서의 값이 커지면 LED도 밝아지고, 조도 센서의 값이 작아지면 LED도 어두워진다.
근데, 뭔가 이상하네. 내가 원한건 이 동작이 아닌 듯. 난 주위가 밝으면 LED가 어두워지고, 주위가 어두워지면 LED가 밝아졌으면 좋겠는데. 이건 반대로 동작하네.
즉, 조도 값이 낮으면 LED로 내보내는 PWM의 듀티비가 커야 한다는 말. 어떻게 바꿀까?
쉽다. 한 줄만 바꾸면 된다.
AnalogInOutSerial2.ino |
const int analogInPin = A0; const int analogOutPin = 9; int sensorValue = 0; int outputValue = 0; void setup() { Serial.begin(9600); } void loop() { sensorValue = analogRead(analogInPin); outputValue = map(sensorValue, 0, 1023, 255, 0); analogWrite(analogOutPin, outputValue); Serial.print("sensor = " ); Serial.print(sensorValue); Serial.print("\t output = "); Serial.println(outputValue); delay(100); } |
map() 함수로 sensorValue 값을 바꿀 때 toLow 값과 toHigh 값을 바꾸면 반대 위치의 값이 나온다는 말. 0일 때 255로, 1023일 때 0으로.
업로드 한 후 확인해보자. 손으로 조도 센서를 가려 어둡게 만들면 LED가 밝아지고, 빛을 비춰 밝게 만들면 LED가 어두워지는 것이 보이는가?
지금 우리는 "자동 밝기 조절 전등"을 만든 셈이다. 완전 대다나다!
이러다 우주선 만드는거 아님? ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 아두이노로 3D 프린터도 만드는데, 우주선이라고 못만들까. ㅋㅋㅋㅋㅋㅋ
자, 그 날을 꿈꾸며. 이번 시간은 여기서 안녕~