NodeMCU 입문하기 목차 1. NodeMCU란? 2. NodeMCU로할수있는프로젝트 3. NodeMCU 개발환경구축하기 4. NodeMCU를사용하여 HELLO WORLD! 웹에출력하기 5. NodeMCU로 Blink 예제실행하기 6. 원격으로 LED 제어하기 7. 원격으로 RGB LED 제어하기 8. 원격으로온습도모니터링하기 9. 원격으로화분의수분량모니터링하기 10. 128X62 LCD에원격으로텍스트출력하기 11. 미세먼지모니터링
1. NodeMCU 란? NodeMCU ( 노드엠씨유 ) 는오픈소스사물인터넷 (IoT) 플랫폼으로와이파이기능이구현된 MCU 개발보드라고생각할수있습니다. 아두이노및라즈베리파이를사용해보신분이라면한번쯤들어보셨을 ESP8266 와이파이모듈을개발한 ESPRESSIF사의 ESP8266-12 모듈을사용합니다. 이름에서의미하는것처럼사물인터넷노드용 MCU이며, 작은크기와저렴한가격으로네트워크기능이구현된아두이노라고생각할수있습니다. 메카솔루션에서판매하고있는 NodeMCU V1.0은 ESP-12E를사용하며, USB 신호를 UART 신호로변경하기위해서 CP2012 칩셋을사용하고있습니다. 마이크로USB의앞쪽에있는조그만칩이 CP2012이고, 오른쪽의안테나와알루미늄쉴드가 ESP8266-12E SOC이며, 중앙의검정색칩이 LM1117로 5V 전압을 3.3V로변환합니다.
[NodeMCU V1.0 의핀배치도 ] 2. NodeMCU 로할수있는프로젝트 아두이노와와이파이모듈로할수있었던원격제어, 원격모니터링이주로 NodeMCU 로할수 있는프로젝트입니다. 3D 프린터를활용하여현재시간과날씨습도등의데이터를웹을통해받은후디스플레이를
할수도있으며, 저렴한 DHT11 센서를통해원격으로온습도센싱을한후디스플레이를할수도있습니다. 뿐만아니라, 스마트플러그를통한전력센싱과전력제어, 그리고비닐하우스내에서광량조절및온습도조절등다양한분야에서도활용할수있습니다.
3. NodeMCU 개발환경구축하기 NodeMCU는 Lua라는프로그램언어를통해개발할수있습니다. 하지만, 많은사람들이아두이노 IDE를통해프로그래밍을하면서보다많은자료가공유되고, 편리하게사용되고있습니다. 본챕터에서는아두이노 IDE를통한 NodeMCU 개발환경을구축하고, 기본예제인 Blink 프로그램을업로드해보도록하겠습니다. 먼저, NodeMCU 에 USB 마이크로케이블을통해 PC 에연결합니다. 그러면다음과같이 CP2012 드 라이버가설치되는것을윈도우즈오른쪽하단에서확인할수있습니다. 제대로설치되었는지보기위해서는 PC 의장치관리자의포트를통해재확인할수있습니다. 아두이노 IDE 를설치했다면, Tools ( 도구 ) Boards Manager ( 보드매니저 ) 를통해 ESP8266 개발툴킷 을설치합니다.
설치가완료된후, 아두이노 IDE 의 Tools ( 도구 ) Board ( 보드 ) 설정에서 NodeMCU 1.0 (ESP-12E Module) 이라는보드를찾을수있습니다. 클릭을해서지정을합니다.
그다음에는 NodeMCU가연결된포트를 Tools ( 도구 ) Port ( 포트 ) 를통해설정합니다. 보드선택할때와마찬가지로클릭을해서지정을하게되는데, 여러개의 COM 포트가있다면연결된 NodeMCU를 PC에서뺐다가다시연결하면서변화가있는 COM 포트번호를선택할수있습니다.
4. NodeMCU 를사용하여 HELLO WORLD! 웹에출력하기 #include <ESP8266WiFi.h> const char* ssid = "iptime"; const char* password = ""; WiFiServer server(80); void setup() { Serial.begin(115200); delay(10); // Connect to WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status()!= WL_CONNECTED) { delay(500); Serial.print("."); Serial.println(""); Serial.println("WiFi connected"); // Start the server server.begin(); Serial.println("Server started"); // Print the IP address Serial.print("Use this URL to connect: "); Serial.print("http://"); Serial.print(WiFi.localIP()); Serial.println("/");
void loop() { // Check if a client has connected WiFiClient client = server.available(); if (!client) { return; // Wait until the client sends some data Serial.println("new client"); while(!client.available()){ delay(1); // Read the first line of the request String request = client.readstringuntil('\r'); Serial.println(request); client.flush(); // Return the response client.println("http/1.1 200 OK"); client.println("content-type: text/html"); client.println(""); // do not forget this one client.println("<!doctype HTML>"); client.println("<html>"); client.print("hello WORLD!"); client.println("</html>"); delay(1); Serial.println("Client disonnected"); Serial.println(""); 업로드가완료된후에, 오른쪽상단의시리얼모니터링버튼을클릭하고 NodeMCU 의리셋버튼을 누르면원격접속하기위한 URL 을확인할수있습니다.
http://192.168.1.16 을스마트폰에서접속하면 HELLO WORLD! 라는텍스트를다음과같이확인할 수있습니다.
5. NodeMCU 로 Blink 예제실행하기 NodeMCU를사용하여 Blink 예제를사용해보면다른점을발견할수있는데, 바로내장된 LED이다. digitalwrite(led, HIGH); 를실행하면 LED가켜져야한다고생각하는데, NodeMCU에서는이부분이반대로되어있다. 그이유는다음의 NodeMCU의스케메틱을통해확인해볼수있다. NodeMCU 에서제공하는스케메틱을보면, 오른쪽상단의블럭에서내장 LED 와연결된 GPIO16 번 이 LED 의 (-) 극에연결이되어있다. 확대해서살펴보면다음과같다.
GPIO16이 LOW인상태이면, LED는 3V3을입력받고불이켜지게되며, GPIO16이상태가 HIGH가되면, LED의양단의전위차가 0이되어불이꺼지게된다. 일반적인아두이노의 13번내장 LED와는방향이반대이기때문에같은예제를사용하더라도반대로 LED가작동하는것을확인할수있다. 때문에, NodeMCU를사용하여내장된 LED를제어한다면다음과같은코드를사용할수있다. int LED_pin = 16; int turn_on = 0; int turn_off = 1; void setup() { // put your setup code here, to run once: pinmode(led_pin, OUTPUT); digitalwrite(led_pin, turn_off); void loop() { // put your main code here, to run repeatedly: digitalwrite(led_pin, turn_on); delay(1000);
digitalwrite(led_pin, turn_off); delay(1000);
6. 원격으로 LED 제어하기 #include <ESP8266WiFi.h> const char* ssid = "iptime"; const char* password = ""; WiFiServer server(80); // 변수지정 int LED_pin = 16; int turn_on = 0; int turn_off = 1; void setup() { Serial.begin(115200); delay(10); pinmode(led_pin, OUTPUT); digitalwrite(led_pin, turn_off); // Connect to WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status()!= WL_CONNECTED) { delay(500); Serial.print("."); Serial.println(""); Serial.println("WiFi connected"); // Start the server
server.begin(); Serial.println("Server started"); // Print the IP address Serial.print("Use this URL to connect: "); Serial.print("http://"); Serial.print(WiFi.localIP()); Serial.println("/"); void loop() { // Check if a client has connected WiFiClient client = server.available(); if (!client) { return; // Wait until the client sends some data Serial.println("new client"); while(!client.available()){ delay(1); // Read the first line of the request String request = client.readstringuntil('\r'); Serial.println(request); client.flush(); // Match the request int value = turn_off; if (request.indexof("/led=on")!= -1) { digitalwrite(led_pin, turn_on); value = turn_on; if (request.indexof("/led=off")!= -1) { digitalwrite(led_pin, turn_off); value = turn_off;
// Return the response client.println("http/1.1 200 OK"); client.println("content-type: text/html"); client.println(""); // do not forget this one client.println("<!doctype HTML>"); client.println("<html>"); client.print("led pin is now: "); if(value == turn_on) { client.print("on"); else { client.print("off"); client.println("<br><br>"); client.println("<a href=\"/led=on\"\"><button>turn On </button></a>"); client.println("<a href=\"/led=off\"\"><button>turn Off </button></a><br />"); client.println("</html>"); delay(1); Serial.println("Client disonnected"); Serial.println(""); 스마트폰에서접속을한후에, 버튼을클릭하게되면다음과같이원격으로 LED 가제어되는것을 확인할수있습니다.
7. 원격으로 RGB LED 제어하기 #include <ESP8266WiFi.h> const char* ssid = "iptime"; const char* password = ""; WiFiServer server(80); // 변수지정 int LED_pin_R = 5; // D1 int LED_pin_G = 4; // D2
int LED_pin_B = 0; // D3 // Anode int turn_on = 0; int turn_off = 1; // Cathode // int turn_on = 1; // int turn_off = 0; void setup() { Serial.begin(115200); delay(10); pinmode(led_pin_r, OUTPUT); pinmode(led_pin_g, OUTPUT); pinmode(led_pin_b, OUTPUT); digitalwrite(led_pin_r, turn_off); digitalwrite(led_pin_g, turn_off); digitalwrite(led_pin_b, turn_off); // Connect to WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status()!= WL_CONNECTED) { delay(500); Serial.print("."); Serial.println(""); Serial.println("WiFi connected"); // Start the server server.begin(); Serial.println("Server started");
// Print the IP address Serial.print("Use this URL to connect: "); Serial.print("http://"); Serial.print(WiFi.localIP()); Serial.println("/"); void loop() { // Check if a client has connected WiFiClient client = server.available(); if (!client) { return; // Wait until the client sends some data Serial.println("new client"); while(!client.available()){ delay(1); // Read the first line of the request String request = client.readstringuntil('\r'); Serial.println(request); client.flush(); // Match the request int value_r = turn_off; int value_g = turn_off; int value_b = turn_off; if (request.indexof("/led_r=on")!= -1) { digitalwrite(led_pin_r, turn_on); value_r = turn_on; if (request.indexof("/led_r=off")!= -1) { digitalwrite(led_pin_r, turn_off);
value_r = turn_off; if (request.indexof("/led_g=on")!= -1) { digitalwrite(led_pin_g, turn_on); value_g = turn_on; if (request.indexof("/led_g=off")!= -1) { digitalwrite(led_pin_g, turn_off); value_g = turn_off; if (request.indexof("/led_b=on")!= -1) { digitalwrite(led_pin_b, turn_on); value_b = turn_on; if (request.indexof("/led_b=off")!= -1) { digitalwrite(led_pin_b, turn_off); value_b = turn_off; // Return the response client.println("http/1.1 200 OK"); client.println("content-type: text/html"); client.println(""); // do not forget this one client.println("<!doctype HTML>"); client.println("<html>"); client.println("<meta http-equiv='content-type' content='text/html' charset='utf-8'/>"); client.println("<br><br>"); client.println("<a href=\"/led_r=on\"\"><button> 빨간색 LED ON </button></a>"); client.println("<a href=\"/led_r=off\"\"><button> 빨간색 LED OFF </button></a><br/>"); client.println("<a href=\"/led_g=on\"\"><button> 녹색 LED ON </button></a>"); client.println("<a href=\"/led_g=off\"\"><button> 녹색 LED OFF </button></a><br/>"); client.println("<a href=\"/led_b=on\"\"><button> 파랑색 LED ON </button></a>"); client.println("<a href=\"/led_b=off\"\"><button> 파랑색 LED OFF </button></a><br/>");
client.println("</html>"); delay(1); Serial.println("Client disonnected"); Serial.println("");
8. 원격으로온습도모니터링하기 HELLO WORLD! 예제에서는 NodeMCU 웹서버에접속한브라우저에 HTML로텍스트를표현해보았습니다. 이번에는텍스트뿐만아니라온도와습도를센서를사용하여모니터링하고, 이를웹서버의브라우저에표현해보도록하겠습니다. 그리고, 스마트폰을통해원격으로접속하여확인하는프로그램을작성해보겠습니다. 사용할온습도센서는 DHT11 기반의온습도센서로다음과같습니다. 사양 (Specification) 작동전압 : DC 3.3V ~ 5V 온도범위 : 0 ~ 50 / 정밀도 ± 2 습도범위 : 0~90% RH / 정밀도 ± 5% 디지털인터페이스크기 : 30 x 21 mm 먼저, DHT11 센서를사용하기위해서다음의링크를참고해볼수있습니다. https://blog.naver.com/roboholic84/221186233842 상단의링크에라이브러리에대한사용법및링크가있지만, 직접라이브러리압축파일은다음의링크에서다운로드받습니다. https://github.com/adafruit/adafruit_sensor https://github.com/adafruit/dht-sensor-library 그리고, 창의오른쪽에녹색버튼인 Clone or download 을클릭해서압축파일을받습니다.
두개의압축파일을받은후에, 아두이노 IDE 의 Sketch ( 스케치 ) Include Library Add.ZIP Library 를통해추가합니다.
먼저, 원격이아닌온습도만모니터링하는프로그램은다음과같습니다. #include "DHT.h" #define DHTPIN 2 // DHT11 이연결된핀 #define DHTTYPE DHT11 // DHT 11, DHT 시리즈중 11 을선택합니다. DHT dht(dhtpin, DHTTYPE); void setup() { Serial.begin(9600); Serial.println("DHTxx test!");
dht.begin(); void loop() { delay(2000); float h = dht.readhumidity();// 습도를측정합니다. float t = dht.readtemperature();// 온도를측정합니다. float f = dht.readtemperature(true);// 화씨온도를측정합니다. // 값읽기에오류가있으면오류를출력합니다. if (isnan(h) isnan(t) isnan(f)) { Serial.println("Failed to read from DHT sensor!"); return; // 보정된화씨값을가져옵니다. float hif = dht.computeheatindex(f, h); // 보정된섭씨값을가져옵니다. float hic = dht.computeheatindex(t, h, false); Serial.print("Humidity: "); Serial.print(h); Serial.print(" %\t"); Serial.print("Temperature: "); Serial.print(t); Serial.print(" *C "); Serial.print(f); Serial.print(" *F\t"); Serial.print("Heat index: "); Serial.print(hic); Serial.print(" *C "); Serial.print(hif); Serial.println(" *F"); 시리얼모니터링을통해, 온습도가잘출력되는것을확인한후원격으로데이터를모니터링하기 위해다음의코드를업로드해봅니다.
#include <ESP8266WiFi.h> const char* ssid = "iptime"; const char* password = ""; #include "DHT.h" #define DHTPIN 2 // DHT11이연결된핀 #define DHTTYPE DHT11 // DHT 11, DHT시리즈중 11을선택합니다. DHT dht(dhtpin, DHTTYPE); WiFiServer server(80); void setup() { Serial.begin(115200); delay(10); Serial.println("DHTxx test!"); dht.begin(); // Connect to WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status()!= WL_CONNECTED) { delay(500); Serial.print("."); Serial.println(""); Serial.println("WiFi connected"); // Start the server server.begin(); Serial.println("Server started"); // Print the IP address
Serial.print("Use this URL to connect: "); Serial.print("http://"); Serial.print(WiFi.localIP()); Serial.println("/"); void loop() { // Check if a client has connected WiFiClient client = server.available(); if (!client) { return; // Wait until the client sends some data Serial.println("new client"); while(!client.available()){ delay(1); // Read the first line of the request String request = client.readstringuntil('\r'); Serial.println(request); client.flush(); delay(2000); float h = dht.readhumidity();// 습도를측정합니다. float t = dht.readtemperature();// 온도를측정합니다. float f = dht.readtemperature(true);// 화씨온도를측정합니다. // 값읽기에오류가있으면오류를출력합니다. if (isnan(h) isnan(t) isnan(f)) { Serial.println("Failed to read from DHT sensor!"); return; // 보정된화씨값을가져옵니다. float hif = dht.computeheatindex(f, h);
// 보정된섭씨값을가져옵니다. float hic = dht.computeheatindex(t, h, false); // Return the response client.println("http/1.1 200 OK"); client.println("content-type: text/html"); client.println(""); // do not forget this one client.println("<!doctype HTML>"); client.println("<html>"); client.print("humidity: "); client.print(h); client.print(" %\t"); client.print("temperature: "); client.print(t); client.print(" *C "); client.print(f); client.print(" *F\t"); client.print("heat index: "); client.print(hic); client.print(" *C "); client.print(hif); client.println(" *F"); client.println("</html>"); delay(1); Serial.println("Client disonnected"); Serial.println(""); 시리얼모니터링을위해브라우저에서 http://192.168.1.16 을접속해봅니다.
9. 원격으로화분의수분량모니터링하기 사양 (Specification) 토양수분센서아날로그인터페이스센싱부표면금도금입력전압 : 3.3~5V 출력전압 : 0~3.6V 전체크기 : 60 x 20mm 센싱부크기 : 40 x 20mm
#include <ESP8266WiFi.h> const char* ssid = "iptime"; const char* password = ""; WiFiServer server(80); void setup() { Serial.begin(115200); delay(10); // Connect to WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status()!= WL_CONNECTED) { delay(500); Serial.print("."); Serial.println(""); Serial.println("WiFi connected"); // Start the server server.begin(); Serial.println("Server started"); // Print the IP address Serial.print("Use this URL to connect: "); Serial.print("http://"); Serial.print(WiFi.localIP()); Serial.println("/"); void loop() { // Check if a client has connected WiFiClient client = server.available();
if (!client) { return; // Wait until the client sends some data Serial.println("new client"); while(!client.available()){ delay(1); // Read the first line of the request String request = client.readstringuntil('\r'); Serial.println(request); client.flush(); delay(2000); int waterlevel = analogread(0); // Return the response client.println("http/1.1 200 OK"); client.println("content-type: text/html"); client.println(""); // do not forget this one client.println("<!doctype HTML>"); client.println("<html>"); client.print("water level: "); client.print(waterlevel); client.println("</html>"); delay(1); Serial.println("Client disonnected"); Serial.println("");
동일한방법으로아날로그센서를사용하는조도센서, 사운드센서, 수위센서, 가스센서등에사용할수있습니다. 사양 (Specification) CDS 황화카드뮴광센서아날로그인터페이스작동전압 : DC 3.3V ~ 5V 크기 : 23 x 21 mm
사양 (Specification) LM386 기반사운드센서아날로그인터페이스작동전압 : DC 5V 크기 : 26 x 21 mm 무게 : 5g 사양 (Specification) 아날로그인터페이스작동전압 : 3.3~5V 크기 : 60 x 40mm 무게 : 4g
사양 (Specification) MQ 시리즈가스센서아날로그인터페이스작동전압 : 5V 크기 : 38 x 21mm 측정가스 : 알코올
10. 128X62 LCD 에원격으로텍스트출력하기 https://github.com/squix78/esp8266-oled-ssd1306 사양 (Specification) 0.96 인치 OLED 디스플레이 SSD1306 드라이버칩사용 I2C 인터페이스 I2C 주소 : 0x3C 해상도 : 128x64 컬러 : 검정 / 배경, 흰색 / 글씨크기 : 38 x 28 x 9mm 무게 : 16g
OLED 12864 I2C GND VCC SDA SCL NodeMCU 보드 GND 3V3 D2 D1 /* Hello World OLED Test */ #include "SSD1306.h" // alias for `#include "SSD1306Wire.h"`
SSD1306 display(0x3c, 5, 4); // Initialise the OLED display using Wire library void setup() { Serial.begin(115200); display.init(); // Initialising the UI will init the display too. display.flipscreenvertically(); display.clear(); drawhelloworld(); display.display(); void loop() { void drawhelloworld() { display.settextalignment(text_align_left); display.setfont(arialmt_plain_10); display.drawstring(0, 0, "Mechasolution"); display.setfont(arialmt_plain_16); display.drawstring(0, 10, "Mechasolution"); display.setfont(arialmt_plain_24); display.drawstring(0, 26, "Mechasolution");
11. 미세먼지모니터링 int measurepin = 0; int ledpower = 5; unsigned int samplingtime = 280; unsigned int deltatime = 40; unsigned int sleeptime = 9680; float vomeasured = 0; float calcvoltage = 0; float dustdensity = 0;
void setup(){ Serial.begin(9600); pinmode(ledpower,output); void loop(){ digitalwrite(ledpower,low); delaymicroseconds(samplingtime); vomeasured = analogread(measurepin); delaymicroseconds(deltatime); digitalwrite(ledpower,high); delaymicroseconds(sleeptime); calcvoltage = vomeasured*(5.0/1024); dustdensity = 0.17*calcVoltage-0.1; if ( dustdensity < 0) { dustdensity = 0.00; Serial.println("Raw Signal Value (0-1023):"); Serial.println(voMeasured); Serial.println("Voltage:"); Serial.println(calcVoltage); Serial.println("Dust Density:"); Serial.println(dustDensity); delay(1000); 원격미세먼지모니터링 #include <ESP8266WiFi.h> const char* ssid = "iptime";
const char* password = ""; // 먼지센서모니터링용변수 int measurepin = 0; int ledpower = 5; unsigned int samplingtime = 280; unsigned int deltatime = 40; unsigned int sleeptime = 9680; float vomeasured = 0; float calcvoltage = 0; float dustdensity = 0; WiFiServer server(80); void setup() { Serial.begin(115200); delay(10); pinmode(ledpower,output); // Connect to WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status()!= WL_CONNECTED) { delay(500); Serial.print("."); Serial.println(""); Serial.println("WiFi connected"); // Start the server server.begin(); Serial.println("Server started");
// Print the IP address Serial.print("Use this URL to connect: "); Serial.print("http://"); Serial.print(WiFi.localIP()); Serial.println("/"); void loop() { // Check if a client has connected WiFiClient client = server.available(); if (!client) { return; // Wait until the client sends some data Serial.println("new client"); while(!client.available()){ delay(1); // Read the first line of the request String request = client.readstringuntil('\r'); Serial.println(request); client.flush(); delay(1000); digitalwrite(ledpower,low); delaymicroseconds(samplingtime); vomeasured = analogread(measurepin); delaymicroseconds(deltatime); digitalwrite(ledpower,high); delaymicroseconds(sleeptime); calcvoltage = vomeasured*(5.0/1024); dustdensity = 0.17*calcVoltage-0.1;
if ( dustdensity < 0) { dustdensity = 0.00; // Return the response client.println("http/1.1 200 OK"); client.println("content-type: text/html"); client.println(""); // do not forget this one client.println("<!doctype HTML>"); client.println("<html>"); client.print("raw Signal Value (0-1023): "); client.println(vomeasured); client.print("voltage:"); client.println(calcvoltage); client.print("dust Density:"); client.println(dustdensity); client.println("</html>"); delay(1); Serial.println("Client disonnected"); Serial.println("");