1. 아두이노 (Arduino) 개요및개발환경구축 아두이노프로젝트는예술가, 디자이너또는학생들이저렴한마이크로컨트롤러를이용해제어장치를쉽게만들수있도록돕기위해마시모밴지 (Massimo Banzi) 와데이비드쿠아르티에예스 (David Cuartielles) 에의해 2005년이탈리아의이브레아 (Ivrea) 라는곳에서시작되었다. 아두이노가오픈소스하드웨어로발표된이후마이크로컨트롤러를활용해필요한제어장치를만들고자하는사람들로부터선풍적인기를끌기시작하여 2011년구글의오픈소스하드웨어파트너가되기까지꾸준한성장을거듭하면서오늘날에이르게되었다. 아두이노는앞에서도언급한것처럼오픈소스하드웨어로아트멜 (Atmel) 사의마이크로컨트롤러 (MCU - Micro Controller Unit) 를기반으로제작된소형보드이다. 하지만아두이노라는용어는단순히하드웨어에국한된용어가아니라아두이노보드를사용해소프트웨어를개발하는통합개발환경 (IDE Integrated Development Environment) 을포함하는포괄적의미를가진다. 1.1 아두이노보드의구성과기능 우리가실습에사용할아두이노보드는 Arduino Uno R3( 이하 Arduino Uno로표기하겠다.) 로그림 1-1과같이구성되어있다. USB와시리얼통신을위해 USB to 시리얼변환용마이크로컨트롤러로 Atmel사의 ATMega 16U2가장착되어있다. 또한외부장치와연결을위한입 / 출력핀, 전원연결단자와스케치프로그램을다운로드하기위한 USB 연결단자, 부트로더와프로그램다운로드를위한 ICSP 연결단자로구성되어있다. 아래는 Arduino Uno 보드의주요사양을표로나타낸것이다. 주요항목사양비고 마이크로컨트롤러 ATMega 328P USB-to-Serial 변환컨트롤러 ATMega 16U2 USB를이용한프로그램업로드지원등 동작전압 5V USB 연결입력전압 입력전압 7V ~ 12V 별도의외부전원입력단자 디지털입 / 출력핀 14개 3, 5, 6, 9, 10, 11번 6개핀은 PWM(Pulse Width Modulation) 을이용해아날로그출력기능제공 아날로그입력핀 6개 아날로그입력전용핀 플래시메모리 32KB ATMega 328P, 부트로더 0.5KB SRAM 2KB ATMega 328P EEPROM 1KB ATMega 328P 동작클럭 16MHz 16MHz의크리스털발진자 표 1-1 Arduino Uno 의주요사양 1.1.1 Atmel MCU(Micro Controller Unit) 아두이노 Uno를비롯한대부분의아두이노보드에는 Atmel사의 AVR ATMega 시리즈의 MCU 를사용하고예외적으로아두이노 Due에 32비트 ARM Cortex MCU를사용하고있다. MCU는컴파일된코드를저장하고프로그램에서지정한명령어를실행한다. 개발자는자신이작성한프로그램을아두이노보드의메인 MCU에업로드하여디지털입 / 출력핀, 아날로그-디지털컨버터 (ADC) 와시리얼인터페이스, 각종통신버스 (I 2 C와 SPI 등 ) 를통해아두이노보드와연결된전자회로를제어할수있다. 1.1.2 USB 프로그래밍인터페이스그림 1-1 Arduino Uno 보드의구성아두이노프로그램은 C/C++ 언어를기반으로한다. 개발자는 C/C++ 를이용해작성한자신의프로그램을 MCU에업로드해야아두이노를사용해주변장치를제어할수있다. ATMega 시리즈의 MCU는전용프로그래머를사용해프로그램을 MCU에업로드해야하지만 Arduino Uno 보드는메인마이크로컨트롤러로 Atmel사의 ATMega 328P가장착되어있고 - 1 -
아두이노는별도의프로그래머없이도컴퓨터와 USB 연결만으로아두이노의메인 MCU인 ATMega 328P에프로그램을업로드할수있다. 프로그래머역할을하는아두이노의부트로더가메인 MCU에이미설치되어있기때문에별도의프로그래머없이도시리얼 UART를사용해자신이개발한프로그램을아두이노의메인 MCU에업로드할수있다. 아래그림은국내의가치창조기술 (http://www.vctec.co.kr) 에서판매하고있는 AVR 전용프로그래머로 ICSP 연결단자와연결해아두이노의부트로더나스케치프로그램을메인 MCU인 ATMega 328P에업로드할수있다. 전원공급에주로사용된다. 1.1.4 디지털입 / 출력핀과아날로그-디지털컨버터 (ADC) 아두이노보드와연동하는전자회로를구성하고프로그래밍하여테스트할경우가장많이사용되는부분이바로디지털입 / 출력핀과아날로그-디지털컨버터 (ADC) 핀들이다. 디지털입 / 출력핀들은디지털신호의입력과출력에사용되며프로그램에서각각의핀을지정하여디지털입력신호와출력신호를제어할수있다. 아날로그-디지털컨버터 (ADC) 핀들은각종센서가출력하는 0V ~ 5V 사이의전압이나아날로그신호를입력받아그값을디지털신호로변환해메인컨트롤러에전달한다. 우리가사용하는 Arduino Uno 보드는아날로그입력을지원하는 6개의핀이존재하지만아날로그출력을지원하는별도의핀은존재하지않는다. 아날로그출력은디지털입 / 출력핀중에서 3, 5, 6, 9, 10, 11번핀이 PWM(Pulse Width Modulation 펄스폭변조 ) 기능을지원하여이들핀을이용해 PWM 형식의디지털출력으로아날로그출력을대체할수있다. 그림 1-2 AVR Programmer 1.2 아두이노보드의종류 아두이노보드는오픈소스를기반으로하는하드웨어이다. 그렇기때문에시중에유통되는아두이노보드는아두이노사에서제작한정품아두이노보드와세계의여러제조사에서제작한많은아두이노호환보드가존재한다. 이외에도아두이노보드의기능확장을위해쉴드 (Shiedl) 라불리는다양한확장모듈들이존재한다. 아두이노보드의주력제품은우리가실습에사용하는 Arduino Uno 보드이다. Arduino Uno 에는메인 MCU인 ATMega 328P를보드에서제거할수있는 DIP(Dual In-line Package) 버전과 MCU를제거할수없는표면실장형 ( 납땜처리된 ) 보드인 SMD(Surface Mount Device) 버전이있다. 두가지버전의 Arduino Uno 보드는그림1-3과같이구성되어있다. 1.1.3 정전압장치와외부전원단자대부분의아두이노프로젝트에서사용하는전원공급방식은아두이노보드와컴퓨터를 USB로연결해아두이노보드의동작에필요한 5V 전원을공급받을수있다. 이외에도컴퓨터와연결없이별도의직류 (DC) 전원공급단자를사용해 7V ~ 12V 전원을아두이노보드에공급할수있다. 이렇게입력된전원은아두이노보드에내장되어있는정류기로 5V와 3.3V로정류하여사용된다. 5V의전압은아두이노보드의대부분의회로에서사용된다. 예를들어아두이노보드의 4번디지털입 / 출력핀에연결된회로의 LED를 4번핀에 5V 또는 0V를가해 LED를켜거나끌수있도록할수있다. 아두이노보드에는 3.3V의출력핀이 1개가존재하며이 3.3V의전압은 XBee 무선통신모듈을연결하기위한쉴드 (Shield) 와같이 3.3V의전압이필요한확장쉴드 (Shield) 나외부회로의 - 2 - 그림 1-3 Arduino Uno 보드의 DIP 버전과 SMD 버전
접방문해확인해보자. Arduino Mega ADK 보드는그림 1-5 와같이구성되어있다. 아두이노보드는다양한사양의여러가지보드가출시되어있으며대부분의아두이노보드는 Atmel사의 8비트 AVR ATMega 시리즈의 MCU를메인 MCU로채택하고있으나 Arduino Due 보드는메인 MCU로 ARM사의 32비트 ARM Cortex M3 SAM3X MCU를장착하여출시되었다. Arduino Due는 Arduino Uno 보다클럭속도가빠른 84MHz의동작속도를가지며해상도조정이가능한 PWM, 정밀한 ADC와디지털-아날로그컨버터 (DAC), USB 호스트연결단자가장착되어있다. 이외에도아두이노보드시리즈중에독특한디자인을가진 LilyPad라는보드가있는데이보드는의류에장착할수있도록설계되어전도성섬유를사용하면옷에봉재된센서나 LED 등과연동하는여러가지효과를제어할수있다. 그림 1-4에서왼쪽이 Arduino Due이고오른쪽동그란보드가 LilyPad의사진이다. 그림 1-5 Arduino Mega ADK 1.3 아두이노통합개발환경구축 아두이노프로젝트는 H/W와통합개발환경 (IDE) 모두오픈소스로진행되는프로젝트이다. 그렇기때문에누구나아두이노보드와호환되는 H/W를만들어판매할수있으며통합개발환경 (IDE) 또한전세계누구나다운받아사용이가능하다. 그림 1-4 Arduino Due와 LilyPad 아두이노의통합개발환경 (IDE) 은다양한운영체제를지원하기위해자바로개발되었으며아두이노통합개발환경 (IDE) 을통해프로그램을작성하고한번의클릭으로프로그램을컴파일할수있는기능을지원하고있다. 또한한번의클릭으로컴파일과동시에아두이노보드로업로드아두이노는 2011년구글의오픈소스하드웨어파트너로지정되면서 Arduino Mega 2560 보드하여프로그램을실행할수도있다. 와비슷한성능의 Arduino Mega ADK(Accessory Development Kit) 라는보드를출시하였다. 아두이노에서기본제공되는예제프로그램과개발자가아두이노를통해작성한프로그램을스이보드의메인 MCU는 Atmel 사의 ATMega 2560을사용하며시리얼인터페이스를한개만케치 (Sketch) 라부르며이단어에서느낄수있듯이프로그램을그림그리듯이쉽게작성할수제공하는 Arduino Uno 보다많은 4개의시리얼인터페이스를지원하고 ADC 채널도더많이있다는의미로사용된다. 지원하고있다. 또한 Arduino Uno에비에훨씬많은기기와통신할수있는디지털입 / 출력자! 그럼아두이노통합개발환경 (IDE) 을다운로드받아설치하고아두이노의 Hello Java 격인핀을 54개나 (ATMega 2560 보드와동일함.) 제공하고있다. 아두이노예제프로그램의 Blink 스케치를구동시켜보자. Arduino Mega ADK는 USB 호스트기능을장착하여 USB를사용해안드로이드폰과간편하게연결을할수있어개발자가작성한안드로이드앱을쉽게연동할수있도록지원하고있다. 이외에도 http://arduino.cc/en/main/products 사이트를참조하면여러종류의아두이노 1.3.1 아두이노통합개발환경 (IDE) 다운로드및설치보드와아두이노보드를이더넷에연결해주는이더넷쉴드 (Shield) 와같은여러가지확장쉴아두이노통합개발환경 (IDE) 은 http://arduino.cc/en/main/software에서다운로드받을수드를볼수있을것이다. 여러가지종류의아두이노보드를확인하고싶다면위의사이트를직있다. 먼저위의사이트에접속해그림 1-6 위쪽그림의빨간색박스부분인 Windows ZIP - 3 -
file for non admin install 을클릭하면그림 1-6 의아래쪽그림이나타나는데여기서빨간 색박스부분인 JUST DOWNLOAD 를클릭해서 arduino-1.6.6 버전의아두이노통합개발환 경 (IDE) 을다운로드받는다. 2015 년 11 월 3 일 arduino-1.6.6 버전이정식으로릴리즈되었다. 이압축유틸리티를이용해여기에압축풀기를선택해압축을푼다. 그림 1-7 Arduino 통합개발환경 (IDE) 설치하기 02 아두이노통합개발환경은별도의설치과정없이압축을해제하는것만으로그림 1-8 과같이설 치를완료할수있다. 그림 1-6 Arduino 통합개발환경 (IDE) 설치하기 01 그림 1-8 Arduino 통합개발환경 (IDE) 설치하기 03 다운로드가완료되었다면 arduino-1.6.6-windows.zip 파일을 C:\ 에복사하고그림 1-7 과같 - 4 -
설치가완료되었다면 arduino-1.6.6 폴더로이동해 arduino.exe 를더블클릭해실행해보자. 그럼그림 1-9 와같이아두이노의통합개발환경 (IDE) 을만날수있을것이다. 게된다. 우리가설치한아두이노통합개발환경의설치위치는 C:\ 에압축을풀어설치했으므로 아두이노와관련된 drivers 폴더의위치는 C:\arduino-1.6.6\drivers 가될것이다. 그림 1-10 Windows 8.1 의장치관리자 그림 1-9 Arduino 통합개발환경 (IDE) 1.3.2 아두이노를컴퓨터와연결하고테스트하기아두이노통합개발환경을종료하고 Arduino Uno 보드를컴퓨터와연결하면 USB를통해아두이노보드에전원이공급되면서아두이노보드가시작된다. 처음컴퓨터와연결한경우에는아두이노보드의드라이버가자동으로설치되지않으므로 [ 제어판 ] - [ 하드웨어및소리 ] - [ 장치관리자 ] 를통해아두이노드라이버를수동으로설치해야한다. 아두이노보드를컴퓨터에처음연결하면장치관리자의 기타장치 에그림 1-10의좌측그림과같이 알수없는장치 가나타나는데여기에마우스오른쪽버튼을클릭해그림 1-10의우측그림과같이 드라이버소프그림 1-11 드라이버소프트웨어업데이트 01 트웨어업데이트 (P) 를선택하면그림 1-11과같은소프트웨어업데이트대화상자가나타난다. 여기에서빨간색사각형으로표시한 컴퓨터드라이버소프트웨어찾아보기 를클릭하면그림 1-12와같이수동으로아두이노드라이버위치를지정할수있는대화상자가나타난다. 여기서그림 1-12에서 다음 버튼을클릭하면 Windows 보안대화상자가나타나고 설치 버튼을클 찾아보기 버튼을클릭하여아두이노통합개발환경이설치된폴더아래의 drivers 폴더를아래릭하면드라이버를설치하고 1-13과같은드라이버소프트웨어업데이트완료창이나타난다. 그림과같이지정하면 다음 버튼이활성화되고그버튼을클릭하게되면다음단계로넘어가 - 5 -
포트번호는아두이노와컴퓨터사이의통신에서반드시필요한부분으로아두이노통합개발환경에서스케치를아두이노보드에업로드할때포트번호를선택해줘야한다. 스케치를아두이노보드에업로드할때포트번호가기억나지않는다면장치관리자에서확인하면된다. 그림 1-14와같이아두이노보드에 COM10번포트가할당된것을볼수있는데여러분은필자와다를수있으니 COM 포트번호가다르다고걱정할필요는없다. 그림 1-12 드라이버소프트웨어업데이트 02 그림 1-14 드라이버소프트웨어업데이트 04 아두이노보드들은많은부분에서호환되지만동작클럭이나입 / 출력핀의수등에서차이가있으므로통합개발환경에서사용할아두이노보드의종류를지정해야한다. 아두이노의통합개발환경을실행하고그림 1-15의좌측그림과같이 [ 도구 ] - [ 보드 ] 를선택하그림 1-13 드라이버소프트웨어업데이트 03 면사용가능한여러가지보드의종류를나열한메뉴가나타나는데여기서 Arduino Uno 보드를선택한다. 그리고컴퓨터에서아두이노보드에데이터를전송할수있도록하려면드라이버를설치할때장치관리자에서확인했던 COM 포트를그림 1-15의우측그림과같이지정해아두이노의드라이버가성공적으로설치되었다면그림 1-14와같이장치관리자에서 [ 기타장치 ] 야한다. 이제아두이노의통합개발환경을사용해여러가지제어장치를만들준비가끝났다. - [ 알수없는장치 ] 가사라지고 [ 포트 (COM & LPT)] - [Arduino Uno(COM10)] 에표시될것이아두이노통합개발환경은다양한예제를제공하고있는데이중에서가장기본적인예제인다. 아두이노보드는 USB를통해연결되지만실제아두이노와컴퓨터의 USB 연결은가상의 Blink 라는스케치불러와실행해보자. COM 포트를통해이루어지므로장치관리자에서는 포트 (COM & LPT) 에나타난다. - 6 -
그림 1-16의좌측그림과같이 [ 파일 ] - [ 예제 ] 를선택하면아두이노에서기본적으로제공하는여러종류의스케치리스트가나타나는데여기서 [01Basics] - [Blink] 를선택하면새로운창이화면에띄워지면서그림 1-16의우측그림과같은 Blink의코드를볼수있을것이다. 그림 1-16의우측그림에서확인버튼 ( ) 을클릭하면스케치를컴파일하는데만약스케치에오류가있으면그림 1-17의좌측그림과같이코드에오류가있음을알려준다. 오류를수정하고다시확인버튼 ( ) 을클릭하면그림 1-17의우측그림과같이컴파일이완료되면서아두이노보드에업로드할스케치의크기가출력된다. 오류없이컴파일이완료된것을확인했으면업로드버튼 ( ) 을이용해스케치를아두이노보드에업로드할수있다. 업로드버튼 ( ) 을클릭하면스케치를다시컴파일하고아두이노보드에업로드되어프로그램이실행된다. 그림 1-15 통합개발환경에서 Arduino Uno 보드선택과 COM 포트지정하기 그림 1-17 아두이노스케치의컴파일 그림 1-16 Blink 스케치실행하기 위에서사용한 Blink 스케치는아두이노 13번핀에연결된 LED를 1초마다점멸시키는예제로 Arduino Uno 보드는 13번핀에연결된 LED가보드에포함되어별도의 LED를연결하지않아도 LED 테스트를할수있다. Blink 스케치가아두이노보드에제대로업로드되었다면 13번핀에연결된 LED가 1초간격으로껴지고꺼지는것을볼수있을것이다. 아두이노에서제공하는기본적인예제를불러와사용하고수정한후그대로저장하게되면기본 - 7 -
스케치가변경되므로수정후에는반드시다른이름으로저장하기메뉴를통해다른위치에저 장하는것이바람직하다. 그렇지않으면기본스케치가훼손되어나중에그스케치를참고할때 문제가생길수있다는것을꼭기억하기바란다. - 8 -
2. 아두이노를위한전기전자기초 2.1 옴의법칙과전력량구하기 2.1.1 전압 (Voltage) 전기장내에서두지점사이의전위 (Electric Potential Difference : 전기적위치에너지 ) 의차를전위차또는전압 (Voltage) 이라한다. 전위 (Electric Potential) 란전기장내에서단위전하가가지는위치에너지로스칼라 (Scalar 방향을가지고있지않고크기만가지고있는물리량을의미한다.) 량이며국제표준단위로 V(Volt) 라는단위를사용한다. 2.1.2 전류 (Electric Current) 전류 (Electric Current) 는물이중력에의해높은곳에서낮은곳으로흐르듯이전위가높은곳에서낮은곳으로전하가연속적으로이동하는현상을말한다. 전하 (Electric Charge) 란어떤물체가띠고있는정전기의양으로모든전기현상의근원이되는실체이다. 전하는양전하와음전하가있으며전위차가있는두지점을연결하게되면전위가높은곳에서낮은곳으로전하가이동하게되는데이를전류 (Electric Current) 라부른다. 물이중력으로인해높은곳에서낮은곳으로흐르듯이전류는기전력이라는힘에의해전압이높은곳 (Vcc - 고전압 ) 에서낮은곳 (GND - 저전압또는접지 ) 으로흐르게된다. 또한물이흐르는통로를수로라한다면전류가흐르는통로는전기회로라할수있다. 전류는국제표준단위로 A(Ampere) 라는단위를사용한다. 위의공식에서알수있듯이전압이높을수록전류량은많아지며저항이높을수록전류량은적어지므로전류의세기는전압에비례하고저항에반비례한다는것을알수있다. 그러므로전기회로에서전류는저항이낮은곳으로흐르게된다. 모든전압은전기회로안에서소진되며회로의각부품에는전류를낮추는일정한저항이사용된다. 이옴의법칙을이용하면아두이노회로에서사용되는 LED나각종센서와같은전자부품에연결해야할적정저항값을구할수있다. LED와같은전자부품은특정전압과전류에서동작하도록제조된다. LED에많은전류가흐를수록빛이밝고열이많이발생하게된다. 아래의그림은국내전자부품전문쇼핑몰인디바이스마트 (http://www.devicemart.co.kr) 에서판매되는 LED 데이터시트의일부분이다. 이 LED는아두이노에서가장일반적으로사용되는 LED중하나이다. 이를자세히살펴보면동작전압은 2.2V ~ 2.5V이고최대전류는 30mA 정도로 20mA에서테스트되었다는것을알수있다. 2.1.3 저항 (Resistor) 저항은전류의흐름을방해하는작용의정도를말하며국제표준단위로 Ω(Ohm) 이라는단위를사용한다. 1Ω은기전력이존재하지않는도체의두점사이에서 1V의전위차로 1A의전류가흐를때의저항을의미한다. 다시말해 1Ω은 1V의전압을가할때 1A의전류가흐르는도체의저항을의미하며아래와같은관계가성립된다. 1Ω = 1V / 1A 2.1.4 옴 (Ohm) 의법칙 전류의세기는두지점사이의전위차에비례하고전기저항에반비례한다는법칙으로 1826년 그림 2-1 아두이노에서많이사용되는 LED 데이터시트 독일의물리학자 G. S. Ohm에의해발견되어세상에알려졌으며그로부터옴의법칙으로불린 다. 이옴의법칙은전기회로내의전류, 전압, 저항사이의관계를나타내며전기회로를다루기 위해서필수적으로알아야할매우중요한법칙이다. 일반적으로아두이노회로는 5V 또는 3.3V의입력전압에서동작하게되는데위의 LED 데이터 전압의크기를 V, 전류량을 I, 전기저항값을 R이라할때아래와같은관계가성립된다. 시트를참고하여그림 2-2의회로도와같이 LED 하나를동작시킬수있는저항값을옴의법 칙을사용해구해보자. V = IR ------> I = V / R 그림 2-2와같이우리가구성하는전자회로는아두이노의입력전압인 5V를사용할것이므로 - 9 -
입력전압은 5V, LED의동작전압은 2.2V ~ 2.5V 보다약간작은 2V, 전류는테스트에서사용한 20mA를적용해계산해보면될것이다. 입력전압 (5V) LED 동작전압 (2V) = 초과전압 (3V) 가되므로저항을사용해초과전압을낮춰야한다. 옴의법칙인 V = IR을적용해초과전압인 3V를 0V로낮춰야하기때문에 3V = 20mA * R의계산식에서 R = 3V / 20mA(0.02A) 가되므로저항 R의값은 150Ω이라는값이나온다. 그림 2-2 저항과 LED 회로그러므로저항값이 150Ω인저항을사용하면 LED가손상되지않는범위의전압 (2V) 에서 20mA의전류를 LED에흐르게할수있어 LED의불빛을밝게켤수있게되는것이다. 일반적으로저항을선택할때는전자부품을보호하기위해계산식으로구한값보다약간높은저항을사용하며저항값이조금높다고해서 LED를동작시킬수없는것이아니고 LED에흐르는전류량만큼 LED를밝게할수있기때문에위의계산식에서구한저항값인 150Ω보다저항값이약간높은 180Ω ~ 220Ω정도의저항을사용하면될것이다. 물론그이상의저항값을가진저항도사용이가능하다그렇지만 LED의불빛은생각보다밝지못할수있다. 2.1.5 회로의소비전력체크하기위에서알아본옴의법칙과같이알아두면좋은공식으로전력량을구하는공식이있다. 이전력량을구하는공식을알면전기회로에서각부품이전력을얼마나소비하는지알수있다. 전자부품이전력을많이소모할수록열이많이발생하기때문에현재유통되는대부분의전기 / 전자부품에는최대전력이표시되어있다. 이최대전력을초과하게되면회로가과열되어부품이손상될수있기때문에회로를구성할때는반드시저항의최대전력을확인한후회로를구성할필요가있다. 전력 (Electric Power) 의단위는 W(Watt 1W는 1초동안에소비하는전력을의미한다.) 가사용된다. 최대전력을 P, 전류량을 I, 전압의크기를 V라할때아래와같은공식으로최대전력을구할수있다. 그림 2-3 저항의정격전력그럼이번에는최대전력을구하는공식을사용해옴에법칙에서사용한 LED에필요한저항의최대전력을구해보자. 옴의법칙에서계산한식을보면아두이노에서입력되는입력전압은 5V이고 LED의동작전압은 2.2V ~ 2.5V 보다약간작은 2V, 전류는테스트에서사용한 20mA를적용해계산하게되면초과전압이 3V가되고전류는 20mA이므로최대전력을구하는공식 P = IV에서이회로에사용할저항의최대전력을구하게되면 P = 20mA(0.02A) * 3V = 0.06W(60mW) 가된다. 일반적으로시중에서판매되는탄소피막고정저항 (LEAD Resistor 막대저항이라고도한다.) 은 1/8W(125mW), 1/4W(250mW), 1/2W(500mW), 1W의최대전력을가진저항이많이유통되고있다. 시중에서쉽게구할수있는저항중에서위의계산식으로구한저항의최대전력보다큰저항을선택하면되겠다. 60mW보다소비전력이큰저항을사용해야저항으로서의역할을제대로할수있어회로의다른부품들도보호할수있다. 만약계산식에서구한전력보다작은소비전력의저항을사용하게되면저항이열을견디지못해타버리고저항이제역할을다하지못했기때문에회로의다른부품들도손상되는결과를가져올것이다. 위에서구한저항의최대전력이 60mW이므로이보다크고가장근접한소비전력을가진저항인 1/8W(125mW) 를선택하면우리가구성한회로는정상적으로잘동작할것이다. 하지만 1/8W의탄소피막고정저항은저항의크기가너무작아저항값을표시하는띠를읽기가힘들수있다. 그러므로 1/8W 보다더큰소비전력에서도동작할수있는 1/4W의저항을선택하면 1/8W의저항보다상대적으로크기가커서저항값을표시하는띠를읽기가수월할것이다. P = IV 2.2 아두이노에사용되는전자부품위의공식에서알수있듯이전류량이많거나전압이높을수록전력이높기때문에그회로의사용환경에맞는적절한저항의선택이필요하다. 그렇지않으면저항뿐만이아니라그회로에사용되는부품들이열에의해손상될수있다. 그러므로전자회로를구성할때는그회로에사용되는부품의데이터시트를반드시확인한후회로를구성할수있도록하자. 그림 2-3은국내전자부품전문쇼핑몰인디바이스마트 (http://www.devicemart.co.kr) 에서판 2.2.1 저항 (Resistor) 매하고있는고정저항의데이터시트에서발췌한저항의정격전력이다. 아두이노와전자부품을처음접하는입문자라면아두이노도서와기본부품들로구성된스타터 키트를권장하고싶다. 그래도아두이노에관심을가지고이를사용해여러가지제어장치를 만들고자하는입문자라면가장기본적인부품의용도와사용법은알고있어야할것이다. 아 두이노실습에가장일반적으로사용되는전자부품을중심으로간단히알아보도록하자. 저항은전류의흐름을방해하는성질을가진회로소자로전자회로를구성할때빠져서는안되 - 10 -
는약방의감초같은전자부품이다. 저항은전류나전압을제한하는용도로사용되며저항기 (Resistor) 라고도부른다. 저항은국제표준단위로 Ω(Ohm) 이라는단위를사용하며대부분의저항은두개의다리 (Lead) 가있는막대형태의원통형으로제작되며저항은따로극성을갖지않는다. 저항이극성을갖지않는다는말은저항을회로에연결할때양극 (Vcc) 또는음극 (GND) 어디든연결할수있다는말이다. 그렇다고저항의두다리를모두양극으로연결하거나음극으로연결해서는안된다. 다시말해저항을회로에연결할때저항의양쪽다리가양극과음극으로하나씩연결되어야하지만저항에는극성이없으므로어떤방향으로연결해도된다는말이다. 일반적으로저항은크기가작기때문에저항의용량을표시하기위해저항의몸통에색상띠를사용해저항값을표시한다. 표 2-1은저항의표준색상코드표이다. 띠가녹색으로 5 를나타내고있으므로 15 가된다. 그리고저항값의승수를나타내는세번째 띠가빨간색으로 2 를의미한다. 즉 10 의 2 제곱승으로 10 2 (100) 을나타내고있는것이다. 네번째띠가보라색으로 ±0.1%(B) 의오차를가지는저항이라는것을나타내고있다. 위의값들을조합하여계산해보면 15 100 = 1500Ω 으로그림 2-4 의저항은 1.5KΩ 에 ±0.1%(B) 의오차를가지는저항이라는것을알수있다. 갈 색 녹 색 빨간색 보라색 그림 2-4 4 띠저항과저항기호 색상 (Color) 첫번째띠두번째띠세번째띠네번째띠다섯번째띠저항값저항값저항값제곱승수오차범위 검정색 (Black) 0 0 0 10 0 갈색 (Brown) 1 1 1 10 1 ±1%(F) 빨간색 (Red) 2 2 2 10 2 ±2%(G) 주황색 (Orange) 3 3 3 10 3 노란색 (Yellow) 4 4 4 10 4 녹색 (Green) 5 5 5 10 5 ±0.5%(D) 파란색 (Blue) 6 6 6 10 6 ±0.25%(C) 보라색 (Violet) 7 7 7 10 7 ±0.1%(B) 회색 (Gray) 8 8 8 10 8 ±0.05%(A) 흰색 (White) 9 9 9 10 9 금색 (Gold) ±5%(J) 은색 (Silver) ±10%(K) 없음 (None) ±20%(M) 표 2-1 저항의표준색상코드 [ 연습문제 2-1] 표 2-1 을참고해아래그림의 4 띠저항의값을구해보자. 파란색 회 색 정밀한저항은 5 개의색상띠를사용해용량을표시하며첫번째, 두번째, 세번째띠는저항 값을표시하고네번째띠는저항값의 10 의제곱승을표시하며다섯번째띠는저항값의오 차범위를표시한다. 그림 2-5 의저항은 5 가지색상띠를사용해저항값을표시하고있다. 이 저항값을표 2-1 을참고해계산해보자. 그림 2-5 저항을자세히살펴보면저항값을표시하 는첫번째띠가노란색으로 4 를두번째띠가보라색으로 7 을그리고세번째띠가검정색으 로 0 을나타내고있으므로 470 이된다. 갈 색 금 색 일반적인저항은 4개의색상띠를사용하여용량을표시하며첫번째와두번째띠는저항값을표시하고세번째띠는저항값의 10의제곱승을표시하며네번째띠는저항값의오차범위를표시한다. 그림 2-4는고정저항과저항의기호를나타낸그림으로이저항은 4가지색상띠를사용해저항값을표시하고있다. 이저항의저항값을표 2-1을참고해계산해보자. 그림 2-4 저항을살펴보면저항값을표시하는첫번째띠가갈색으로 1을나타내며두번째 노란색 보라색 검정색 갈 색 그림 2-5 5 띠저항 금 색 - 11 -
그리고저항값의승수를나타내는네번째띠가갈색으로 1 을나타낸다. 즉 10 의 1 제곱승으 로 10 1 (10) 을나타내고있는것이다. 다섯번째띠가금색으로저항값에서 ±5%(J) 의오차가있는저항이라는것을나타내고있다. 이값들을조합해다시계산해보면 470 10 = 4700Ω 으로그림 2-5 의저항은 4.7KΩ 의저 항값에 ±5%(B) 의오차범위를갖는저항이라는것을알수있다. [ 연습문제 2-2] 표 2-1 을참고해아래그림의 5 띠저항의값을구해보자. 갈 색 녹 색 검정색 빨간색 갈 색 전류가흐르도록다이오드가연결된것을순방향연결 (Forward Bias) 이라하고전류가흐르지않도록연결된것을역방향연결 (Reverse Bias) 이라한다. 정류다이오드는교류전원을직류전원으로변환하거나역방향의전류로부터회로를보호하는목적으로주로사용된다. 이제우리가아두이노실습에서저항다음으로많이사용하게될발광다이오드 (Light Emitting Diode - LED) 에대해알아보자. LED는 Light Emitting Diode의약자로빛을내는반도체란뜻을가지고있으며기존의전기발광체에비해열이적게발생하며반영구적인수명이 LED의가장큰특징이라할수있다. LED는순방향으로전원이연결되었을때만빛을발산하는다이오드로주로표시장치에많이사용된다. 그림 2-7은 LED 모양과회로도에서사용하는 LED의기호이다. 위에서살펴본저항은고정저항 (LEAD 저항, 막대저항이라고도한다.) 으로고정저항의종류도재질에따라탄소피막저항, 금속피막저항, 권선형저항등이있으며고정저항외에도칩저항, 어레이저항, 시멘트저항등많은종류의저항이있으며우리가앞으로아두이노실습을하면서사용할광센서나온도센서그리고포텐셔미터 (Potentiometer) 와같은가변저항도있다. 2.2.2 다이오드 (Diode) 다이오드또한여러가지종류가있으나우리가다뤄야할범위를넘어서기때문에일반적이정류다이오드의특징과용도그리고아두이노보드를가지고여러가지실습을할때많이다루게되는발광다이오드 (Light Emitting Diode LED) 에대해서만알아보겠다. 다이오드는전류를한쪽방향으로만흐르게하고다른쪽방향은차단하는반도체부품이다. 여러종류의다이오드중에서양극 (Vcc Anode라한다.) 에서음극 (GND Cathode라한다.) 방향으로전류가흐르는특징을이용한다이오드를정류다이오드 (Rectifier Diode) 라고하며 우리가일반적으로말하는다이오드가바로정류다이오드이다. 그림 2-6은정류다이오드 (Rectifier Diode) 와회로도에서사용하는다이오드의기호이다. 그림 2-6 정류다이오드와기호 그림 2-7 발광다이오드 (LED) 와기호앞에서다이오드는한쪽방향으로만전류를흐르게한다고그랬다. LED도다이오드의일종이므로극성을갖는다. LED를회로에연결할때는반드시극성을체크하여연결해야한다. LED는양극 (+) 을애노드 (Anode) 라하고반드시 Vcc( 전원 ) 에연결해야한다. 또한음극 (-) 을캐소드 (Cathode) 라하며반드시 GND( 그라운드 ) 에연결해야한다. 그림 2-7을살펴보면 LED의다리가긴쪽이애노드 (Anode) 이고다리가짧은쪽이캐소드 (Cathode) 이다. LED는반드시극성에맞게회로에연결해야하며반대로연결할경우전류가흐르지못하므로 LED는켜지지않고 LED가손상될수있다. LED는첨가된화학물질에따라다양한색상의빛을표현할수있으며적색과녹색 LED가가장흔하게사용된다. LED는빛을발산하기때문에우리생활에서여러용도로사용되는데우리가일상적으로많이사용하고있는리모컨에는적외선 LED가사용되고살균 / 소독용기기에는자외선 LED를사용되고있다. 옴의법칙에서알아본것처럼 LED마다최대전압과전류가정해져있으므로반드시적절한저항과같이사용해야한다. - 12 -
2.2.3 캐패시터 (Capacitor) 캐패시터 (Capacitor) 는아주짧은시간동안전기에너지를저장할수있는전자부품으로전자회로에서안정된전원공급을위해주로사용된다. 캐패시터 (Capacitor) 는콘덴서 (Condenser) 또는축전지라고도불리지만캐패시터가더정확한이름이라할수있다. 캐패시터또한종류가많고그종류만큼이나서로다른특성을가지고있다. 항체에연결되고세번째핀 ( 일반적으로중앙에위치한핀, 와이퍼라고한다.) 은회전하면서저항체의어디에나연결될수있는와이퍼에연결된다. 포텐셔미터가회전하게되면중앙의와이퍼를기준으로어느한쪽의저항은증가하고다른한쪽의저항은감소하게된다. 우리의아두이노실습에서포텐셔미터는아두이노보드로입력되는포텐셔미터의변화되는값을아날로그입력핀으로읽을때사용하게될것이다. 일반적으로아두이노의아날로그입력핀에포텐셔미터를연결할때는 10KΩ의포텐셔미터를많이사용한다. 그림 2-8 전해캐패시터와기호시중에흔히볼수있는것이콘덴서라불리우는전해캐패시터로그림 2-8의좌측그림과같은모양을하고있다. 전해캐패시터는극성을가지고있는캐패시터로그림 2-8의빨간색사각형으로표시한부분이음극 (-) 을표시하는부분이다. 2.2.5 포토레지스터 (Photoresistor) 포토레지스터 (Photoresistor) 는빛의밝기에따라저항값이바뀌는가변저항이다. 포토레지스터와같이빛의밝기에따라저항값이바뀌는가변저항을 LDR(Light Dependent Resistor) 이라고한다. 포토레지스터는주변의밝기정도에따라저항값이바뀌기때문에전압도바뀌게된다. 포토레지스터는빛의양이많아지면저항값이줄어들고어두워지면저항값이수 MΩ까지도올라가는특성을가지고있다. 포토레지스터를 CDS 조도센서라고도하며흔히빛감지센서또는조도센서라고도한다. CDS 센서는빛에노출되면저항값이감소하는광전도효과 (Photo Conductive Effect) 를이용한반도체센서에속한다. 그림 2-10의좌측그림은시중에서쉽게구할수있는포토레지스터이다. 2.2.4 포텐셔미터 (Potentiometer) 포텐셔미터 (Potentiometor) 는직선의변위나회전의변위를전기저항의변화로바꾸는가변저 항기이다. 그림 2-8 에서와같이포텐셔미터에는세개의핀이있으며그중두개의핀은저 그림 2-10 포토레지스터와기호 우리는위에서언급한포토레지스터의특성을이용해빛의양을측정하여밝으면 LED 를끄고 어두우면 LED 를켜는회로를구성해테스트하는실습을해볼것이다. 그림 2-9 포텐셔미터와기호 2.2.6 써미스터 (Thermistor) 써미스터 (Thermistor) 는망간, 니켈, 코발트, 철, 동, 티탄등의여러가지금속산화물을녹여만든반도체소자이다. 일반적인금속과는다르게온도가올라갈수록저항이감소하는전기적성질을가지고있어주변의온도변화를전기적신호로바꾸어주는여러가지유형의센서역할을한다. 온도측정범위는 50 ~ 300 정도로온도측정장치나자동온도조절장치에많 - 13 -
이사용된다. 이외에유량계나기압계그리고전력계등의여러산업분야에서사용되고있다. 트랜지스터는베이스 (Base), 에미터 (Emitter), 콜렉터 (Collector) 로구성되어있으며베이스로입력되는전류의작은변화에따라콜렉터와에미터사이에흐르는전류에큰변화를줄수있도록설계되어있다. 트랜지스터는전자회로에서고전류나고전압을스위칭하는데사용되며아날로그회로에서는신호를증폭시킬목적으로사용된다. 트랜지스터는 1948년발명되어그이전에사용하던진공관에비해낮은소비전력으로소형화경량화를가능하게함으로서전자혁명을이끈주역으로평가받고있다. 그림 2-11 써미스터와기호사실써미스터는한종류만있는것이아니고몇가지종류로분류되지만우리가주로사용할써미스터는온도가오르면저항값이떨어지는 NTC(Negative Temperature Coefficient) 계열의써미스터를사용할것이므로나머지는언급하지않겠다. 써미스터또한극성이없어일반저항과같이어떤방향으로연결해도문제없이잘동작한다. 2.2.7 트랜지스터트랜지스터는서로다른종류의반도체를접합해만든소자로접합된반도체의종류에따라 NPN형과 PNP형으로나뉜다. 두종류의트랜지스터는극성이반대인것을제외하면동작하는원리는같다. 2.2.8 스위치스위치는전기회로에서전원을연결하고차단하는데주로사용된다. 스위치의종류에는슬라이드스위치 (Slide Switch), 택트스위치 (Tact Switch), 푸쉬스위치 (Push Switch) 등등스위치의종류도너무많아여기서전부나열할수는없고실습에사용할택트스위치에대해서만간단히알아보도록하자. 택트스위치도푸쉬스위치에일종으로스위치안쪽에스프링을장착해일정이상의힘이가해지면반대방향으로스프링이변형되면서작동되기때문에스위치를눌렀을때딸각하는느낌이생기게되는데이러한종류의스위치를택트스위치라고부른다. 택트스위치내부에는두쌍의접점 ( 스위치의다리가 4개로구성되어있다.) 이있는데이들접점은스위치를눌렀을때서로연결된다. 각쌍의두접점은스위치내부에서서로연결되어있으므로두개의접점중어느것을사용해도스위치는정상적으로동작한다. 그림 2-13의좌측그림과우측의기호를보면택트스위치가내부적으로어떻게연결되어있는지짐작할수있을것이다. 그림 2-13 택트스위치와기호 그림 2-12 PNP 형트랜지스터와 NPN 형트래지스터 - 14 - 그림 2-13 의우측회로기호와같이스위치내부에서 1 번과 2 번또는 3 번과 4 번이서로연결 되어있기때문에택트스위치를가지고회로를구성할때는 1 번과 3 번또는 2 번과 4 번을스위
2.3 회로도그리기 치접점으로사용하거나 1번과 4번또는 2번과 3번을스위치접점으로하여스위칭을구성해야스위치가제대로동작할수있다. 전자부품을처음만져보는입문자라면부품하나하나파악하기도힘든데무슨회로도를그릴스위치의값을명확하게하기위해일반적으로풀업 (Pull-up) 저항또는풀다운 (Pull-down) 이수있겠어라는생각을하는사람이대부분일것이다. 라불리는저항을 1KΩ ~ 10KΩ을연결해사용한다. 풀업 (Pull-up) 저항이란 Vcc에서나온전맞는말이다. 용어하나가생소하고난생처음보는부품들인데회로도를그린다는것은나의일원을저항 ( 보통 10KΩ을사용한다.) 에연결하고스위치의한쪽접점에연결한후스위치의다이아닌먼나라전문가들만할수있는일로치부해버리기쉽다. 른접점을 GND에연결하는형태로회로를구성하는것을말한다. 풀다운저항은 Vcc에서나온하지만아두이노를이용해무엇인가를제어하기위해시작한공부가아닌가? 전원을스위치의한쪽접점에연결하고스위치의다른점점에저항을연결한후저항에서그래서소개하고싶은소프트웨어가하나있다. 초보자도자신이만들고싶은회로를쉽게설계 GND로연결되게회로를구성하는것을말한다. 일반적으로풀업저항이나풀다운저항은 10K 할수있는소프트웨어, 초보자부터전문가 (?) 까지누구나쉽게사용할수있는전자회로스케 Ω의저항을사용한다. 치프로그램이있어이단원을통해소개하겠다. 국내에서개발되었다면더좋았을텐데라는생각이쏙들어갈정도로사용하는데큰불편없이한글도잘지원된다. 무엇보다무료로사용할수있어너무좋다. 공짜너무좋아하지말자 ~ 2.2.9 브레드보드 (Breadboard) 그이름하여 Fritzing이라는소프트웨어로브레드보드위에그림그리듯이부품을하나씩드래브레드보드 (Breadboard) 는 DIP(Dual In-line Package) 타입의전자부품을보드에꽂아납땜그해가져다놓으면회로도와 PCB까지만들수있다. 을하지않고점퍼선을이용하여부품을연결할수있도록만들어진실험용보드이다. 이프로그램은 http://fritzing.org/download 에서다운로드받을수있다. 브레드보드에부품을꽂으면보드안쪽에연결된금속조각으로인해부품들이연결되어납땜을사용법은다운로드받아설치하고 1시간만가지고놀면회로도하나는그릴수있을만큼쉽다. 하지않고간단한전자회로를구성할수있도록해준다. 브레드보드는전원연결블록 ( 아래그림 1번 ) 과회로연결블록 ( 아래그림 2번 ) 으로구성된다. 그림 2-14 브레드보드의구성 전원연결블록은그림에서검정색선과빨간색선같이가로로연결되어있으며회로연결블록 은파란색선과같이세로로연결되어있다. 가운데회색부분은홈이파져있어 DIP 형태의반 도체칩을쉽게꽂을수있게해준다. - 15 -
3. 아두이노를위한프로그래밍기초 3.1 main() 함수는어디에있나? #include <Arduino.h> 아두이노프로그래밍은 C/C++ 언어를기반으로하고있기때문에아두이노를사용해컨트롤러 int main(void) 장치를만들고제어하기위해서는 C/C++ 언어에대한이해가필요하다. C/C++ 은자바보다먼 { 저세상에나온언어로자바가많은부분 C/C++ 을닮았다고할수있다. // 마이크로컨트롤러초기화 C/C++ 은자바와비슷한문법구조를가지고있어많은부분닮은꼴이지만개념적으로여러가 init(); 지다른부분들도많다. C/C++ 언어를배우기위한목적이아니라아두이노에필요한프로그래 initvariant(); 밍개념을설명하기위한것이므로전체적인문법에대한설명은피하고아두이노에서프로그램을작성하기위해꼭필요한부분만간단히설명하게될것이다. #if defined(usbcon) 아두이노는 C/C++ 을기반으로만들어졌기때문에스케치를컴파일하고실행시키기위해서는 // USB 장치연결설정자바와마찬가지로프로그램의진입점인 main() 함수가반드시필요하다. 하지만우리가앞에서 USBDevice.attach(); 통합개발환경을설치하면서처음접해본 Blink 스케치를보면 main() 함수는존재하지않고덩 #endif 그러니 setup() 함수와 loop() 함수만이존재한다. 아두이노에는 main() 함수가존재하지않는 // 아두이노스케치초기화함수호출것일까? 그렇지는않다. 아두이노에도 main() 함수는존재하지만프로그램초보자를위해코딩 setup(); 을최소화하고직관적인코드구조를만들기위해 main() 함수를따로숨겨놓은것이다. 그럼 main() 함수는어디에있는것일까? main() 함수는아두이노프로그램에서스케치를작성 // 무한반복문할때 ( 정확하게는코드를컴파일할때전처리기에의해 main() 함수가추가된다.) 자동으로추 for (;;) { 가해주기때문에크게신경쓰지않아도되지만그래도궁금한것은못참는성격이라아두이 // 아두이노스케치함수호출 loop() 함수는무한호출된다. 노통합개발환경이설치된폴더를뒤져보니아래와같은위치에 main.cpp이라는파일안에서 loop(); main() 함수를찾을수있었다. // 시리얼수신버퍼에데이터가수신된경우처리 C:\arduino-1.6.6\hardware\arduino\avr\cores\arduino\main.cpp if (serialeventrun) serialeventrun(); 이 main.cpp 파일의내용은코드 3-1과같이구성되어있다. return 0; 코드 3-1을토대로정리하면 setup() 함수는스케치가시작될때딱한번실행되는함수로주 로프로그램실행에필요한초기화코드를작성하면될것이다. 예를들어특정핀의입 / 출력코드 3-1 아두이노의 main() 함수모드를설정하거나스케치에필요한라이브러리를불러오거나또는스케치에서사용되는전역변수를초기화하는데 setup() 함수를이용하면되겠다. 또한 loop() 함수는무한반복되는 for 문안에서호출되므로스케치가시작되면무한히호출되기때문에무한반복함수가된다. 끝으로 init() 함수는마이크로컨트롤러를초기화하는함수이므로이함수와동일한이름의사용자함수를정의할수없다는것에주의를기울여야한다. [ 예제3-1] 디지털입 / 출력핀을이용해외부 LED 점멸시키기아두이노통합개발환경도설치가되었고아두이노에서사용되는전기 / 전자에대한기초지식과먼저그림 3-1을참고해서 Fritzing 프로그램으로회로구성도를작성하고그구성도를바탕으부품도어느정도파악이되었으니이쯤해서아두이노를이용해외부 LED를점멸시키는예제로브레드보드에회로를직접구성한후스케치 3-1을작성해보자. 하나를만들어보고다음으로넘어가자. 스케치작성이완료되면아두이노보드를컴퓨터에연결하고작성한스케치를업로드한후 LED가 1초마다점멸되는지테스트해보자. 참고로이예제에서사용한저항은 220Ω 이다. - 16 -
digitalwrite(ledpin4, LOW); // 1 초대기 delay(1000); 3.2 식별자와데이터타입 우리는앞에서 Fritzing을이용해회로구성도를작성하고그회로구성도에따라브레드보드에전자회로를구성하여아두이두보드와연동하는 LED 점멸테스트를해보았다. 이제아두이노에서프로그램을작성하기위해필요한변수와데이터타입그리고아두이노프로그램을작성하기위해알아야하는몇가지사항에대해알아보자. 그림 3-1 디지털입 / 출력핀을이용해외부 LED 점멸시키기회로구성도 [ 스케치 3-1] 디지털입 / 출력핀을이용해외부 LED 점멸시키기 // 디지털출력으로사용할핀을 4번으로지정 int ledpin4 = 4; void setup() { // 디지털 4번핀을출력모드로설정 pinmode(ledpin4, OUTPUT); void loop() { // 디지털 4번핀에 5V 전원인가 digitalwrite(ledpin4, HIGH); // 1초대기 delay(1000); 3.2.1 식별자 (Identifier) 식별자 (identifier) 란프로그래밍에서사용하는데이터를구분하기위해사용되는이름을의미하며클래스, 함수, 변수등에붙이는이름을말한다. 아두이노프로그램에서식별자는영문자와숫자, 밑줄문자 (_) 를사용해명명할수있으며중간에공백이들어가면안되고식별자의첫문자는영문자와밑줄문자 (_) 만가능하다. 또한 C/C++ 에서이미특정의미가부여되어사용되는예약어 (Reserved Words, 또는키워드라한다.) 는사용할수없으며대문자와소문자를구분하기때문에 num, Num, NUM은모두다른식별자로구분된다. 변수는프로그램수행중에데이터를담아두는상자라할수있는데어떤프로그램이실행되면그프로그램안의변수는컴퓨터의메인메모리에만들어지며이메모리공간의이름이바로변수인것이다. 프로그램에서는변수를통해메모리에접근하여데이터를저장하거나가져올수있다. 변수는하나의값을저장할수있으며프로그램수행중에값이변경될수있기때문에변수라부른다. 또한변수를만들기위해서는그변수에저장될데이터타입을함께기술해야하는데이를변수의선언이라한다. 상수또한데이터가저장되는메모리공간의이름으로변수와마찬가지로상수에저장할데이터타입과함께선언해야하며데이터타입앞에 const라는예약어를사용해상수를선언할수있다. 변수는프로그램중에값이변경될수있지만상수는한번값이지정되면프로그램이실행되는동안그값을변경할수없다. [ 예제 3-2] 변수와상수변수와상수는선언된위치에따라서접근할수있는영역이정해지는데이를스코프라한다. 스케치 3-2는변수와상수를선언하고초기화하는방법과스코프에대한예제이다. // 디지털 4 번핀에 0V 인가 /* 여러줄주석 - 17 -
* 정수를저장할수있는전역변수 i를선언 * 이변수는 int 타입으로선언되었기때문에정수만저장할수있다. * 여기서전역이라함은이스케치내에서어디서든접근가능함을의미한다. int i; /* 실수를저장할수있는전역상수 f를선언 * 상수는그상수에저장할데이터타입과 const 예약어를사용해아래와같이선언한다. * 상수는선언과동시에초기화를해야하며그렇지않으면컴파일에러가발생한다. * 변수나상수에처음값을대입 ( 저장 ) 하는것을초기화라한다. const float f = 3.14; void setup() { // 변수 i에 1을대입 ( 저장 ) - 한줄주석 i = 1; Serial.begin(9600); /* 변수는프로그램실행중에값이바뀔수있으며 * 최종적으로대입된값이그변수의값이된다. i = 10; /* 하나의문자를저장할수있는지역변수 ch를선언하고 A로초기화 * 변수 ch는 setup() 함수안에서선언되었기때문에이함수안에서만접근할수있다. char ch = 'A'; void loop() { Serial.println(" 반지름이 " + String(i) + " 인원의둘레 : " + (i * 2 * f)); /* setup() 함수에선언된변수 ch는지역변수이므로 * 변수의스코프를벗어난곳에서사용하게되면컴파일에러가발생한다. //Serial.println(" 변수 ch의값 : " + ch); while(true); 프로그램에서사용하는데이터의종류는여러가지유형이있다. 또한데이터유형에따라그 데이터를저장하는데필요한메모리공간의크기다르다. 프로그램에서사용되는데이터의종류 를자료형 (Data Type) 또는데이터타입이라부른다. 아두이노프로그램은 C/C++ 기반이기때문에 C/C++ 에서사용하는데이터타입은비슷하나메 모리공간을차지하는크기는약간다르다. 표 3-1은아두이노프로그래밍에서사용되는주요한 데이터타입이다. 데이터형 크기 특 징 boolean 1Byte 논리형 (true/false) char 1Byte 문자형, unsigned char byte 1Byte 부호없는정수형 int 2Byte 정수형, unsigned int word 2Byte 부호없는정수형 long 4Byte 정수형 short 2Byte 정수형 float 4Byte 단정도실수형 double 4Byte 배정도실수형 표 3-1 ATmega 기반프로그램에서사용되는데이터형 [ 예제 3-3] 아두이노에서사용되는데이터타입의크기 표 3-1에서각각의데이터타입이얼마나많은메모리를필요로하는지아래스케치를작성해 확인해보자. [ 스케치 3-3] 데이터타입의크기 void setup() { Serial.begin(9600); void loop() { - 18 -
// sizeof() 연산자는각데이터형이필요로하는크기 ( 바이트수 ) 를반환한다. Serial.println("boolean : " + String(sizeof(boolean))); 표 3-2는 C/C++ 에서많이사용되는주요한연산자를정리한것이다. 이외에더많은연산자를 Serial.println("char : " + String(sizeof(char))); 지원하고있지만이정도만알아도아두이노프로그래밍을하는데불편함은없을것이다. Serial.println("byte : " + String(sizeof(byte))); 이외의연산자가필요하다면그연산자가사용되는예제에서설명할것이다. Serial.println("int : " + String(sizeof(int))); Serial.println("word : " + String(sizeof(word))); [ 예제 3-4] 산술연산자 Serial.println("long : " + String(sizeof(long))); Serial.println("short : " + String(sizeof(short))); // 변수를선언하고초기화 Serial.println("float : " + String(sizeof(float))); int i = 10; Serial.println("double : " + String(sizeof(double))); int j = 3; float f = 10.0; while(true); void setup() { // 시리얼통신초기화 Serial.begin(9600); 3.3 연산자 (Operator) 프로그램에서어떤처리를위해데이터를더하거나빼는작업을하는것을연산이라고한다. 이연산을위해서수학에서사용하는것과비슷한수식을사용하게되는데이때사용되는기호 를연산자라한다. 연산자의종류는매우다양하며연산자에따라서연산우선순위가존재하는 데이는수학에서곱셈이덧셈보다우선적으로적용되는것과같은의미이다. 분류 연산자 설 명 대입 = 우측의데이터를좌측의변수에대입 산술 + - * / % 사칙연산과나머지연산 증감 ++ -- 수의증가, 감소연산 비교 > < ==!= >= <= 좌측과우측의데이터를비교연산 ( 관계연산 ) 논리 &&! 논리적 AND, OR, NOT 연산 조건? 좌측의조건에따라서선택적연산 ( 삼항연산자 ); sizeof sizeof 데이터타입이나변수의크기를바이트단위로반환 형변환 (type) 변수나상수의자료형을지정한 type으로변환 메모리주연산, 포인터 * & [] while(true); 포인터가가리키는메모리주소의데이터를추출 표 3-1 ATmega 기반프로그램에서사용되는데이터형 void loop() { Serial.println("i * j + f = " + String(i * j + f)); /* 아래연산의결과는 3이된다. * 우리는 10을 3으로나누면 3.33... 이라고생각하기쉽지만 * 프로그래밍에서정수와정수의연산결과는정수가되기때문에 3이된다. Serial.println("i / j = " + String(i / j)); /* 아래연산의결과는 1이된다. * % 는 10을 3으로나눠나머지를구하는연산자로 * 정수와정수의연산이므로정수 1이결과가된다. Serial.println("i % j = " + String(i % j)); - 19 -
[ 예제 3-5] 증감연산자와조건연산자 /* 변수를선언하고초기화 */ int i = 10; long l = 100; void setup() { Serial.begin(9600); void loop() { /* 증감연산자는변수의값을 1 증가시키거나 1 감소시키는연산자이다. * 하지만증감연산자의위치에따라서선증감연산자와후증감연산자로나뉜다. * 아래에서증가연산자를변수 l 앞과변수 i 뒤에사용하였다. 이때변수 l의값은 * 변수 i와덧셈하기전에증가되고변수 i의값은변수 l과덧셈한후에증가된다. * 그래서변수 l과변수 i의덧셈결과는 111이된다. Serial.println("++l + i++ = " + String(++l + i++)); 특정블록의코드를여러번반복할수있는 for, while, do-while 문이있다. 참고로제어문에서특정조건을판단하기위해비교연산자와논리연산자가많이사용된다. [ 예제 3-6] 단일조건문과다중조건문 int i = 10; int j = 20; void setup() { Serial.begin(9600); void loop() { // if문은주어진조건이참 (true) 일경우에만실행된다. if(j > i) { Serial.println(String(j) + " 은 " + String(i) + " 보다크다."); /* 조건연산자를삼항연산자라고도부르며? 앞의연산결과가참 (true) 또는 * 거짓 (false) 에따라서반환되는값이다르기때문에조건연산자라한다. *? 앞의연산이참이면 : 앞의값이, 거짓이면 : 뒤의값이반환된다. * 아래는변수 l에저장된값 101이변수 i에저장된값 11 보다크기때문에 * 참이되므로 : 앞에기술된변수 l의값 101이출력된다. Serial.println("l > i = " + String(l > i? l : i)); while(true); 3.4 제어문 프로그램은기본적으로위에서아래로순차적으로실행된다. 이렇게순차적으로만실행해서는다양한요구사항을해결할수가없다. 현실세계의다양한요구사항을프로그램으로구현하려면특정조건에따라서프로그램의실행흐름을바꾸거나특정구간을여러번반복해야하는경우가빈번히발생하게되는데이때사용되는것이바로제어문이다. 제어문에는조건에따라서프로그램의실행흐름을변경할수있는 if문과 switch 문이있으며 /* i가 5보다크고 10보다작거나같은지를비교한다. * 논리곱 (&&) 연산은좌우의피연산자가모두 true일때실행된다. if(i > 5 && i <= 10) { Serial.println(String(i) + " 은 5와 10사이의정수이다."); /* if의조건식이참이아니면 else if의조건을검사하고 * 이또한참이아니면 else 블록의코드가실행된다. if(i > j) { Serial.println(String(i) + " 은 " + String(j) + " 보다크다."); else if(i == j) { Serial.println(String(i) + " 와 " + String(j) + " 는같다."); else { Serial.println(String(j) + " 은 " + String(i) + " 보다크다."); - 20 -
while(true); [ 예제 3-7] switch 문을이용한학점출력하기 Serial.println(" 당신의학점은 " + String(grade) + " 입니다."); while(true); int score = 87; char grade = ' '; void setup() { Serial.begin(9600); void loop() { /* switch 문은조건식결과와일치하는 case의문장이실행되는조건문이다. * switch 문의조건식결과와 case 절은반드시정수또는정수로형변환이가능한 * 데이터야한다. default는조건식의결과와모든 case 절의정수값이일치하지 * 않을때실행된다. 또한 case 절에 break; 문을사용하지않으면첫번째 case 부터 * default까지의문장이순차적으로실행된다. * 모든 switch 문은 if 문으로대체할수있다. switch(score / 10) { case 9: case 10: grade = 'A'; break; case 8: grade = 'B'; break; case 7: grade = 'C'; break; case 6: grade = 'D'; break; default: grade = 'F'; [ 예제 3-8] for 문을이용한 1부터 100까지합구하기 int sum = 0; void setup() { Serial.begin(9600); void loop() { /* for 문은 for( 초기식 ; 조건식 ; 증감식 ) 으로구성되며초기식은 for 문이실행될때 * 단한번변수를초기화하는역할을하며 for문이한번반복될때마다조건식을 * 검사하여참인경우증감식에따라변수의값을증가시킨다. * 아래는 for 문이시작될때변수 i를 1로초기화하고조건식을검사하여참인경우 * 블록안의문장을실행한후변수 i를 1 증가시킨다. 그리고조건식을검사하여 * 참인경우다시블록안의문장을실행한다. 이과정은조건이참인동안반복된다. for(int i = 1; i <= 100; i++) { /* += 는복합대입연산자라고하며좌변의변수에우변의값을더한후다시 * 좌변의변수에대입하는연산자이다. 즉 sum = sum + i를수행하는연산자이다. sum += i; Serial.println("1부터 100까지합 : " + String(sum)); while(true); [ 예제 3-9] while 문을이용해 1부터 100까지짝수의합구하기 int i = 1; - 21 -
int sum = 0; [ 예제 3-10] 배열사용하기 void setup() { // 정수를저장할수있는길이가 3인배열선언 Serial.begin(9600); int kor[3]; // 정수를저장할수있는배열을선언하고초기화 void loop() { int math[] = { 83, 88, 92 ; /* while 문은조건식이참인동안블록안의코드를반복수행한다. * 아래의경우 while 문블록안에서 i의증가시켜지않으면조건을거짓으로 void setup() { * 만들수없으므로무한실행되는무한반복문이된다. Serial.begin(9600); while(i <= 100) { void loop() { // i를 2로나눈나머지가 0이면짝수가된다. // 위에서선언한배열변수 kor의요소에데이터를저장한다. if(i % 2 == 0) { kor[0] = 87; sum += i; kor[1] = 91; kor[2] = 81; i++; /* sizeof 연산자를사용하면배열의길이를알수있다. Serial.println("1부터 100까지짝수의합 : " + String(sum)); * sizeof(kor) 연산자는테이터타입이나변수의크기를바이트단위로 * 반환하기때문에배열전체의크기를배열요소하나의크기로나누면 while(true); * 배열안의요소갯수를알수있다. Serial.println("## 국어점수 ##"); for(int i = 0; i < sizeof(kor) / sizeof(kor[0]); i++) { 3.5 배열 Serial.println(kor[i]); 배열은같은타입의데이터를여러개저장할수있는저장소이다. 앞에서다뤄본정수, 실수등의기본형데이터타입의변수는하나의데이터만저장할수있어한꺼번에여러개의데이터를다루기가불편한반면배열은같은타입의데이터를여러개저장 Serial.println("## 수학점수 ##"); 할수있어한번에여러개데이터를다루기에편리하다. 배열은메모리의연속된주소를할당 for(int i = 0; i < sizeof(math) / sizeof(math[0]); i++) { 받기때문에배열의항목들은번호가지정되어있으며이번호를사용해배열안에데이터를 Serial.println(math[i]); 저장하거나읽어올수있다. 배열각각의항목을요소 ( 또는원소 ) 라고하며이요소에접근하기 위해서배열변수에번호를붙여접근한다. 배열요소에지정된번호를 index라고하며이 index는 0부터시작한다. while(true); - 22 -
프로그램코드에서정수로된메모리주소를기억하고사용하는데불편함이있기때문에상대적 위의데이터형이외에많이사용되는것이문자열일것이다. 으로기억하기쉽고사용하기편리한변수를사용하는것이다. 아두이노프로그램에서는두가지형태로문자열을표현한다. 그중하나는 C/C++ 에서사용하 그렇다면위의예에서변수 x에저장되어있는값 1이실제저장된메모리의주소는어떻게알 는 char 배열을사용해문자열을표현하는방법이다. 이방법을사용해문자열을다룰때는몇수있을까? C/C++ 에서는포인터를사용하면데이터가저장된메모리의주소를알수있다. 가지주의할사항이있는데그첫번째가 char 배열을이용해문자열을다룰때배열선언시 C/C++ 언어에서가장이해하기어려운부분중하나가바로포인터이므로간단히개념만기억 점에서만문자열 ( 문자열리터럴 ) 로초기화할수있고변수가정의된이후에는문자단위로지 하고넘어가도록하자. 아두이노프로그램은 C/C++ 언어기반이기때문에아두이노로프로그래 정하거나전용함수를이용해문자열을지정해야한다는것이다. 밍을하다보면종종포인터가등장한다. 포인터는어떤데이터가저장되어있는위치를가리키 는것으로메모리의주소를가리킨다. 코드 3-2는포인터변수를사용하는간단한예제이다. char str[10]; // 배열을생성하고초기화하지않음 char str1[15]; srt1 = abc ; char str2[] = abc ; char char3[10] = abc ; // 배열생성후문자열로초기화불가능 // 배열크기지정없이초기화가능 // 초기값보다큰배열생성 // 변수 i에 0을저장 int i = 0; char str4[4] = { a, b, c ; strcpy(str, abc ); // null 문자를위해길이가 1큰배열생성 // 전용함수를이용하면배열생성후초기화가능 // 변수 i가가리키고있는주소를포인터변수 p에저장 int *p = &i; 주의사항두번째는 char 배열을이용해문자열을다루는경우문자열의끝에항상널문자 ( \0 ) 를사용해문자열의끝을표시해야한다는것이다. 그래서배열의길이는실제데이터보다최소 1크게지정해생성해야한다. 널문자없이문자열을저장하는것이가능하긴하지만대부분의기존함수들이널문자를체크해문자열의끝을확인하기때문에널문자를사용하지않는다면필요한함수들을직접작성해사용해야한다. 이외에도문자열을다루기위해문자열전용클래스인 String 클래스를제공하고있다. String 클래스는 char 배열과비교해쉽고편리하게다양한문자열을조작할수있지만 char 배열보다많은메모리를필요로한다는단점이있다. 큰따옴표로사용하는문자열리터럴은내부적으로 String 클래스를사용하는것이아니라 char 배열을이용해다뤄진다. 이외에도 char 형과 char 배열변수를초기화할때 cahr 형의변수는작은따옴표를사용하지만 char 배열은큰따옴표를사용해야한다. char ch = A ; // 문자 1Byte 필요 char str[] = A ; // 문자열 2Byte 필요 (null 문자포함 ) void setup() { // 시리얼포트초기화 Serial.begin(9600); void loop() { // int형변수 i에저장된값을출력 Serial.println( i의값 : + String(i)); // 포인터변수에저장된메모리주소를 16진수로출력 Serial.println(int(p), HEX); // 실제값이저장되어있는주소는번지연산자 (&) 를이용해알수있다. Serial.println(int(&p), HEX); 3.1.3 포인터프로그램에서변수는변수가저장되는메모리내의위치와그위치의메모리에저장되는값으로이루어진다. 예를들어 int x = 1; 이선언되어있다고가정하자. 변수 x는정수 1이저장되어있는메모리주소의다른이름으로아두이노에서메모리주소는 2Byte로표현되는정수이다. /* 포인터변수가가리키는메모리주소에저장된실제값을출력 * 포인터변수로부터실제값을얻어오기위해서는 '*' 사용한다. Serial.print((int)*p); - 23 -
while(true){ 코드 3-2 포인터변수의특징코드 3-2에서와같이포인터변수는실제데이터가저장된메모리주소에직접접근할수있는변수라는것은꼭기억하고넘어가자. 코드 3-3은함수의매개변수가일반변수와포인터변수로정의되었을때프로그램에서동작하는차이를비교한예제이다. void setup() { // 시리얼포트초기화 Serial.begin(9600); void loop() { int num = 10; Serial.println(String("num의초기값 : ") + num); function1(num); Serial.println(String("num을인수로함수호출 : ") + num); function2(&num); Serial.println(String("&num을인수로함수호출 : ") + num); while(true); 코드 3-3 함수의매개변수로포인터사용하기 void function1(int x) { /* x는이함수내에서만사용할수있는지역변수로 * 10 이복사되어 x에저장된후 x의값을변경해도 * loop() 함수의지역변수인 num의값은변경되지않는다. x = 100; void function2(int *p) { /* 포인터변수 p에 loop() 함수의지역변수 num이 * 가리키고있는주소값이복사되어저장되고 * p가가리키고있는메모리주소에 1000을저장하게되면 * loop() 함수의지역변수 num도같은주소를가리키기 * 때문에변수 num의값이변경되어출력되는것이다. *p = 1000; - 24 -
4. 기본클래스와함수 아두이노는수학함수나삼각함수를비롯한마이크로컨트롤러를제어하기위한다양한함수를지원하고있다. 아두이노에서기본적으로제공하는함수들은아두이노통합개발환경이설치된폴더 C:\arduino-1.6.6\hardware\arduino\avr\cores\arduino 에저장되어있다. 이폴더에가보면 Arduino.h, HardwareSerial.h 등과같은여러가지헤더파일과소스파일이저장되어있는것을볼수있을것이다. 여기에저장된기본함수에는디지털 / 아날로그입 / 출력함수, 시간관련함수, 수학함수, 삼각함수, 비트와바이트조작함수그리고인터럽트관련함수등이있다. 이중에서아두이노실습에가장필요한디지털, 아날로그입 / 출력함수와기본클래스에대해서만간단히알아보도록하자. 4.1 Serial 클래스 아두이노의라이브러리는대부분클래스로지원되며이외에시리얼통신과문자열처리를위해 Serial 클래스와 String 클래스를지원하고있다. 이두클래스는기본클래스로 ( 자바에서 java.lang 패키지와비슷하다.) 별도의 #include 구문없이스케치코드에서바로사용할수있다. String 클래스에는 length(), indexof(), equals() 함수등과같이자바에서사용하는 String 클래스의메소드와같은기능을제공하는같은이름의함수들이대부분이므로따로언급하지않고 Serial 클래스에서제공하는함수를간단히살펴보고자한다. Serial 클래스는아두이노보드에서컴퓨터나여러주변장치와시리얼통신을위해제공되는클래스이다. 방식으로 ( 일반적으로 UART 방식또는 UART 통신으로많이불려진다.) RS-232C 프로토콜에정의된내용중에서데이터송수신을위한세개의핀만으로통신을하는방식이다. 앞에서언급한세개의핀은 RXD(Receive Data), TXD(Transmit Data), GND(Ground) 핀을말하며일반적으로 RXD를 RX로 TXD를 TX로통용하고있다. UART 시리얼통신을위해아두이노보드와컴퓨터를서로연결할때주의할점은송신과수신선이그림 4-1과같이서로교차하게연결해야한다는것이다. Arduino Uno에는디지털 0번핀이 RX, 디지털 1번핀이 TX 역할을수행하는핀이다. 또한컴퓨터와 USB 연결을통해서도시리얼통신을사용할수있다. 시리얼통신을사용하는경우 0번핀과 1번핀은디지털입 / 출력핀으로사용할수없다. 스케치를아두이노보드에업로드하는경우에도시리얼통신으로이루어지며컴퓨터의가상시리얼포트와아두이노보드의 Serial을통해통신이이루어진다. UART 시리얼통신에서전송속도는보율 (Baud Rate) 을사용한다. 보율은변조속도를의미하는단위로통신회선을통해 1초동안전달되는데이터비트수를나타내는단위로모뎀이나데이터전송속도를표시하기위해사용되었다. 모뎀이나데이터전송속도를나타내는경우보율은 BPS(Bit per second) 와동일하다. 아두이노는 4개의시리얼포트를가지고있으며 Serial 클래스는이시리얼포트를이용한통신을구현한클래스로실제클래스이름은 Serial_ 이다. Serial_ 클래스의객체로 Serial이 USBAPI.h에정의되어있어프로그램에서는전역객체로 Serial을사용할수있다. Serial 클래스는 Stream 클래스를상속받아정의된클래스로 Stream 클래스는아두이노에서직접사용되는경우는거의없으며 Serial, Wire, EthernetClient, EthernetServer, SD 등의문자열이나이진수열을사용하는여러클래스들이베이스클래스로사용하고있다. 4.1.1 begin void begin(unsigned long baud) void begin(unsigned long baud, byte config) baud : 전송속도를보율로지정한다. config : 데이터비트의수를지정한다. 패리티비티와정지비티를설정할수있다. 시리얼통신을위한전송속도와필요한옵션을설정하는함수로컴퓨터와통신하기위해서는일반적으로보율을설정하는데여러가지보율중에서 Arduino Uno는 9600 보율을많이사용한다. 4.1.2 available 그림 4-1 컴퓨터와아이두노보드의시리얼통신연결 int available(void) 시리얼포트로수신되어버퍼에저장된데이터의바이트수를반환하는함수이다. 시리얼포트로수신된데이터는 64Byte까지수신버퍼에저장된다. 시리얼통신은 USART(Universal Synchoronous Asynchoronous Receiver Transmitter) - 25 -
4.1.3 print, println size_t print(value, format) size_t println(value, format) value : 출력값으로 char, char[], String, 정수, 실수등을지정할수있다. format : 출력형식을지정 (BIN, OCT, DEC, HEX 또는소수점자리수지정 ) 출력값 value를 ASCII 형식으로시리얼포트로출력하는함수로시리얼포트로출력된바이트수를리턴한다. Serial.begin(9600); // 버퍼의크기를최대 200 문자까지저장하도록지정 inputstr.reserve(200); void loop() { 4.1.4 read int read(void) 시리얼통신수신버퍼에서첫번째문자를읽어반환한다. 수신버퍼가비어있으면 1일리턴한다. read() 함수는수신버퍼에서읽은문자를제거한다. 4.1.5 write size_t write(uint8_t ch) size_t write(const char *str) size_t write(const uint8_t *buffer, size_t size) 이진데이터를시리얼포트로출력하고출력된바이트수를반환한다. 이진형식으로출력하기때문에숫자를출력하려면 print() 나 println() 함수를사용해출력해야한다. 문자열의경우는 print() 함수와동일하게출력된다. // 시리얼포트로수신된데이터읽기가완료되었으면 if(readcomplete) { // 읽어온데이터를시리얼포트로출력한다. Serial.println(inputStr); // 버퍼를초기화한다. inputstr = ""; // 수신데이터읽기상태초기화 readcomplete = false; [ 예제4-1] 시리얼포트로수신한데이터 Echo Back 하기이예제는시리얼포트로수신된데이터를읽어시리얼통신을통해재전송하는예제로스케치를작성하여실행한후시리얼모니터를띄워데이터를입력하여 Send 버튼을을클릭하면아두이노에서데이터를수신해받은데이터를재전송해시리얼모니터에출력된다. 이실습은시리얼모니터의라인옵션리스트박스에서 Newline 을선택해야제대로동작한다. // 수신데이터를저장할버퍼초기화 String inputstr = ""; // 시리얼포트로수신된데이터읽기완료상태변수 boolean readcomplete = false; void setup() { // 시리얼통신포트초기화 /* 이함수는수신버퍼에데이터가수신된경우호출되는함수이다. * 자동으로추가되는 main() 함수안에서 loop() 함수다음에호출된다. * serialeventrun() 함수에서시리얼통신수신버퍼를검사한후 * 데이터가수신된경우이함수를호출하도록되어있다. void serialevent() { /* 시리얼포트로들어온모든데이터를읽는다. * available() 함수는시리얼포트로수신되어버퍼에 * 저장된데이터의바이트수를반환한다. while(serial.available()) { /* read() 함수는시리얼통신수신버퍼의첫번째문자를읽어반환한다. - 26 -
* 데이터가존재하지않으면 -1이리턴되므로반복문을빠져나간다. char input = (char) Serial.read(); inputstr += input; [ 스케치 4-2] 시리얼통신을이용해 LED 제어하기 // LED 를제어할디지털 7 번핀설정 int ledpin7 = 7; // 수신된데이터를끝까지읽었으면수신데이터읽기완료상태설정 if(input == '\n') { readcomplete = true; // 시리얼포트에수신된데이터를저장할버퍼초기화 String inputstr = ""; // LED 상태를저장할변수초기화 boolean isledon = false; void setup() { [ 예제 4-2] 시리얼통신을이용해 LED 제어하기이번예제는컴퓨터와시리얼통신을이용해컴퓨터로부터 on 이수신되었으면 LED를켜고 off 가수신되었으면 LED를끄는예제를만들어보자. 스케치 4-2을작성하고그림 4-2를참고해회로를구성한후스케치를실행하고시리얼모니터를열어 on 또는 off 를아두이노로전송하여 LED가제대로켜지고꺼지는지테스트해보자. // 시리얼통신포트초기화 Serial.begin(9600); // 디지털 7번핀을출력모드로설정 pinmode(ledpin7, OUTPUT); void loop() { // LED 상태가 "ON" 이면 if(isledon) { digitalwrite(ledpin7, HIGH); // LED 상태가 "OFF" 이면 else { digitalwrite(ledpin7, LOW); 그림 4-2 시리얼통신을이용해 LED 제어하기회로구성도 /* 이함수는수신버퍼에데이터가수신된경우호출되는함수이다. * 자동으로추가되는 main() 함수안에서 loop() 함수다음에호출된다. * serialeventrun() 함수에서시리얼통신수신버퍼를검사한후 * 데이터가수신된경우이함수를호출하도록되어있다. - 27 -
void serialevent() { else { /* 시리얼포트로들어온모든데이터를읽는다. * available() 함수는시리얼포트로수신되어버퍼에 * 저장된데이터의바이트수를반환한다. while(serial.available()) { // 종료문자를만날때까지버퍼에추가한다. inputstr += input; /* read() 함수는시리얼통신수신버퍼의첫번째문자를읽어반환한다. * 데이터가존재하지않으면 -1이리턴되므로반복문을빠져나간다. char input = (char) Serial.read(); // 문자열종료를검사하여수신데이터의끝이면 if(input == '\n' input == '\r') { // 수신된데이터가 "on" 이면 if(inputstr.equals("on")) { /* LED 상태를 "ON" 으로설정하고시리얼모니터에 * LED 상태를출력한후버퍼를초기화한다. isledon = true; Serial.println("LED ON"); inputstr = ""; [ 예제 4-3] 시리얼통신으로 Handshaking( 주고받음 ) 하기아두이노보드와컴퓨터사이에시리얼연결이성립되면처음송수신되는데이터는주변회로의잡음등의영향으로잘못된데이터가전달될수있다. 그래서초기연결시에서로약속한데이터를주고받음으로써초기잡음등에의한잘못된데이터의전달로인해오동작하는것을미연에방지할수있다. 스케치 4-3은 Handshaking을통해시리얼통신을연결하여 LED를제어하는예제이다. 그림 4-3을참고해회로를구성하고스케치를실행한후시리얼모니터를열어아두이노보드에서보낸 이메시지가보이면 OK를전송해주세요 라는메시지를확인한후아두이노로 OK 메시지를보낸다. 그리고 LED의밝기를 0 ~ 255사이의숫자로입력해주세요 라는메시지가도착하면 LED 밝기를숫자로입력하여아두이노로메시지를보내면입력한수치에따라밝기가다르게 LED가켜지는것을확인할수있을것이다. 이실습은시리얼모니터의라인옵션리스트박스에서 No line ending 을선택해야제대로동작한다. // 수신된데이터가 "off" 이면 else if(inputstr.equals("off")) { /* LED 상태를 "OFF" 로설정하고시리얼모니터에 * LED 상태를출력한후버퍼를초기화한다. isledon = false; Serial.println("LED OFF"); inputstr = ""; 그림 4-3 Handshaking( 주고받음 ) 을통해시리얼통신회로구성도 - 28 -
[ 스케치 4-3] 시리얼통신으로 Handshaking( 주고받음 ) 하기 analogwrite(ledpin5, brightness); /* 아날로그출력을위해 PWM(Pulse Width Modulation, 펄스폭변조 ) 를 * 지원하는디지털 5번핀을지정하였다. int ledpin5 = 5; void setup() { // 현재 LED의밝기를컴퓨터로전송한다. Serial.println(" 현재 LED의밝기 : " + String(brightness, DEC)); // 컴퓨터에서받은숫자의밝기로 LED를켜고 2초동안유지시킨다. delay(2000); // 시리얼통신포트초기화 Serial.begin(9600); pinmode(ledpin5, OUTPUT); serialconnectionok(); void loop() { void serialconnectionok() { // 시리얼모니터로수신된데이터를저장하기위한버퍼 char buffer[100] = ""; // 컴퓨터로메시지전송 Serial.println(" 이메시지가보이면 OK를전송해주세요 "); /* int parseint(void) 함수는시리얼통신수신버퍼에서첫번째 * 유효한정수를반환하는함수로현재수신버퍼가비어있거나 * 정수가발견되지않으면 0을반환하는함수이다. int brightness = Serial.parseInt(); // Handshaking가성립될때까지반복 while(true) { // 수신된데이터가존재하면 if(serial.available()) { /* brightness의값을 0 ~ 255의값으로제한한다. * constrain(value, minvalue, maxvalue) 함수는아두이노에서지원하는 * 수학함수로지정한 value를 minvalue에서 maxvalue 범위의값으로 * 제한하는함수이다. 반환값은지정한 value가범위내의값이면 * value를반환하고범위밖의값이면 minvalue나 maxvalue를반환한다. brightness = constrain(brightness, 0, 255); /* 디지털 5번핀은 PWM(Pulse Width Modulation) 을지원하는핀으로 * Arduino Uno 보드에는아날로그입력핀은 6개나존재하지만 * 아날로그출력핀은존재하지않는다. PWM을지원하는디지털핀 * 3, 5, 6, 9, 10, 11번을이용해아날로그출력을대신할수있다. /* size_t readbytes(char *buffer, size_t length) 함수는시리얼통신 * 수신버퍼에서문자를읽어지정한버퍼에저장하는함수로 length에 * 지정한바이트수의문자를읽었거나시간초과가발생하면종료되며 * 입력받은문자의수를반환하는함수이다. int readcount = Serial.readBytes(buffer, 99); // 버퍼의맨마지막에종료문자를추가한다. buffer[readcount] = '\0'; // 수신된문자를컴퓨터로전송한다. Serial.println(" 수신한문자 : " + String(buffer)); - 29 -
// "OK" 문자열이수신될때까지대기한다. if(string(buffer).equals("ok")) { Serial.println("LED 의밝기를 0 ~ 255 사이의숫자로입력해주세요 "); // "OK" 문자열이수신되었으면반복문을빠져나간다. break; [ 예제 4-4] 시리얼통신을이용해 RGB LED 밝기제어하기이번예제는시리얼모니터에서값을입력받아 RGB LED의색상을바꾸는예제로 RGB LED 는공통양극 (Common Anode) 방식과공통음극 (Common Cathode) 방식이있다. 공통양극방식은공통단자에 Vcc를연결하고나머지 R, G, B 단자를 GND에연결하면 Red, Green, Blue 색상의불빛이켜지는방식이며공통음식방식은공통단자에 GND를연결하고 R, G, B 단자를 Vcc에연결하면 Red, Green, Blue 색상의불빛이켜지는방식이다. RGB LED는 R, G, B 단자와공통단자 4개의다리로구성되어있으며다리가가장긴단자가공통단자가된다. 같은방식이라하더라도 RGB에해당하는단자의위치가다를수있으므로데이터시트를확인해 RGB 단자를확인하고회로를구성할수있도록하자. 우리가이번실습에사용할 RGB LED는공통양극방식의 LED로다리가가장긴단자가왼쪽부터 2번째에위치하게놓은상태에서왼쪽부터 Red 단자, 공통양극단자, Green 단자, Blue 단자로연결하면된다. 그림 4-4와같이 PWM(Pulse Width Modulation) 을지원하는디지털핀인 3, 6, 9번핀에각각 R, G, B 단자를연결하고공통양극단자에는 5V를연결하여회로를구성해보자. 이때각 R, G, B 단자에는 220Ω의저항을각각연결해야한다. 공통양극 RGB LED는각단자를 GND에연결하므로각단자에 0을출력하면최대밝기가되고 255를출력하면최소밝기가된다. 공통음극 RGB LED는이와반대로동작한다. 스케치 4-4를작성하여아두이노보드에업로드하고시리얼모니터를띄워공백으로구분하거나콤마로구분하여 R, G, B에해당하는숫자를입력하면 RGB LED가입력된숫자에맞춰색상이바뀌면서켜지는것을확인할수있을것이다. 이실습은시리얼모니터의라인옵션리스트박스에서 No line ending 을선택해야제대로동작한다. 그림 4-4 시리얼통신을이용해 RGB LED 밝기제어하기회로구성도 [ 스케치 4-4] 시리얼통신을이용해 RGB LED 밝기제어하기 int redpin3 = 3; int greenpin6 = 6; int bluepin9 = 9; void setup() { // 시리얼포트초기화 Serial.begin(9600); // R, G, B에연결되는핀을출력모드로지정한다. pinmode(redpin3, OUTPUT); pinmode(greenpin6, OUTPUT); pinmode(bluepin9, OUTPUT); /* 스케치가시작되면 RGB LED는꺼져있는상태로시작한다. * 공통양극 RGB LED는각단자를 GND에연결하므로 0을출력하면 * 최대밝기가되고 255를출력하면최소밝기가된다. - 30 -
digitalwrite(redpin3, 255); digitalwrite(greenpin6, 255); digitalwrite(bluepin9, 255); void loop() { Serial.print("RED : " + String(255 - red, DEC)); Serial.print(", GREEN : " + String(255 - green, DEC)); Serial.println(", BLUE : " + String(255 - blue, DEC)); while(serial.available()) { /* int parseint(void) 함수는시리얼통신수신버퍼에서첫번째 * 유효한정수를반환하는함수로현재수신버퍼가비어있거나 * 정수가발견되지않으면 0을반환하는함수이다. * 반환된정수는수신버퍼에서삭제된다. int red = Serial.parseInt(); // 첫번째유효한정수읽기 int green = Serial.parseInt(); // 두번째유효한정수읽기 int blue = Serial.parseInt(); // 세번째유효한정수읽기 if(serial.read() == '\n') { /* 공통양극 RGB LED는각단자에 0을출력하면최대밝기가되고 255를 * 출력하면최소밝기가되므로시리얼통신으로입력된값을반전시켰다. * constrain() 함수를사용해입력된값은 0 ~ 255로제한하였다. red = 255 - constrain(red, 0, 255); green = 255 - constrain(green, 0, 255); blue = 255 - constrain(blue, 0, 255); // 시리얼통신으로수신된데이터를 PWM로출력하여밝기를조절한다. analogwrite(redpin3, red); analogwrite(greenpin6, green); analogwrite(bluepin9, blue); /* 시리얼통신으로입력받은값을그대로시리얼모니터에출력한다. * 입력된숫자가반전되어적용되었으므로다시반전하여출력한다. 4.2 디지털입 / 출력함수 4.2.1 pinmode 함수 void pinmode(uint8_t pin, uint8_t mode) pin : 입 / 출력모드를설정할핀번호, mode : INPUT, OUTPUT, INPUT_PULLUP pin으로지정한핀이입력또는출력으로동작하도록설정하는함수로디지털핀 0번 ~ 13번핀 14개를지정할수있다. 또한아날로그핀 6개도디지털입력으로사용할수있는데핀번호를지정할때는 A0 ~ A5 또는 14번 ~ 19번으로지정할수있다. mode를 INPUT_PULLUP으로설정한경우 Arduino Uno 보드에장착된풀업저항을사용하도록설정되며 mode가 INPUT인경우풀업저항이사용되지않는다. 이두이노핀의기본값은입력 (INPUT) 상태로설정된다. 그래서입력으로사용하기위해서는 pinmode() 함수를사용하지않아도입력으로사용할수있다. 입력상태로설정된핀은하이임피던스 (High Impedance State) 에있다고말한다. 하이임피던스상태란단어가의미하듯아주큰저항이연결된상태로아주적은전류가흐르는상태를말하는데하이임피턴스상태에있는핀은 1이나 0의상태가아닌플로팅 (Floating) 상태가되어외부의잡음이나입력핀주변의상태에따라신뢰할수없는값 ( 명확히 5V 또는 0V가아닌제 3의값 ) 이될수있다. 그래서하이임피던스상태를방지하기위해 Vcc로연결된저항 ( 이런저항을풀업저항이라고한다.) 이나 GND로연결된저항 ( 이런저항을풀다운저항이라고한다.) 을사용하여회로를구성하면 5V 또는 0V 입력을보장받을수있다. 풀업저항이나풀다운저항은주로 10KΩ의저항을많이사용한다. 그림 4-5는풀업저항을구성한회로도로스위치가눌려지지않으면 Vcc의전원이디지털 7번핀에연결되므로 5V의입력이가해져논리 1의입력이보장되고스위치가눌려지면 GND로연결되어 0V의입력이가해져논리 0의입력이보장된다. 그림 4-6은풀다운저항을구성한회로도로스위치가눌려지지않으면 GND가디지털 7번핀에연결되므로 0V의입력이가해져논리 0의입력이보장되고스위치가눌려지면 Vcc가연결되어 5V의입력이가해져논리 1의입력이보장된다. 풀업저항은우리가일상적으로사용하는스위치의반대개념으로동작하기때문에스케치코드에서적절한코드로대응해프로그램을작성할필요가있다. - 31 -
4.2.2 digitalwrite 함수 void digitalwrite(uint8_t pin, uint8_t value) pin : 디지털출력으로사용할핀번호, value : HIGH, LOW pin으로지정된핀에 value에지정한 HIGH 도는 LOW 값을출력하는함수이다. pinmode 함수에서 OUTPUT을지정된경우 HIGH는 5V, LOW는 0V가출력된다. 또한 INPUT 으로지정된경우 digitalwrite() 함수로 HIGH 값을출력하면 Arduino Uno 보드에장착된내부풀업저항 20KΩ이연결되며 LOW를출력하면풀업저항연결이해제된다. 한가지주의사항은디지털 13번핀을입력으로사용할경우 Arduino Uno 보드에장착된 LED를보호하기위해저항이 13번핀에연결되어있으므로 13번핀에내부풀업저항 20KΩ 을사용하도록설정하면 LED 보호를위한저항도같이사용되어이핀으로입력되는 5V에서도전압이 1.7V로낮아져항상 LOW 상태가된다. 그래서 13번핀을입력으로사용할때는내부풀업저항을사용하지않고외부풀업저항을사용한다. 그림 4-5 풀업저항을구성한회로도 4.2.3 digitalread 함수 int digitalread(uint8_t pin) pin : 디지털입력으로사용할핀번호 pin으로지정된디지털핀으로부터입력되는 HIGH 또는 LOW 값을읽어서반환한다. HIGH는 5V, LOW는 0V로동작하지만실제로는 pin에공급되는전압이 1/2에해당하는 2.5V 보다높으면 HIGH로동작하고낮으면 LOW로동작한다. [ 예제 4-5] 스위치로내부 LED 제어하기 풀다운저항스위치는 ON 과 OFF 상태두가지상태를가지므로논리 1과논리 0을표현하기위한대표적인부품중하나이다. 이번예제는이스위치와풀다운회로를구성하여디지털입 / 출력함수를이용해아두이노보드 13번핀에연결된내부 LED를스위치로제어하는예제를만들어보자. 먼저그림 4-6과같이풀다운저항을이용해회로를구성한후스케치 4-5과같이스케치를작성해아두이노보드에업로드하고스위치를눌렀다떼었다해가며테스트해보자. 이예제에사용된풀다운저항은위에서언급한것처럼 10KΩ을사용하였다. [ 스케치 4-5] 스위치로내부 LED 제어하기 풀다운저항 // 디지털출력으로사용할핀을 13 번으로지정 int ledpin13 = 13; 그림 4-6 풀다운저항을구성한회로도 // 디지털입력으로사용할핀을 7 번으로지정 - 32 -
int ledpin7 = 7; // 디지털 7 번핀의입력을저장할변수 int inputval = 0; void setup() { // 디지털 13 번핀을출력모드로지정 pinmode(ledpin13, OUTPUT); // 디지털 7 번핀을입력모드로지정 pinmode(ledpin7, INPUT); void loop() { 그림 4-7 스위치로내부 LED 제어하기회로구성도 /* 디지털 7번핀의입력을읽어디지털 13번핀을제어한다. * 스위치를누르면풀다운저항에의해 7번핀에 * 5V가인가되고버튼을놓으면 0V가인가된다. inputval = digitalread(ledpin7); digitalwrite(ledpin13, inputval); [ 연습문제 4-1] 버튼을이용해 LED 상태제어하기예제 4-5에서는버튼을누르고있는동안만 LED가를켜고버튼을떼면 LED가꺼지게된다. 이동작은우리가일상생활에서사용하는버튼과는차이가있어좀어색한감이있다. 그래서버튼을한번눌렀다떼어도 LED가계속해서켜져있고다시한번눌렀다떼면 LED가꺼지는동작을할수있도록스케치를수정해보자. // 버튼입력을위해약간의대기상태를만든다. delay(100); 4.3 아날로그입 / 출력함수 4.3.1 analogreference void analogreference(uint8_t type) 이함수는아날로그입력을위한기준전압을설정하는기능을제공한다. 아래는 type에지정할수있는상수로 Arduino Uno에지정할수있는상수만나열하였다. DEFAULT : 아두이노보드의동작전압인 5V로설정한다. INTERNAL : 내부기준전압으로설정한다. Arduino Uno인경우 1.1V로설정한다. EXTERNAL : AREF 핀에인가된 0V ~ 5V 사이의전압을기준전압으로설정한다. 주의할사항은기준전압을변경한후 analogread() 함수를이용해읽으면최초몇번의아날로그전압은부정확할수있다. 또한 AREF 핀에외부기준전압을사용하는경우 0V 미만이나 5V를초과해서전압을가하면안된다. AREF 핀에인가되는전압을기준전압으로할경우반드시 analogread 함수를호출하기이전에기준전압을 INTERNAL로설정해야한다. 그렇지 - 33 -
않으면 AREF 핀에인가된전압과외부전압이동시에아두이노보드에인가되어아두이노보드가손상될수있다는것을꼭기억하자. 4.3.2 analogread int analogread(uint8_t pin) pin : 아날로그입력으로사용할핀번호 pin에지정한아날로그입력핀으로부터아날로그값을읽어 ADC를통해디지털값으로변환해반환한다. Arduino Uno에는 A0 ~ A5까지 6개의아날로그입력핀이있다. 각핀에는 10비트 (2 10-1) 아날로그-디지털컨버터 (ADC) 가연결되어있어 6개의아날로그입력핀에입력되는전압을 0 ~ 1023 사이의디지털값으로변환하여읽을수있다. 아날로그입력핀에외부회로가연결되어있지않은경우 analogread() 함수의반환값은다른입력핀에인가된전압이나정전기등에의해의미없는무작위값이반환되므로난수생성함수의초기화방법으로도사용된다. * analogread() 함수는아날로그값을읽어 ADC를통해 * 0 ~ 1023 사이의정수를디지털값으로변환하여반환한다. inputval = analogread(analogpina2); // 시리얼모니터에읽어온가변저항의값을출력한다. Serial.println(inputVal); [ 예제 4-6] 아날로그입력핀으로포텐셔미터 ( 가변저항 ) 의값읽기스케치 4-6은가변저항인포텐셔미터의가변저항값을아날로그 A2 핀으로입력받아시리얼모니터에출력하는스케치이다. 그림 4-8과같이회로를구성하고가변저항값이제대로출력되는지시리얼모니터로확인해보자. [ 스케치 4-6] 아날로그입력핀으로포텐셔미터 ( 가변저항 ) 의값읽기 // 가변저항의값을읽을아날로그핀정의 int analogpina2 = A2; // 가변저항의값을저장할변수초기화 int inputval = 0; 그림 4-8 아날로그입력핀으로포텐셔미터 ( 가변저항 ) 값읽기회로구성도 void setup() { // 시리얼통신포트초기화 Serial.begin(9600); void loop() { /* 아날로그핀으로입력되는가변저항의값을읽는다. 4.3.3 analogwrite void analogwrite(uint8_t pin, int value) pin : 아날로그출력으로사용할핀번호 value : 듀티사이클 (Duty Cycle) - 0( 항상 Off 상태 ) ~ 255( 항상 On 상태 ) 사이의정수아두이노에는아날로그입력핀은 6개나존재하지만아날로그전용출력핀은단한개도없다. 아두이노에서아날로그출력을사용하기위해서는 PWM(Pulse Width Modulation) 을지원하는디지털 3, 5, 6, 9, 10, 11번핀을이용해야한다. analogwrite() 함수에의해출력되는신호는아날로그신호가아니라펄스폭이변조된 (PWM) 디지털신호로이함수의두번째인수로전달하는 0(0%) ~ 255(100%) 사이의값은디지털신 - 34 -
호한주기내에서 HIGH의값을가지는신호의비율인듀티사이클 (Duty Cycle) 을지정하는값이다. analogread() 함수와는달리 analogwrite() 함수를사용하는 PWM을지원하는핀은디지털핀으로 pinmode() 함수를통해해당핀을출력모드로지정해야한다. analogwrite() 함수를사용하는핀은이함수가호출되면다른 analogwrite(), digitalread(), digitalwrite() 함수가호출되기전까지지정한듀티사이클을가지는신호가지속적으로출력된다. PWM 신호를이용하면 LED의밝기를변화시키거나모터의속도를제어할수있다. 그림 4-9는펄스폭변조에따른듀티사이클을그림으로나타낸것이다. int analogpina0 = A0; // 가변저항의값을읽어와저장할변수초기화 int inputval = 0; void setup() { // 디지털 5번핀을출력모드로지정 pinmode(ledpin5, OUTPUT); analogwrite(0) - 듀티사이클 0% analogwrite(63) - 듀티사이클 25% // 시리얼통신포트초기화 Serial.begin(9600); void loop() { analogwrite(127) - 듀티사이클 50% analogwrite(255) - 듀티사이클 100% 그림 4-9 펄스폭변조에따른듀티사이클 [ 예제 4-7] 아날로그입력과 PWM 출력을이용한 LED 제어스케치 4-7은가변저항인포텐셔미터의가변저항값을아날로그 A0 핀으로입력받아 PWM (Pulse Width Modulation) 을지원하는디지털 5번핀과 analogwrite() 함수를이용해 LED의밝기를조절하는스케치이다. 그림 4-10과같이회로를구성하고테스트해보자. 포텐셔미터의손잡이를좌 / 우로회전시키면 LED의밝기가밝아졌다어두워졌다할것이다. [ 스케치 4-7] 아날로그입력과 PWM 출력을이용한 LED 제어 /* 아날로그 A0 핀으로입력되는가변저항의값을읽는다. * analogread() 함수는아날로그값을읽어 ADC를통해 * 0 ~ 1023 사이의정수를디지털값으로변환하여반환한다. inputval = analogread(analogpina0); /* PWM 기능을제공하는디지털 5번핀을이용해읽어온 * 가변저항의값을 4로나누어아날로그값으로출력한다. * ADC에서반환되는값이 0 ~ 1023이므로필요한 0 ~ 255까지의 * 정수를얻기위해 4로나누어지정하였다. analogwrite(ledpin5, inputval / 4); Serial.println(inputVal / 4); // 아날로그출력을위해 PWM 기능을제공하는 5 번핀지정 int ledpin5 = 5; // 가변저항의입력값을입력받을아날로그핀 A0 지정 - 35 -
#define NOTE_B 494 // 시 int speakerpin5 = 5; // 학교종멜로디 - 0은쉽표 int melody[] = { NOTE_G, NOTE_G, NOTE_A, NOTE_A, NOTE_G, NOTE_G, NOTE_E, 0, NOTE_G, NOTE_G, NOTE_E, NOTE_E, NOTE_D, 0, NOTE_G, NOTE_G, NOTE_A, NOTE_A, NOTE_G, NOTE_G, NOTE_E, 0, NOTE_G, NOTE_E, NOTE_D, NOTE_E, NOTE_C, 0 ; // 모든음표를 4 분음표로설정 int noteduration = 4; [ 그림 4-10] 아날로그입력과 PWM 출력을이용한 LED 제어회로구성도 [ 예제 4-8] 디지털출력과부저 (buzzer) 를이용한멜로디재생디지털신호출력을이용해부저나스피커로멜로디를재생할수있다. 음을출력하기위해서는 tone() 함수를사용해야한다. tone() 함수를사용해음을출력하기위해서특정음의주파수를미리알고있어야하며이음의주파수는스케치시작부분에정의하였다. 스케치 4-8은디지털출력과 tone() 함수를사용해학교종멜로디를재생하는예제이다. 이예제에서사용한부저 (buzzer) 는다리가두개로다리가긴쪽의옆면을보면극성을표시하는 + 문자가있으므로다리가긴쪽을디지털 5번핀과연결하면되고부저에연결된저항은 100Ω을사용하였다. void setup() { void loop() { /* sizeof 연산자는데이터타입의바이트수를구하는연산자이다. * melody는 int형배열로아두이노에서 int 형은 2Byte 이므로 * sizeof(melody) = 28개 x 2Byte = 56, sizeof(int) = 2 * sizeof(melody) / sizeof(int) = 28로 melody 배열의길이를구하는식이다. for(int i = 0; i < sizeof(melody) / sizeof(int); i++) { [ 스케치 4-8] 디지털출력과부저 (buzzer) 를이용한멜로디재생 // 음표의길이를밀리초로변환 int notelength = 1000 / noteduration; // 음의주파수 - 음표정의 #define NOTE_C 262 // 도 #define NOTE_D 294 // 레 #define NOTE_E 330 // 미 #define NOTE_F 349 // 파 #define NOTE_G 392 // 솔 #define NOTE_A 440 // 라 - 36 - /* 디지털 7번핀으로멜로디를재생한다. * tone(uint8_t pin, unsigned int frequency, unsigned long duration) 함수는 * 50% 듀티사이클과지정된주파수를가지는구형파 (Square Wave) 를출력하며 * 피에조부저나스피커를연결해단음을재생하기위해사용한다. tone(speakerpin5, melody[i], notelength);
/* 음표와음표사이의시간간격을설정한다. * 음표길이의 50% 를더해서출력하게설정하였다. int pause = notelength * 1.5; delay(pause); /* tone() 함수에의해실행되는재생을중지한다. * notone(unit8_t pin) 함수는 tone() 함수에의해출력되는구형파출력을멈춘다. //notone(speakerpin7); [ 연습문제 4-2] 버튼을이용한모형신호등만들기이제디지털입 / 출력과아날로그입출력을제어하는방법을알았으니그림 4-12와같이회로를구성하고빨간색, 노란색, 초록색 LED를사용해신호등을만들어보자. 이신호등은버튼을사용해색상을바꾸는수동신호등으로버튼이한번눌려질때마다빨간색, 노란색, 초록색 LED가켜지고나머지두가지색상의 LED는꺼지도록스케치를구현해보자. 또한시리얼모니터를통해그림 4-13과같이현재눌린버튼상태와신호등색상을출력하는기능도추가해보자. 이번연습문제는그림 4-12와같이디지털 3번핀에외부풀다운 (Pull-down) 저항을연결해버튼이눌려지면 5V의전압이디지털 3번핀에가해지고이 3번핀의입력을읽어디지털 5, 7, 9번에연결된초록색, 노란색, 빨간색 LED를버튼상태에따라하나의 LED만켜고나머지두가지색상의 LED는꺼지도록스케치를작성해야한다. 외부풀다운저항으로 10KΩ을사용하고각색상별 LED에는 220Ω 저항을사용하여회로를구성해야한다. // 5 초후에처음부터다시재생한다. delay(5000); 그림 4-12 버튼을이용한모형신호등만들기회로구성도 그림 4-11 디지털출력과부저 (buzzer) 를이용한멜로디재생회로구성도 - 37 -
그림 4-13 버튼을이용한모형신호등만들기시리얼모니터 - 38 -
5. 센서를이용한주변환경정보얻기 5.1 조도센서 [ 예제 5-1] 조도센서를이용한주변의밝기값출력하기이번예제는포토레지스터또는 CDS(Cadmium Sulfide - 황화카드뮴 ) 센서라고부르는조도센서를사용해주변의밝기를시리얼모니터로출력하는예제이다. CDS 센서는빛의밝기에따라저항값이변하는가변저항의일종으로어두우면높은저항값을가지고밝아지면저항값이낮아지는특성을가지고있다. 우리가사용할조도센서를가지고테스트해본결과형광등불빛에서 460 ~ 480 사이의값이출력되고손으로불빛을가렸을때 960 ~ 980 사이의값이출력되었다. 이예제에는 10KΩ 저항을사용하였다. CDS 센서도저항으로따로극성을구분해서연결하지않아도된다. // 시리얼통신포트를초기화한다. Serial.begin(9600); void loop() { // 아날로그 A3 핀으로입력되는 CDS 센서값을읽어온다. int val = analogread(cdspina3); Serial.println(String(val)); delay(500); [ 예제 5-2] 주변의밝기에따라 LED 제어하기 CDS 센서를이용해주변이어두워지면자동으로 LED를켜고주변이밝으면 LED를끄는예제와주변에밝기에따라 LED의밝기도변하는예제를만들어보자. 스케치 5-2-1은주변밝기에따라 LED를켜고끄기위해디지털출력을이용하는스케치이며스케치 5-2-2는주변의밝기에따라 LED의밝기가변하도록동작하기위해서는 CDS 센서입력값에따라아날로그출력을이용해 LED의밝기를조절하기위해 PWM(Pulse Width Modulation) 을지원하는디지털 9번핀을사용한스케치이다. 두스케치모두회로구성은그림 5-2와동일하며 CDS 센서에는 10KΩ의저항을연결하고 LED에는 220Ω의저항을연결하였다. [ 스케치 5-2-1] 주변이밝으면 LED 를끄고어두우면 LED 를켜기 // CDS 센서값을읽을아날로그 A5 핀지정 int cdspina5 = A5; 그림 5-1 조도센서를이용한주변의밝기값출력하기회로구성도 [ 스케치 5-1] 조도센서를이용한주변의밝기값출력하기 // CDS 센서값을읽을아날로그 A3핀지정 int cdspina3 = A3; // LED를켜고끄기위해출력신호를보낼 9번핀지정 int ledpin9 = 9; void setup() { // 시리얼통신포트초기화 Serial.begin(9600); void setup() { - 39 -
// LED 를켜고끄기위해디지털 9 번핀을출력모드로지정 pinmode(ledpin9, OUTPUT); int ledpin9 = 9; void setup() { void loop() { // 아날로그 A5 핀으로입력되는 CDS 센서의값을읽어온다. int val = analogread(cdspina5); /* 우리가사용할조도센서를가지고테스트해본결과형광등 * 불빛에서 460 ~ 480 사이의값이출력되고손으로불빛을가렸을때 * 960 ~ 980 사이의값이출력된다는데이터를얻었다. * 그래서아래조건문에서입력값이 600 미만이면주변이밝은것으로 * 판단하고 900 초과면주변이어두운것으로판단하게코드를구성하였다. if(val < 600) { // 밝으면 LED를끈다. digitalwrite(ledpin9, LOW); else if(val > 900) { // 어두우면 LED를켠다. digitalwrite(ledpin9, HIGH); Serial.println("CDS 입력값 : " + String(val)); delay(1000); [ 스케치 5-2-2] 주변밝기에따라 LED 밝기조절하기 // 시리얼통신포트초기화 Serial.begin(9600); // LED를밝기를조절하기위해디지털 9번핀을출력모드로지정 pinmode(ledpin9, OUTPUT); void loop() { // 아날로그 A5 핀으로입력되는 CDS 센서의값을읽어온다. int val = analogread(cdspina5); /* Arduino Uno의 ADC(Analog Digital Converter) 는 10비트의해상도로 * 아날로그핀으로입력되는값을디지털로변경하면 0 ~ 1023 사이의 * 값이된다. PWM 출력은 0 ~ 255 사이의값을출력하게되므로아두이노에서 * 제공하는수학함수인 map(value, fromlow, fromhigh, tolow, tohigh) * 함수를사용해아날로그로부터입력된 0 ~ 1023 사이의값을 0 ~ 255 * 사이의값으로맵핑 (Linear Mapping) 하였다. * 이함수를사용할때 fromlow 값과 fromhigh 값이같은경우 0으로 * 나누는 (divide by zero) 경우가발생하므로주의가필요하다. int mappingval = map(val, 0, 1023, 0, 255); analogwrite(ledpin9, mappingval); Serial.println("CDS 입력값 : " + String(val) + ", PWM 출력값 : " + String(mappingVal)); // CDS 센서값을읽을아날로그 A5 핀지정 int cdspina5 = A5; delay(500); // LED 로아날로그출력신호를보낼 PWM 을지원하는 9 번핀지정 - 40 -
참고사이트 : http://playground.arduino.cc/componentlib/thermistor2 이예제를테스트해본결과생각보다오차가큰 4 ~ 5 더높게온도가측정된다. 그림 5-2 주변의밝기에따라 LED 제어하기 5.2 온도센서 온도센서는온도에따라출력되는전압이변하는특성을가지는센서로온도가높을수록높은전압을출력한다. 우리가작성할예제에는아나로그핀을사용해온도를검출할수있는써미스터 (Thermistor) 와 TMP36 온도센서를사용해주변온도를측정하는예제를만들어볼것이다. 그림 5-3 써미스터를이용한주변온도측정하기회로구성도 [ 스케치 5-3] 써미스터를이용한주변온도측정하기 [ 예제 5-3] 써미스터를이용한주변온도측정하기써미스터 (Thermistor) 는여러가지금속산화물을녹여만든반도체소자로일반적인금속과는 // 써미스터값을읽어들일아날로그입력핀 A0을지정다르게온도가올라갈수록저항이감소하는전기적성질을가지고있어주변의온도변화를전 int thermistorpin = A0; 기적신호로바꾸어주는여러가지유형의센서역할을한다. 온도측정범위는 50 ~ 300 정도로온도측정장치나자동온도조절장치에많이사용된다. void setup() { 써미스터의종류도여러가지가있지만우리가사용할써미스터는온도가오르면저항값이떨어지는특성을가진 NTC(Negative Temperature Coefficient) 계열의써미스터를사용할것이 // 시리얼통신포트를초기화한다. 다. 써미스터또한가변저항으로극성이없어일반저항과같이아무방향으로연결해도된다. Serial.begin(9600); 먼저그림 5-3과같이풀다운 (Pull-down) 저항회로를구성하고스케치 5-3을작성하여테스 트해보자. 써미스터입력값을현재온도로변환하는작업은써미스터가가지는저항값과현재시점의써미스터입력값을조금은복잡한공식에적용해온도로산출해야한다. void loop() { 이번예제는아두이노공식사이트의 Playground에올라온예제를가지고이해를돕기위해소스를약간수정하고주석을추가하였다. - 41 -
// 아날로그 A0핀으로입력되는써미스터의값을읽는다. int readthermistor = analogread(thermistorpin); // 써미스터입력값을섭씨온도로변환한다. float temperature = totemperature(readthermistor); // 시리얼모니터에계산된섭씨온도를출력한다. Serial.print(" 현재온도 : "); Serial.print(temperature); Serial.println(" "); delay(1000); // 써미스터의값을온도로변환하는함수 float totemperature(int readthermistor) { // 10KΩ 풀다운 (Pull-down) 저항연결시 float temp = log(10000.0 * ((1024.0 / readthermistor - 1))); return temp; [ 예제 5-4] TMP36과 LM35 온도센서를이용한온도측정하기이번예제는써미스터보다가격은약간비싸지만온도를쉽게측정할수있는 TMP36과 LM35 라는온도센서 ( 열감지센서라고도한다.) 를가지고주변온도를측정하는예제를다루어볼것이다. TMP36 온도센서는온도가 1도변할때출력전압이 10mV 변하며영하의온도를측정할수있도록 500mV가섭씨 0 에해당하도록제작되어있다. TMP36을이용해섭씨온도를계산하기위해서는 TMP36의출력전압을구해야하는데이값은 TMP36의출력을아날로그입력핀에연결하여입력되는값을기준전압으로변경하여계산해야한다. 아날로그입력값은 analogread() 함수를통해읽을수있지만아두이노의 ADC는 10비트이므로 0 ~ 1023 사이의값이입력된다. 이값을기준전압인 0V ~ 5V로변환하여 TMP36의출력전압을환산하고다시바이어스 ( 동작기준점을정하기위한전압또는전류를바이어스라하며섭씨 0 에서 TMP36의기준전압은 500mV로이전압이 TMP 36의동작기준점이된다.) 값인 500mV를적용해섭씨온도를계산할수있다. 예를들어 analogread() 함수로얻은값이 143이라면 TMP36 센서의출력전압은아래와같이구할수있다. // 10KΩ 풀업 (Pull-up) 저항연결시 // float temp =log(10000.0 / (1024.0 / readthermistor - 1)); /* 절대온도 (absolute temperature / Kelvin temperature) 계산 * 절대온도란물질의특성에의존하지않는절대적인온도를말한다. * 1848년켈빈이도입하여켈빈온도또는열역학적온도라고도한다. * 섭씨온도 0 일때절대온도는 273.15K 이므로절대온도가 0K일때 * 섭씨온도는 -273.15 이며화씨온도로 -459.67 가된다. temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * temp * temp)) * temp); /* 절대온도 (K, Kelvin) 를섭씨온도 (, Celcius) 로변환한다. * 아래주석은절대온도 (K, Kelvin) 를화씨온도 (, Fahrenheit) 로변환한다. temp = temp - 273.15; // 절대온도를섭씨온도로변환 // temp = (temp * 9.0)/ 5.0 + 32.0; // 절대온도를화씨온도로변환 698.24mV = 143 * 5000.0mV / 1024.0 위와같이 698.24mV가측정되었다면 0 = 500mV가되고 1 가변할때마다 10mV가변하므로아래와같은공식을이용해섭씨온도를구할수있다. 섭씨온도 (( ) * 10mV = 출력전압 (mv) - 500mV라는공식이성립되므로섭씨온도 ( ) = (698.24mV 500mV) / 10mV라는공식을구할수있다. 이공식을적용해 TMP36의출력전압 698.24mV를섭씨온도로산출하면 19.8 가된다. 화씨온도 ( ) 는 32 ~ 180 까지이므로 ( 섭씨온도 ( ) * 1.8) + 32로구할수있다. LM35 온도센서도 TMP36과비슷하게 0.1 당 1mV 즉 1 당 10mV의비율로전압을출력한다. 하지만 TMP36의온도측정범위가 40 ~ 125 인반면 LM35는 0 ~ 100 까지측정할수있어동작기준점을정하는바이어스값이없다. 그림 5-4와같이회로를구성하고스케치 5-4를작성하여각센서의온도가정확히측정되는지테스트해보자. 그림 5-5는 TMP36과 LM35의단자구성그림이다. 두센서모두평평한부분을바라보고오른쪽에 Vcc를왼쪽에 GND를연결하고가운데출력단자를아날로그입력핀에연결하면된다. - 42 -
이예제를테스트해본결과 LM35 보다 TMP36 이더정확한온도를측정할수있었다. // TMP36 온도센서의출력값을읽을아날로그 A0 핀지정 int tmppina0 = A0; // LM35 온도센서의출력값을읽을아날로그 A3 핀지정 int lmpina3 = A3; void setup() { // 시리얼통신포트초기화 Serial.begin(9600); void loop() { 그림 5-4 TMP36 과 LM35 온도센서를이용한온도측정하기회로구성도 // TMP36과 LM35의센서값을읽어온다. int tmpinput = analogread(tmppina0); int lminput = analogread(lmpina3); // TMP36과 LM35의센서값을이용해각센서의출력전압을환산한다. float tmpmillivolt = tmpinput * 5000.0 / 1024.0; float lmmillivolt = lminput * 5000.0 / 1024.0; /* TMP36과 LM35의출력전압을섭씨온도로환산한다. * TMP36은 -40 ~ 125 까지측정할수있는온도센서로동작기준점인 * 0 에해당하는 500mV를적용해섭씨온도로환산해야한다. * TMP36과 LM35는온도가 1 변할때마다출력이 10mV씩변한다. float tmptemp = (tmpmillivolt - 500.0) / 10.0; float lmtemp = lmmillivolt / 10.0; 그림 5-5 TMP36 과 LM35 온도센서의단자구성 [ 스케치 5-4] TMP36 과 LM35 온도센서를이용한온도측정하기 // 시리얼모니터로각센서의온도측정값을출력한다. Serial.print("TMP36 측정온도 : "); Serial.print(tmpTemp); Serial.print(", LM35 측정온도 : "); Serial.println(lmTemp); - 43 -
delay(1000); [ 연습문제 5-1] TMP36 온도센서를활용한온도경보장치만들기 TMP36 온도센서와 RGB LED를이용해지정한온도범위 25 ~ 30 를유지하고있으면초록색 LED가계속해서켜지도록동작하게만들어보자. 또한온도범위를초과하면빨간색 LED 가깜박거리게하고온도범위미만이면파란색 LED를깜박거리게동작하는스케치를만들어보자. [ 예제 3-5] 시리얼통신을이용해 RGB LED 밝기제어하기와 [ 예제 5-4] TMP36과 LM35 온도센서를이용한온도측정하기를참고하여 Fritzing을이용해회로구성도를그리고브레드보드에회로를구성하여스케치를작성해보자. 수있다. 초음파거리센서모듈의에코핀으로들어오는펄스의길이를 58로나누면 cm 단위의거리를얻을수있다. 트리거핀의트리거간격은최소 50ms가되어야한다. HC-SR04 초음파센서모듈의동작전압은 5V이고주파수는 40KHz이다. 또한최대감지거리는 3M이고최소감지거리는 3cm 이다. 그림 5-6과같이회로를구성하고스케치 5-5를작성해작은물체를가지고거리측정이제대로되는테스트해보자. 5.3 초음파센서모듈 우리일상생활에서초음파는생각보다여러분야에서이용되고있다. 예를들면인체검진을위한초음파검사기, 어업을위한어군탐지기, 초음파세척기, 가습기등사람귀에는들리지않지만아주많은산업분야에서이용되고있다. 초음파는파장이짧아지향성과직진성이뛰어나고공기중에서는 340m/s의일정한속도로진행하는특징이있어거리를측정하는수단으로도많이사용되고있다. 예를들어자동차의후방경보시스템, 물체검출, 물체의크기측정, 수위측정등에도많이사용되고있다. [ 예제 5-5] 초음파센서를이용한거리측정초음파거리센서는초음파를이용해거리를측정하는센서로발신부와수신부로구성된다. 발신부는함수발생기에서 (+) 와 (-) 전압을압전소자에번갈아가할때압전소자의변형에의해진동이발생하고이진동에의해초음파가발생하는역압전현상을이용한다. 수신부는초음파가물체에반사되어되돌아오는파동에의해압전소자가진동하고그진동에의해전압이발생되는정압전현상을이용한다. 이렇게초음파거리센서는발신부에서초음파가발생한후물체에반사되어수신부로되돌아오는시간을측정해거리를계산한다. 우리가이번예제에사용할초음파센서는 HC-SR04 초음파센서모듈로 4핀연결단자를가지고있다. 이모듈앞뒤모두에각핀의이름이인쇄되어있다. 트리거 (Trigger) 핀으로최소 10μs의펄스를발생시키면에코 (Echo) 핀으로거리에비례하는펄스가반사되어돌아온다. 이예제에서사용하는 pulsein() 함수는특정핀으로입력되는펄스의길이를측정하는함수로마이크로초 ( μs ) 단위의시간을반환하므로이를통해거리를계산할 그림 5-6 초음파센서를이용한거리측정회로구성도 [ 스케치 5-5] 초음파센서를이용한거리측정 // 트리거핀에 5V를공급할디지털 9번핀지정 int triggerpin9 = 9; // 반사되어돌아오는초음파를감지하기위한디지털 6번핀지정 int echopin6 = 6; // 거리를계산에저장할변수선언 int distance; - 44 -
// 초음파가되돌아온시간을저장할변수 long duration; void setup() { // 시리얼통신포트초기화 Serial.begin(9600); // 초음파출력을위해디지털 9번핀을출력모드로지정 pinmode(triggerpin9, OUTPUT); /* 물체에반사되어되돌아오는초음파입력을받기위해 * 디지털 6번핀을입력모드로지정 pinmode(echopin6, INPUT); void loop() { // 초음파센서를동작시키려면 Trig 핀에 10μs시간동안 5V를공급한다. digitalwrite(triggerpin9, HIGH); /* 트리거핀으로 10μs의펄스를발생시킨다. * delaymicroseconds(unsigned long us) 함수는아두이노에서제공하는 * 시간함수로 us에지정한마이크로초만큼프로그램을실해하고일시 * 중지시키는함수이다. * 지정할수있는최대지정시간은 16383 마이크로초이다. * 이보다긴시간을지연시키려면 delay() 함수를사용해야한다. * 이함수는 3 마이크로초이상에서정확하게동작하며그이하에서는 * 정확성을보장하지못한다. 트리거핀에 10μs의펄스를발생시키면 * 40KHz의초음파 8개가앞으로출력된다. delaymicroseconds(10); digitalwrite(triggerpin9, LOW); * 초음파 8개가모두보내지면바로에코핀에 5V를공급한다. * 거리계산은에코핀으로들어오는펄스의길이를 58로나누면 * cm 단위로거리를얻을수있다. * pulsein(uint8_t pin, uint8_t value) 함수는지정한핀으로부터 * HIGH 또는 LOW를읽어들인다. value를 HIGH로지정하면지정한핀이 * HIGH 상태로바뀐후다시 LOW 상태로바뀔때까지의시간을마이크로초 * 단위로반환한다. // distance = pulsein(echopin6, HIGH) / 58; duration = pulsein(echopin6, HIGH); long cm = microsecondstocentimeters(duration); long inch = microsecondstoinches(duration); Serial.println(" 물체와의거리 : " + String(cm) + "cm, " + String(inch) + "inch"); delay(1000); // 매개변수로넘겨받은마이크로초를 cm로계산해반환하는함수 long microsecondstocentimeters(long duration) { return duration / 29 / 2; // 매개변수로넘겨받은마이크로초를 inch로계산해반환하는함수 long microsecondstoinches(long duration) { return duration / 72 / 2; /* 에코핀입력으로부터거리를 cm 단위로계산한다. - 45 -
6 원격으로장치제어 적외선수신기 적외선송수신은우리일상생활에서아주많이사용되고있는무선제어방식이다. 예를들면 TV, 에어콘, DVD 등의가전제품들은적외선을이용해제어하는대표적인제품이다. 적외선통신은 950nM 파장의적외선은햇빛이나전등, 형광등등에도적외선이포함되어있기때문에외부의영향을줄이기위해서캐리어주파수 (Carrier Frequency, 통신신호를전송하는주파수 ) 를사용하여전달하는방식이다. 적외선통신을수신하기위해서는이캐리어주파수를필터링하여약한신호를증폭하는과정을거쳐야한다. 참고로우리가자주사용하는삼성이나 LG의리모컨은주파수가 38KHz이다. 이번예제는 38KHz 주파수를수신할수있는적외선수신기 (CH0B나 KSM603LM) 를사용하여 LED를제어하는예제이다. 우리는 37.9KHz를수신할수있는 KSM603LM을사용할것이다. KSM603LM에는단자가 3개있는데돌출한부분을앞으로하여왼쪽부터수신 (Echo), GND, Vcc 연결핀으로구성되어있다. 적외선수신을위해서는 IRremote라는라이브러리가필요하다. 이라이브러리는그림 6-1과같이 https://github.com/shirriff/arduino-irremote 에서라이브러리코드와사용예제들을다운받을수있다. 이 IRremote 라이브러리를사용하기위해서아두이노가설치된폴더의 libraries\ 폴더에압축을풀어설치하면된다. 우리는 C:\ 에아두이노통합개발환경을설치했으므로그림 6-2와같이 C:\arduino-1.0.5-r2\libraries\ 에압축파일을복사하고여기에압축풀기로압축을풀면될것이다. 이때통합개발환경이실행되고있다면프로그램을종료하고설치해야한다. 그림 6-2 적외선라이브러리 IRremote 설치 그림 6-1 적외선라이브러리 IRremote 다운로드 위의방법은이전의통합개발환경에서 IRremote 라이브러리가없는경우에라이브러리를추가 하는방법이다. 물론 arduino-1.6.6 통합개발환경에서도 RobotIRremote 폴더를삭제하고위와 같이적용하면사용이가능하다. - 46 -
[ 예제 6-1] 적외선수신기로리모컨수신하기적외선수신기 KSM603LM을이용해우리가일상에서사용하고있는리모컨의신호를수신하는예제를만들어보자. 먼저리모컨으로부터입력된값을알아보기위해아래의스케치 Sketch06-06RemoteTest를이용해각브랜드별리모컨입력값을체크하여스케치를작성해보자. [ 스케치 6-1] 리모컨으로수신된데이터를시리얼모니터로출력하기 /** * 리모컨의입력값과리모컨타입을시리얼모니터로출력하는예제 #include <IRremote.h> // 적외선수신기가연결되어있는디지털핀 9번정의 const int RECEIVE_PIN = 9; // IRrecv 객체를생성한다. IRrecv irrecv(receive_pin); if(irrecv.decode(&decodesignal)) { // 마지막메시지이후 1/4초가경과되었는지체크한다. if(millis() - last > 250) { long input = decodesignal.value; // 리모컨입력값과리모컨타입을시리얼모니터에출력한다. Serial.print(" 리모컨입력값 : "); Serial.print(input, HEX); Serial.print(", 십진수 : "); Serial.print(input, DEC); Serial.println(", 원본값 : " + String(decodeSignal.value)); Serial.print(", 리모컨타입 : "); Serial.println(decodeSignal.decode_type); delay(500); // IR 감지기의결과를저장한다. decode_results decodesignal; // 마지막 IR 메시지수신시간을갱신한다. last = millis(); void setup() { // 시리얼통신포트초기화 Serial.begin(9600); // 다른메시지를기다린다. irrecv.resume(); /* 시리얼포트가준비되었는지검사한다. * 시리얼포트가준비되지않았다면무한대기한다. while(!serial) { // 적외선수신기객체를시작한다. irrecv.enableirin(); unsigned long last = millis(); void loop() { Sketch06-01 스케치를이용해각브랜드별리모컨에서전송한값을시리얼모니터로출력해봤으니이번에는그림 6-3과같이회로를구성하고스케치 6-2를작성해아두이노로업로드한후 TV 리모컨을사용해신호를보내고아두이노에서이신호를받아 LED를제어하는예제를만들어보자. - 47 -
#define JVC 8 #define MITSUBISHI 10 #define UNKNOWN -1 // LG TV 리모컨 - 타입 1 #define LG_NUM2 551504055 #define LG_NUM5 551528535 #define LG_NUM8 551491815 // NEC M420X 리모컨 - 타입 1 #define NEC_NUM3 412592725 #define NEC_NUM5 412574620 #define NEC_NUM7 412607515 그림 6-3 적외선수신기로리모컨수신하기회로구성도 [ 스케치 6-2] 적외선수신기로리모컨수신하기 // 삼성 TV 리모컨 - 타입 -1 #define SAM_NUM0 3119867746 #define SAM_NUM2 2908251746 #define SAM_NUM5 1931099650 #define SAM_NUM8 1747313982 // IRremote 라이브러리코드를스케치에추가한다. #include <IRremote.h> //#include <IRremoteTools.h> /* * 아래리모컨타입정의는 * C:\arduino-1.6.6\libraries\RobotIRremote\src 폴더의 * IRremote.h 파일에정의되어있는것을다시정의한것이다. #define NEC 1 #define SONY 2 #define RC5 3 #define RC6 4 #define DISH 5 #define SHARP 6 #define PANASONNIC 7 // 적외선수신기가연결되어있는디지털핀 9번정의 const int RECEIVE_PIN = 9; // RGB LED 출력핀정의 int redpin5 = 5; int greenpin6 = 6; int bluepin7 = 7; // IRrecv 객체를생성한다. IRrecv irrecv(receive_pin); // IR 감지기의결과를저장한다. decode_results decodesignal; // 적외선수신이완료되면 LED에신호를보낼디지털핀 3번지정 - 48 -
int ledpin3 = 3; void setup() { // 시리얼통신포트초기화 Serial.begin(9600); /* 마지막 IR 메시지의수신시간을저장한다. * unsigned long millis(void) 함수는아두이노가제공하는시간함수로 * 스케치프로그램이시작된이후의경과시간을밀리초단위로반환한다. * 약 50일이경과하면오버플로우 (Overflow) 로인해다시 0이된다. unsigned long last = millis(); /* 시리얼포트가준비되었는지검사한다. * 시리얼포트가준비되지않았다면무한대기한다. while(!serial){ ; // LED 출력핀정의 pinmode(ledpin3, OUTPUT); pinmode(redpin5, OUTPUT); pinmode(greenpin6, OUTPUT); pinmode(bluepin7, OUTPUT); /* 초기시작시 R, B, B색상의 LED가모두꺼진상태로시작한다. * 우리가사용하는 RGB LED는공통애노드방식으로 R, G, B 단자를 GND에 * 연결하므로각단자에 0을출력하면최대밝기가되고 255를출력하면 * 최소밝기가된다. digitalwrite(redpin5, HIGH); digitalwrite(greenpin6, HIGH); digitalwrite(bluepin7, HIGH); // 적외선수신기오브젝트시작한다. irrecv.enableirin(); void loop() { // 적외선신호가들어오면 true를리턴한다. if(irrecv.decode(&decodesignal)) { // 마지막메시지이후 1/4초가경과되었는지체크한다. if(millis() - last > 250) { // LED 상태를토글시킨다. lightstate =!lightstate; // 리모컨입력값과리모컨타입을시리얼모니터에출력한다. long inputnum = decodesignal.value; Serial.print(" 리모컨입력값 : "); Serial.print(inputNum, HEX); Serial.print(", 십진수 : "); Serial.println(inputNum, DEC); Serial.print(" 리모컨타입 : " ); Serial.println(decodeSignal.decode_type); digitalwrite(ledpin3, lightstate); delay(300); lightstate =!lightstate; digitalwrite(ledpin3, lightstate); delay(300); // LED 상태초기화 boolean lightstate = false; // 2 번키가입력되었으면 RGB LED 빨간색켜기 if(inputnum == SAM_NUM2) { digitalwrite(redpin5, LOW); - 49 -
digitalwrite(greenpin6, HIGH); digitalwrite(bluepin7, HIGH); // 5번키가입력되었으면 RGB LED 초록색켜기 else if(inputnum == SAM_NUM5) { digitalwrite(redpin5, HIGH); digitalwrite(greenpin6, LOW); digitalwrite(bluepin7, HIGH); // 8번키가입력되었으면 RGB LED 파란색켜기 else if(inputnum == SAM_NUM8) { digitalwrite(redpin5, HIGH); digitalwrite(greenpin6, HIGH); digitalwrite(bluepin7, LOW); // 0번키가입력되었으면 RGB LED 모두끄기 else if(inputnum == SAM_NUM0) { digitalwrite(redpin5, HIGH); digitalwrite(greenpin6, HIGH); digitalwrite(bluepin7, HIGH); // 마지막 IR 메시지수신시간을갱신한다. last = millis(); // 다른메시지를기다린다. irrecv.resume(); - 50 -
7. 블루투스통신 블루투스 (Bluetooth) 는 1994년에릭슨 (Ericsson) 이개발하여 1999년 5월블루투스 SIG(Special Interest Group) 에의해공식발표된근거리무선통신 (Personal Area Network, PAN) 을위한산업표준으로 RS-232를대체하기위한저가격, 저전력의무선통신기술이다. 또한블루투수는 IEEE 802.15.1(IEEE는국제전기전자기술자협회의표준규격이다.) 규격을사용하는개인근거리무선통신의산업표준이다. SIG는초기에소니에릭슨, IBM, 노키아, 도시바, 인텔등이참여하여시작되었으며현재는 13,000이넘는회원사를보유하고있다. 블루투스는 2.45GHz 대역인 ISM(Industrial Scientific Medical) 대역을사용하며상위및하위영역은다른시스템과의간섭을막기위해제거하고 2402MHz ~ 2480MHz까지총 79개의채널을사용한다. ISM대역 (Industrial Scientific Medical band) 은산업, 과학, 의료분야에서사용할목적으로할당된대역으로전파사용에대한허가를받을필요가없어저전력의전파를사용하는개인무선기기에많이사용되고있다. 2.4GHz 대역은무선 LAN 서비스, 블루투스, 무선식별시스템 (RFID), 디지털코드없는전화등다양한분야의통신에사용되고있다. 블루투스 1.x 버전의통신속도는 723.1Kbps이며암호화기술과 EDR(Enhanced Data Rate) 기술이추가된 2.x 버전의경우 2.1Mbps의속도로데이터를전송할수있다. 2014년현재최신블루투수버전은 4.1로 24Mbps까지데이터를전송할수있다. EDR(Enhanced Data Rate) 은 GPS정보, 파일, 동영상전송이가능한데이터전송기술로이전에등록했던기기를자동으로인식하여별도의페어링없이기기를자동으로연결한다. 블루투수는마스터와슬레이브를구성하여통신할수있으며하나의마스터기기에최대 7개의슬레이브기기를연결하여사용할수있다. 블루투수는마스터와슬레이브사이의통신만가능하며슬레이브와슬레이브사이에는통신이불가능하다. 우리생활에서많은블루투스제품들이사용되고있지만응용분야에따라서여러가지프로파일 (Profile) 로나누어져있다. 프로파일이란블루투수무선통신을위한프로토콜로이프로파일의종류에따라서로지원하는기능이다르다. 우리가실습에사용하는블루투스 HC-06 모듈은여러가지프로파일중에서시리얼통신을사용하기위한 SPP(Serial Port Profile) 프로파일이구현된모듈이다. 그림 7-1 블루투스 HC-06 모듈 블루투스는무선연결이고시리얼통신과는방식이다르지만블루투수 HC-06 모듈에서무선통신을담당하고 SPP(Serial Port Profile) 를지원하기때문에유선을사용한시리얼통신과동일한방법으로블루투스통신을구현할수있다. 우리는그림 7-1과같은 HC-06 슬레이브모듈을사용해아두이노보드와컴퓨터또는아두이노보드와스마트폰사이의블루투스통신을실습하게될것이다. 블루투수 HC-06 슬레이브모듈은그림 7-1과같이 4개의핀 (Vcc, GND의전원핀과시리얼통신을위한 RX, TX 핀 ) 을가지고있다. 이블루투스 HC-06 모듈을연결할때는 TX, RX 핀을아두이노보드의 RX, TX 핀과교차하여연결해야하므로블루투수 HC-06 슬레이브모듈의 TX 핀은아두이노의 RX 핀에연결하고 RX 핀은아두이노보드의 TX 핀에연결해야한다. 이방식은우리가그동안사용해온컴퓨터와아두이노보드의시리얼통신과동일한방식으로아두이노보드의디지털 0번 (RX) 핀과 1번 (TX) 핀을연결해사용해야하지만디지털 0번과 1번핀은이미컴퓨터와 USB 연결을통한시리얼통신에사용되고있으므로이핀들을이용한하드웨어시리얼방식은사용할수없다. 그러므로우리는블루투스 HC-06 슬레이브모듈을디지털 0번핀과 1번핀이외의핀에연결하고아두이노에서제공하는소프트웨어시리얼방식을사용하여블루투스통신을구현하게될것이다. Arduino Uno에는 UART(Universal Asynchronous Receiver Transmitter) 시리얼통신을위한포트가하나뿐이라시리얼연결을사용하는두개이상의장치를연결할수없다. 이런한계를보완하기위해아두이노는소프트웨어적으로가상의 UART 시리얼포트를생성하여시리얼통신을지원하는 SoftwareSerial 라이브러리를제공하고있다. [ 예제 7-1] 블루투스 HC-06 모듈동작테스트그림 7-2와같이블루투스 HC-06 모듈을이용한회로를구성하고스케치 7-1을작성하여아두이노보드에업로드한후시리얼모니터를이용해블루투수 HC-06 슬레이브모듈이제대로동작하는지테스트해보자. [ 스케치 7-1] 블루투스 HC-06 모듈동작테스트 /* Arduino Uno에는 UART(Universal Asynchronous Receiver Transmitter) * 시리얼통신을위한포트가하나뿐이라시리얼연결을사용하는 * 두개이상의장치를연결할수없다. 이런한계를보완하기위해 * 아두이노는소프트웨어적으로가상의 UART 시리얼포트를생성하여 * 시리얼통신을지원하는 SoftwareSerial 라이브러리를제공하고있다. * 소프트웨어시리얼을사용하기위해라이브러리를 include 해야한다. #include <SoftwareSerial.h> - 51 -
/* 소프트웨어시리얼포트를사용하기위해선언하고있다. * SoftwareSerial(RX, TX) 형식으로블루투스모듈과교차하여연결된다. * 블루투스 HC-06 모듈의 RX 핀에연결된디지털 8번은아두이노보드의 * TX 핀이되고블루투스 HC-06 모듈의 TX 핀에연결된디지털 7번은아두이노 * 보드의 RX 핀이된다. 블루투수모듈을초기화하고생성할때 * BTSerial(RX, TX) 의첫번째인수로블루투스 HC-06 모듈의 TX에연결된 * 아두이노보드의 RX 핀을지정하고두번째인수로블루투스 HC-06 모듈의 * RX에연결된아두이노보드의 TX핀을지정하면된다. SoftwareSerial BTSerial(7, 8); // SoftwareSerial BTSerial = SoftwareSerial(7, 8); void setup() { // 컴퓨터와시리얼통신을위한하드웨어통신포트초기화 Serial.begin(9600); // 블루투수 HC-06 모듈과통신을위한소프트웨어시리얼통신포트초기화 BTSerial.begin(9600); /* 소프트웨어시리얼통신포트의버퍼에수신된데이터가존재하면 * SoftwareSerial 클래스의 available() 함수는 Serial 클래스의 available() * 함수와마찬가지로블루투스모듈에서사용하는소프트웨어시리얼 * 포트의수신버퍼에저장된데이터의바이트수를반환한다. * 버퍼에데이터가존재하지않으면 0을반환한다. * 블루투수모듈 --> 아두이노보드 --> 시리얼모니터 if(btserial.available()) { /* "AT" 명령을받은블루투스 HC-06 모듈은응답데이터인 "OK" 를 * 아두이노보드의소프트웨어시리얼수신포트 (RX) 인디지털 7번핀으로 * 보내고아두이노보드는수신된데이터를 1Byte씩읽어하드웨어 * 시리얼통신포트를통해시리얼모니터로보내출력하게된다. byte b = BTSerial.read(); Serial.write(b); void loop() { /* 하드웨어시리얼통신포트의버퍼에수신된데이터가존재하면 * 시리얼모니터 --> 아두이노보드 --> 블루투스모듈 if(serial.available()) { /* 시리얼모니터로부터넘어온 "AT" 명령을하드웨어시리얼통신포트를 * 통해아두이노보드로전달되고아두이노보드는수신된데이터를 * 1Byte씩읽어아두이노보드의소프트웨어시리얼전송포트 (TX) 인 * 디지털 8번핀을통해블루투수 HC-06 모듈의 RX 핀으로전송하게된다. byte b = Serial.read(); BTSerial.write(b); 그림 7-2 블루투스 HC-06 모듈동작테스트회로구성도 - 52 -
블루투스 HC-06 모듈을사용할때한가지주의사항은블루투스모듈의동작전압이 3.3V이기때문에블루투스 HC-06 모듈의 Vcc 핀에 5V를연결하면안되고 3.3V를연결해야한다는것이다. 필자가 5V에연결하여테스트해본결과문제는발생하지않았지만 5V를연결할경우블루투스 HC-06 모듈의칩이손상되거나신호를제대로인식하지못하게되는경우가발생할수있기때문에 5V 보다는 3.3V를연결해사용하는것이바람직하다. 스케치를아두이노보드에업로드한후시리얼모니터를화면에띄우고 AT 명령을블루투스 HC-06 모듈로전송해보자. 이때시리얼모니터로 OK 문자열이수신되었다면이모듈은정상적으로동작하고있는것이다. 참고로이실습은시리얼모니터의라인옵션리스트박스에서 No line ending 또는 줄끝없음 을선택해야블루투수 HC-06 모듈에서보낸 OK 를시리얼모니터로출력할수있다. 아래는블루투스 HC-06 모듈로보낼수있는명령어이다 이유는 Windows 8 이상에서는블루투스동글을컴퓨터 USB에장착하면그림 7-3과같이 Windows 8이자동으로드라이버를검색하여특별한설정없이드라이버를자동으로설치해주는친절함을보이지만필자가 Windows 8에서자동으로설치해준드라이버를가지고테스트해본결과우리가사용하는블루투수동글과는잘맞지않는것같다. 먼저 http://www.bluesoleil.com 사이트에접속해블루투스동글을사용할수있는드라이버인 IVT_BlueSoleil_9.2.484.0.zip 파일을다운로드받은후압축을풀고그폴더안으로들어가서 setup.exe 를더블클릭해실행하면그림 7-4와같이한국어가기본선택된언어선택화면이나타난다. 여기에서 확인 버튼을클릭하여그림 7-5 화면으로넘어간다. AT+NAMEbtModule : 블루투수모듈의이름을 btmodule 로변경 ( 이름은임의로줄것 ) AT+PIN1111 : 블루투수모듈의비밀번호를 1111 로변경 AT+BAUD4 : 통신속도를변경 (4 9600, 5 19200, 7-57600, 8-115200) [ 예제 7-2] 블루투스 HC-06 모듈과컴퓨터블루투수통신대부분의노트북컴퓨터에는블루투스모듈이기본장착되어있지만아직도많은 PC에는블루투스모듈이장착되어있지않기때문에블루투스동글을사용해아두이노보드와컴퓨터간의블루투스통신을실습해볼것이다. 블루투스를지원하지않는컴퓨터라면먼저컴퓨터의 USB 포트에블루투스동글을장착하고드라이버를설치해야한다. 우리는블루투스동글을컴퓨터의 USB에장착하기전에블루투스동글드라이버를먼저설치할것이다. 그림 7-4 블루투스동글드라이버설치 02 그림 7-3 블루투스동글드라이버설치 01 그림 7-5 블루투스동글드라이버설치 03-53 -
그림 7-5에서 다음 을클릭하여나타나는이후화면에서기본설정된상태그대로드라이버설치를진행하면된다. 드라이버설치는큰어려움이없으니여기서생략하도록하겠다. 블루투수동글드라이버가제대로설치되었다면작업표시줄의숨겨진아이콘을표시하는화살표 ( ) 를마우스로클릭하면그림 7-6과같이빨간색동그라미로표시한블루투스아이콘이보일것이다. 그림 7-7 블루투수 HC-06 모듈과컴퓨터페어링하기 05 그림 7-6 블루투수동글드라이버설치 04 블루투스장치간의통신을위해서는먼저두장치를마스터-슬레이브한쌍으로묶어주는페어링 (Pairing) 이라는과정을거쳐야한다. 블루투스장치를페어링할때는보안연결을위해암호를입력해야페어링이이루어지는경우도있으며암호입력없이페어링이이루어지는경우도있다. 우리가사용하는블루투수 HC-06 모듈의기본비밀번호는 1234, 통신속도는 9600(Baud), 8비트데이터비트와 1비트의정지비트그리고패리티비트없음으로설정되어있다. 그러나위에서비밀번호를 1111 로변경했다면이비밀번호를사용해페어링해야한다. 그럼블루투수 HC-06 모듈과컴퓨터를페어링해보자. 먼저블루투스기능이꺼져있는지확인하기위해작업표시줄의숨겨진아이콘을표시하는화살표 ( ) 를마우스로클릭하면그림 7-7의좌측그림과같이숨겨진아이콘들이나타난다. 여기서블루투스아이콘이꺼진상태로표시된다면이아이콘을마우스로클릭하거나마우스오른쪽버튼을클릭하여그림 7-7의좌측그림과같이 [Bluetooth 켜기 (T)] 메뉴를선택해블루투스기능을활성화시킨다. 이어서블루투수아이콘을마우스로클릭하거나마우스오른쪽버튼을클릭하여그림 7-7의우측그림과같이 [ 클래식보기표시 (D)] 메뉴를선택하면그림 7-8과같은화면이나타난다. 그림 7-8 블루투수 HC-06 모듈과컴퓨터페어링하기 06-54 -
이화면중앙에위치한공모양의노란색아이콘을더블클릭하던가마우스오른쪽버튼을클릭하여나타난컨텍스트메뉴의 [ 장치검색 (D)] 을선택하면프로그램이연결가능한블루투스장치를검색하여그림 7-9와같이? 표새겨진아이콘이생성된다. 이아이콘을마우스오른쪽버튼을클릭하여그림 7-10에서와같이 [ 페어링 ] 을선택하면그림 7-11과같이보안연결을위해페어링에필요한암호를물어보는화면이나타난다. 이화면에서블루투수 HC-06 모듈의기본암호인 1234 ( 예제 7-1에서비밀번호를수정했다면수정된비밀번호를사용해야한다.) 를입력하고 확인 버튼을클릭하면컴퓨터 ( 마스터 ) 와블루투수 HC-06 모듈 ( 슬레이브 ) 간의페어링이이루어진다. 페어링이완료되면? 표새겨진아이콘의이름이 btmodule 로바뀌고이아이콘에마우스오른쪽버튼을클릭해나타나는컨텍스트메뉴에서그림 7-12와같이 [ 연결 Bluethooth 직렬포트 (COM6)] 을선택하면그림 7-13과같은화면이나타나면서컴퓨터와블루투수 HC-06 모듈의블루투수송신포트를활성화시킨다. 그림 7-10 블루투수 HC-06 모듈과컴퓨터페어링하기 08 그림 7-9 블루투수 HC-06 모듈과컴퓨터페어링하기 07 그림 7-11 블루투수 HC-06 모듈과컴퓨터페어링하기 9-55 -
정없이바로실행하여사용할수있다. 필자는그림 7-14와같이아두이노와컴퓨터가 USB 연결을통해 COM9번포트를사용하고블루투수 HC-06 모듈이컴퓨터의 USB 포트에장착한블루투수동글과연결되어 COM6번포트를사용한다. 즉시리얼모니터에서입력한메시지가 COM9번시리얼포트를통해아두이노보드로전달되고스케치프로그램에서작성한프로그램에의해다시블루투수 HC-06 모듈로전달된후블루투수무선통신을이용해컴퓨터에연결된동글을통해컴퓨터로데이터가전달된다. 이때블루투수동글로수신된데이터는 COM6번시리얼포트를사용해컴퓨터에서데이터를읽을수있다. 그림 7-12 블루투수 HC-06 모듈과컴퓨터페어링하기 10 그림 7-14 아두이노와컴퓨터블루투수통신 다시말해 COM9번시리얼포트통신은아두이노에서제공하는시리얼모니터를사용해메시지를주고받고 COM6번시리얼포트의통신은 Hercules SETUP utility를사용해메시지를주고받는다. 여러분은필자와다른시리얼포트를사용할수도있으니시리얼포트를확인해아래에서설명하는내용을참고로시리얼포트를설정하면된다. 참고로필자의노트북에서테스트를그림 7-13 블루투수 HC-06 모듈과컴퓨터페어링하기 11 해본결과블루투수통신에사용되는시리얼포트는 COM7번으로설정되었다. 그림 7-15는 COM6번시리얼포트를사용하는 Hercules SETUP utility를실행한화면이다. 이에뮬레이터를처음실행하면 UDP Setup 탭이선택되어있는데그림 7-16와같이 Serial 이번예제는 [ 예제 7-1] 의 [ 스케치 7-1] 과회로를그대로사용하여아두이노에장착된블루투스탭을선택하고그림에서와같이 Serial 포트에대한정보를설정한후 Open 버튼을클릭하여 HC-06 슬레이브모듈과컴퓨터의블루투수동글을통해블루투수통신으로메시지를주고받는메시지출력창에 Serial pot COM6 Opened 라는메시지가출력되면 COM6번포트에정상적예제이다. 이번실습에서시리얼모니터 2개를사용해야메시지를주고받을수있으므로컴퓨터으로연결된것이다. 그리고블루투수 HC-06 모듈로보낼메시지를 Send 입력란에입력하고와아두이노간의메시지송 / 수신은시리얼모니터를사용하고컴퓨터와블루투수 HC-06 슬레 Send 버튼을클릭하면시리얼모니터로메시지가출력될것이다. 또한시리얼모니터에서메이브모듈간의 ( 정확히는컴퓨터에장착된블루투스동글을통한메시지송 / 수신 ) 메시지송 / 수시지를보내면이에뮬레이터의메시지출력창에출력될것이다. 신은 Hercules SETUP utility를사용하여실습할것이다. Hercules SETUP utility는 http://www.hw-group.com/products/hercules/index_en.html 에서다운받을수있다. 이에뮬레이터는다운로드되는파일이실행파일이므로별도의설치과 - 56 -
그림 7-15 Hercules SETUP utility 실행화면 그림 7-16 Hercules SETUP utility 설정화면 [ 예제 7-3] 안드로이드폰과블루투스통신을이용한 LED 제어이번에는아두이노에연결된블루투수 HC-06 모듈을통해안드로이드폰과블루투수통신을실습하는예제이다. 먼저그림 7-17과같이회로를구성하고스케치 7-3을작성하여아두이노에업로드한후테스트해보자. 이예제를테스트하기위해서는먼저안드로이드폰에블루투스를통해 LED를제어할앱을설치해야한다. [ 스케치 7-3] 안드로이드폰과블루투스통신을이용한 LED 제어 - 57 - /* Arduino Uno에는 UART(Universal Asynchronous Receiver Transmitter) * 시리얼통신을위한포트가하나뿐이라시리얼연결을사용하는 * 두개이상의장치를연결할수없다. 이런한계를보완하기위해 * 아두이노는소프트웨어적으로가상의 UART 시리얼포트를생성하여 * 시리얼통신을지원하는 SoftwareSerial 라이브러리를제공하고있다. * 소프트웨어시리얼을사용하기위해라이브러리를 include 해야한다.
#include <SoftwareSerial.h> // LED 에전원을공급할디지털 12 번핀을출력모드로지정하고있다. pinmode(ledpin12, OUTPUT); /* 블루투수 HC-06 모듈의 TX 핀과 RX 핀에연결할디지털 2번핀과 * 3번핀을지정하고 LED에전원을공급할디지털 12번핀을지정하고있다. int rxpin2 = 2; int txpin3 = 3; int ledpin12 = 12; // RGB LED 출력핀정의 int redpin5 = 5; int greenpin6 = 6; int bluepin7 = 7; /* 소프트웨어시리얼포트를사용하기위해선언하고있다. * SoftwareSerial(RX, TX) 형식으로블루투스모듈과교차하여연결된다. * 블루투스 HC-06 모듈의 RX 핀에연결된디지털 3번은아두이노보드의 * TX 핀이되고블루투스 HC-06 모듈의 TX 핀에연결된디지털 2번은아두이노 * 보드의 RX 핀이된다. 블루투수모듈을초기화하고생성할때 * bluebooth(rx, TX) 의첫번째인수로블루투스 HC-06 모듈의 TX에연결된 * 핀을지정하고두번째인수로블루투스 HC-06 모듈의 RX에연결된핀을 * 지정하면된다. SoftwareSerial bluetooth(rxpin2, txpin3); //SoftwareSerial bluetooth = SoftwareSerial(rxPin2, txpin3); void setup() { // RGB LED 출력모드정의 pinmode(redpin5, OUTPUT); pinmode(greenpin6, OUTPUT); pinmode(bluepin7, OUTPUT); /* 초기시작시 R, B, B색상의 LED가모두꺼진상태로시작한다. * 우리가사용하는 RGB LED는공통애노드방식으로 R, G, B 단자를 GND에 * 연결하므로각단자에 0을출력하면최대밝기가되고 255를출력하면 * 최소밝기가된다. digitalwrite(redpin5, HIGH); digitalwrite(greenpin6, HIGH); digitalwrite(bluepin7, HIGH); void loop() { char cmd; /* 소프트웨어시리얼통신포트의버퍼에수신된데이터가존재하면 * SoftwareSerial 클래스의 available() 함수는 Serial 클래스의 available() * 함수와마찬가지로블루투스모듈에서사용하는소프트웨어시리얼 * 포트의수신버퍼에저장된데이터의바이트수를반환한다. * 버퍼에데이터가존재하지않으면 0을반환한다. if(bluetooth.available()) { // 컴퓨터와시리얼통신을위한하드웨어통신포트초기화 Serial.begin(9600); delay(100); // 블루투수 HC-06 모듈과통신을위한소프트웨어시리얼통신포트초기화 bluetooth.begin(9600); /* 블루투수를통해수신된데이터를 1Byte씩읽어온다. * 블루투수 HC-06 모듈의 TX 핀을통해아두이노보드의 * RX 핀인디지털 2번핀으로입력된데이터를읽어온다. cmd = (char) bluetooth.read(); /* 블루투수 HC-06 모듈에수신된데이터를시리얼모니터로출력한다. - 58 -
* 하드웨어시리얼포트를통해컴퓨터로전달되고시리얼모니터에출력된다. Serial.print("cmd : "); Serial.println(cmd); // 안드로이드폰으로부터수신된데이터가 1이면 LED를 ON if(cmd == '1') { // 시리얼모니터로 LED가켜진것을알리고디지털 12번핀에 HIGH를인가한다. Serial.println("LED ON"); digitalwrite(ledpin12, HIGH); // 안드로이드폰으로부터수신된데이터가 2이면 LED를 OFF else if(cmd == '2') { // 시리얼모니터로 LED가꺼진것을알리고디지털 12번핀에 LOW를인가한다. Serial.println("LED OFF"); digitalwrite(ledpin12, LOW); // 안드로이드폰으로부터수신된데이터가 3이면 RGB LED의 RED ON else if(cmd == '3') { Serial.println("RGB LED - RED ON"); digitalwrite(redpin5, LOW); digitalwrite(greenpin6, HIGH); digitalwrite(bluepin7, HIGH); while(true) { digitalwrite(ledpin12, HIGH); delay(100); digitalwrite(ledpin12, LOW); delay(100); if(bluetooth.available()) { break; // 안드로이드폰으로부터수신된데이터가 4면 RGB LED의 GREEN ON else if(cmd == '4') { Serial.println("RGB LED - GREEN ON"); digitalwrite(redpin5, HIGH); digitalwrite(greenpin6, LOW); digitalwrite(bluepin7, HIGH); while(true) { digitalwrite(ledpin12, HIGH); delay(500); digitalwrite(ledpin12, LOW); delay(100); if(bluetooth.available()) { break; // 안드로이드폰으로부터수신된데이터가 5면 RGB LED의 BLUE ON else if(cmd == '5') { Serial.println("RGB LED - BLUE ON"); digitalwrite(redpin5, HIGH); digitalwrite(greenpin6, HIGH); digitalwrite(bluepin7, LOW); while(true) { digitalwrite(ledpin12, HIGH); delay(500); digitalwrite(ledpin12, LOW); delay(500); if(bluetooth.available()) { break; // 안드로이드폰으로부터수신된데이터가 6이면 RGB LED OFF else if(cmd == '6') { - 59 -
Serial.println("RGB LED - OFF"); digitalwrite(redpin5, HIGH); digitalwrite(greenpin6, HIGH); digitalwrite(bluepin7, HIGH); 그림 7-17 안드로이드폰과블루투스통신을이용한 RGB LED 제어회로구성도 - 60 -
8. 이더넷 (Ethernet) 통신 청을보낸장치에서사용가능한 IP 주소를동적으로할당한다. 우리가가정에서사용하는대부분의인터넷유무선공유기는내부적으로사설 IP 주소를사용하아두이노보드를인터넷또는 LAN(Local Network Area) 에연결하여온도센서를이용해집안고있으며이사설 IP를사용하는장치는외부인터넷에접속하기위해공인 IP 주소를가지고의현재온도정보를받아에어컨이나보일러를 ON/OFF 할수있고온 / 습도센서를이용해있는공유기의 IP 주소로인터넷에접속하게된다. 화분에습도를측정하고수분이부족하면스탭핑모터를제어해화분에물을주는장치를구동사설 IP 장치가인터넷으로데이터를송 / 수신할때는공유기에내장되어있는네트워크주소변할수도있다. 아두이노보드만가지고는인터넷에연결할수없고이더넷쉴드를아두이노보환기능 (NAT : Network Address Translation) 을사용한다. 드에추가로장착하여인터넷통신을구현할수있다. 아두이노의 Ethernet 라이브러리는웹서버나클라이언트를만드는데필요한여러가지방법 ( 프로토콜 ) 을지원하고있다. Ethernet 라이브러리는표준인터넷프로토콜을사용하고있지만프로토콜과관련된대부분의하위레벨기술은모듈화되어클래스나라이브러리로숨겨져있 8.1 이더넷쉴드설정하기다. 전체네트워크통신을구현하려면먼저 ISO(International Standard Organization) 에서우리가이번에실습해볼예제는아두이노에서제공하는 Ethernet 표준예제중 WebClient 스제안한네트워크에연결된시스템이갖추어야하는기능인 OSI 7 계층모델 (Open System 케치를기반으로작성한예제로이더넷쉴드에 MAC 주소를설정하고구글검색을통해검색된 Interconnection 7 Layer Model) 을알아야하지만이는하드웨어와소프트웨어를어우르는내용을수신하는방법을알아보자. 네트워크전체영역이므로우리에게꼭필요하다고생각되는몇가지용어만집고넘어가겠다. [ 예제 8-1] 구글검색결과받아오기 - 이더넷 (Ethernet) 이예제는이더넷쉴드에 DHCP IP 주소할당이실패할경우고정 IP 주소할당을통해아두이이더넷은하위레벨신호계층으로기본적인물리적메시지전달기능을제공한다. 노를인터넷에접속시키고이더넷쉴드가정상적으로동작하고있는지구글검색을통해테스메시지소스및대상주소는 MAC(Media Access Control) 주소로식별된다. 아두이노스케치트할수있는예제이다. 에서는네트워크내에서고유해야하는 MAC 주소값을정의할수있다. [ 스케치 8-1] 구글검색결과받아오기 - MAC(Media Access Control) 주소 /* SPI(Serial Peripheral Interface) 통신을위한헤더포함 IP 주소와는다르게 MAC 주소는전세계적으로유일한값으로정의된다. 모든네트워크통신 * SPI는전이중 (Full-Duplex) 방식의통신으로동시에송 / 수신이장치마다공장에서출하할때지정되며한번지정되면 MAC 주소는바뀌지않는다. * 가능한양방향디지털데이터통신을위한프로토콜이다. MAC 주소는고유한값으로네트워크에서물리적인시스템을식별할때사용된다. * Ethernet 통신을위해서필수로포함해야한다. - TCP/IP #include <SPI.h> TCP(Transmission Control Protocol) 과 IP(Internet Protocol) 은이더넷위에구현된핵심인터넷프로토콜로글로벌인터넷상에서동작하는메시지전달기능을제공한다. 이 TCP/IP 메시 // Ethernet 통신을위한헤더포함지는송신자와수신자의고유 IP 주소를통해전달된다. #include <Ethernet.h> 우리가많이사용하는 HTTP(Hyper Text Transfer Protocol), FTP(File Transfer Protocol) 등이이 TCP/IP 기반에서동작하도록설계된응용프로토콜이다. /* 이더넷쉴드에사용할 MAC 주소지정 * 정품이더넷쉴드에는 MAC 주소가스티커로부착되어있으나호환이더넷쉴드는 - DHCP(Dynamic Host Configuration Protocol) * MAC 주소스티커가없는것이많은데이때는아래와같이임의의 MAC 주소를 DHCP는동적으로호스트를설정하는프로토콜로인터넷에연결하려는장치를지역네트워크에 * 16진수 6개를지정해사용할수있다. 쉽게연결할수있는방법을제공하는프로토콜이다. byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED ; 어떤장치가네트워크에연결되면 DHCP 요청을라우터 ( 공유기 ) 에보내고라우터는 DHCP 요 - 61 -
/* DHCP IP 할당이실패할경우이더넷쉴드에할당할 IP 지정 * 현재네트워크에적합한사설 IP를지정하여사용할것 //byte ip[] = { 192, 168, 123, 177; IPAddress ip(192, 168, 123, 177); // 접속할서버 URL 지정 char server[] = "www.google.com"; //IPAddress server(74,125,232,128); EthernetClient client; void setup() { // 시리얼통신포트초기화 Serial.begin(9600); // DHCP IP 할당이실패할경우 if(ethernet.begin(mac) == 0) { Serial.println("DHCP IP 할당실패 "); Serial.println(" 구글서버접속중..."); if(client.connect(server, 80)) { Serial.println(" 구글서버접속완료 "); // GET 방식의요청을보내구글서버로부터 arduino를검색한다. client.println("get /search?q=arduino HTTP/1.1"); client.println(); else { Serial.println(" 구글서버접속실패 "); void loop() { // Ethernet 수신버퍼에데이터가존재하면 if(client.available()) { // Ethernet 수신버퍼에서첫문자를읽어오고읽어온문자는삭제한다. char c = client.read(); Serial.println(" 지정한 IP 주소를할당받는중..."); Ethernet.begin(mac, ip); // 이더넷장치를초기화하는동안잠시기다린다. delay(1000); // 할당받은 IP 주소를시리얼모니터로출력 Serial.print(" 할당받은 IP 주소 : "); Serial.println(Ethernet.localIP()); // IP 주소를지정해초기화할경우 IP 주소를할당받지못하는경우가발생함. //Serial.println("IP 주소를할당받는중..."); //Ethernet.begin(mac, ip); // Ethernet 수신버퍼로부터읽어온문자를시리얼모니터에출력한다. Serial.print(c); // 현재연결된상태가아니면 if(!client.connected()) { Serial.println(); Serial.println(" 구글서버접속해제됨 "); client.stop(); while(true); - 62 -
8.2 아두이노를웹서버로동작시키기 아두이노와이더넷쉴드를이용해아두이노에서웹서비스를제공하는방법에대해알아보자. 아두이노에서웹서비스를하려면아파치 (Apache) 와같은웹서버가동작하는프로토콜을이해해야한다. 물론아두이노에서는아파치와같은전문적인웹서버스는불가능하다하지만아두이노핀에연결된센서값이나 LED를동작시킬수있는간단한웹서비스는가능하다. 웹브라우저와웹서버는 HTTP 프로토콜을통해요청과응답을수행한다. 아두이노는웹브라우저의요청을받고요청에대한응답헤더와요청처리결과를 HTTP 프로토콜규격에맞게작성해웹브라우저로보내야한다. 이번예제는아두이노에서제공하는 Ethernet 표준예제중 WebServer 스케치를기반으로작성한예제로 p42 [ 예제 5-4] 에서다뤄본 TMP36 온도센서를이용해온도를측정하고웹브라우저로출력해주는예제이다. [ 예제 8-2] 아두이노를웹서버로동작시키기브레드보드에그램 8-1과같이회로를구성하고스케치를작성하여웹브라우저로테스트해보자. [ 스케치 8-2] 아두이노를웹서버로동작시키기 /* SPI(Serial Peripheral Interface) 통신을위한헤더포함 * SPI는전이중 (Full-Duplex) 방식의통신으로동시에송 / 수신이 * 가능한양방향디지털데이터통신을위한프로토콜이다. * Ethernet 통신을위해서필수로포함해야한다. #include <SPI.h> // Ethernet 통신을위한헤더포함 #include <Ethernet.h> /* 이더넷쉴드에사용할 MAC 주소지정 * 정품이더넷쉴드에 MAC 주소가스티커로부착되어있으나호환이더넷쉴드는 * MAC 주소스티커가없는것이많은데이때는아래와같이임의의 MAC 주소를 * 16진수로 6개를지정해사용할수있다. byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED ; /* DHCP IP 할당이실패할경우이더넷쉴드에할당할 IP 지정 * 현재네트워크에적합한사설 IP를지정하여사용할것 //byte ip[] = { 192, 168, 123, 177; IPAddress ip(192, 168, 123, 177); // 웹서버의기본포트인 80 번포트로설정하여 EthernetServer 객체생성 EthernetServer server(80); // TMP36 온도센서의출력값을읽을아날로그 A0 핀지정 int tmppina5 = A5; void setup() { 그림 8-1 아두이노를웹서버로동작시키기회로도 // 시리얼통신포트초기화 Serial.begin(9600); - 63 -
// DHCP IP 할당이실패할경우 if(! Ethernet.begin(mac)) { Serial.println("DHCP IP 할당실패 "); // IP 주소를지정해초기화할경우 IP 주소를할당받지못하는경우가발생함. Serial.println(" 지정한 IP 주소를할당받는중..."); Ethernet.begin(mac, ip); // 이더넷장치를초기화하는동안잠시기다린다. delay(10); // 할당받은 IP 주소를시리얼모니터로출력 Serial.print(" 할당받은 IP 주소 : "); Serial.println(Ethernet.localIP()); // 80번포트로서버를시작한다. server.begin(); void loop() { /* Server로요청이수신되면요청을보낸 EthernetClient 객체를구한다. * 이예제에서는 EthernetClient 객체를이용해 Server로들어오는메시지를처리한다. EthernetClient client = server.available(); // EthernetClient가성공적으로시작되었으면 if(client) { // HTTP 요청이끝났는지여부를저장할변수 - HTTP 요청은빈줄로끝난다. boolean current_line_is_blank = true; /* 웹서버가요청을보낸클라이언트와연결되었으면반복문안에서 * 클라이언트의요청을분석하여응답데이터를작성하여클라이언트로출력한다. while(client.connected()) { // 클라이언트가보낸메시지가수신되었으면 if(client.available()) { // 수신버퍼에서첫문자를읽고읽어온문자를버퍼에서삭제한다. char c = client.read(); Serial.print(c); /* 현재읽어온문자가개행문자이고그줄이빈줄이면 * HTTP 요청이끝난것이되므로응답데이터를작성한다. if(c == '\n' && current_line_is_blank) { // 표준 HTTP 응답헤더를작성한다. client.println("http/1.1 200 OK"); // HTTP 응답데이터의문서형식 (MIME) 을지정한다. client.println("content-type: text/html; charset=utf-8"); client.println(); client.print(" 현재거실온도 : "); client.print(temperature()); client.println(" "); // 아두이노의아날로그핀 A0 ~ A5에입력된값을출력한다. /* for(int i = 0; i < 6; i++) { client.print(" 아날로그입력값 : "); client.print(i); client.print(" : "); client.print(analogread(i)); client.println("<br/>"); Serial.println(); */ break; if(c == '\n') { - 64 -
current_line_is_blank = true; else if(c!= '\r') { current_line_is_blank = false; delay(10); client.stop(); 8.3 웹페이지에서아두이노를통해 LED 제어하기 [ 예제 8-3] 웹페이지에서아두이노를통해 LEL 제어하기이번예제는웹페이지에서아두이노웹서버로요청을보내 RGB LED를끄거나켜고 LED의밝기를조절하는예제를만들어보자. 먼저그림 8-2와같이회로를구성하자. // TMP36으로부터값을읽어섭시온도로리턴하는함수 int temperature() { // TMP36의센서값을읽어온다. int tmpinput = analogread(tmppina5); // TMP36 의센서값을이용해센서의출력전압을환산한다. float tmpmillivolt = tmpinput * 5000.0 / 1024.0; /* TMP36의출력전압을섭씨온도로환산한다. * TMP36은 -40 ~ 125 까지측정할수있는온도센서로동작기준점인 * 0 에해당하는 500mV를적용해섭씨온도로환산해야한다. * TMP36은온도가 1 변할때마다출력이 10mV씩변한다. float tmptemp = (tmpmillivolt - 500.0) / 10.0; // 시리얼모니터로각센서의온도측정값을출력한다. Serial.print("TMP36 측정온도 : "); Serial.print(tmpTemp); return tmptemp; 그림 8-2 웹페이지에서아두이노를통해 LED 제어하기회로도 [ 스케치 8-3] 웹페이지에서아두이노를통해 LED 제어하기 /* SPI(Serial Peripheral Interface) 통신을위한헤더포함 * SPI는전이중 (Full-Duplex) 방식의통신으로동시에송 / 수신이 * 가능한양방향디지털데이터통신을위한프로토콜이다. * Ethernet 통신을위해서필수로포함해야한다. #include <SPI.h> // Ethernet 통신을위한헤더포함 #include <Ethernet.h> - 65 -