Skip to content
Home » 아두 이노 Wifi 모듈 | [Esp8266] 드디어!! Esp8266을 인터넷에 접속 시켜보자! 인기 답변 업데이트

아두 이노 Wifi 모듈 | [Esp8266] 드디어!! Esp8266을 인터넷에 접속 시켜보자! 인기 답변 업데이트

당신은 주제를 찾고 있습니까 “아두 이노 wifi 모듈 – [ESP8266] 드디어!! ESP8266을 인터넷에 접속 시켜보자!“? 다음 카테고리의 웹사이트 sk.taphoamini.com 에서 귀하의 모든 질문에 답변해 드립니다: https://sk.taphoamini.com/wiki/. 바로 아래에서 답을 찾을 수 있습니다. 작성자 러봇랩 이(가) 작성한 기사에는 조회수 23,816회 및 좋아요 206개 개의 좋아요가 있습니다.

Table of Contents

아두 이노 wifi 모듈 주제에 대한 동영상 보기

여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!

d여기에서 [ESP8266] 드디어!! ESP8266을 인터넷에 접속 시켜보자! – 아두 이노 wifi 모듈 주제에 대한 세부정보를 참조하세요

ESP8266의 주소를 알아내 웹 브라우저에서 열어볼까요?
아두이노 코드는 여기에 (sourcecode) :
https://github.com/LOVOTLAB/youtube/tree/master/ESP8266/webServerLED
//러봇랩
웹사이트: http://www.lovot.co
인스타그램: https://www.instagram.com/lovotlab/

아두 이노 wifi 모듈 주제에 대한 자세한 내용은 여기를 참조하세요.

아두이노(Arduino) 인터넷 하기 – Wifi (ESP-01: ESP8266)연결 …

아두이노(Arduino)로 인터넷을 연결하는 방법은 랜선(LAN)을 연결하는 방법인 이더넷 모듈(Ethernet module)을 사용하는 방법, Wifi를 연결하는 방법, …

+ 여기를 클릭

Source: it-g-house.tistory.com

Date Published: 2/24/2022

View: 1117

[아두이노 강좌] WIFI ESP8266(ESP-01) 모듈 사용방법 알아보기

안녕하세요 에듀이노 입니다. 오늘은 WIFI 모듈에서 가장 보편적인 모델중 하나인 ESP8266(ESP-01) 모듈을 사용하는 …

+ 여기를 클릭

Source: m.blog.naver.com

Date Published: 2/17/2022

View: 8280

아두이노 – 와이파이, ESP01 wifi 모듈 무선 원격제어 그리고 …

이번 글에서는 아두이노 와이파이(wifi) 모듈 ESP-01을 이용하여 wifi AP를 설정하고 스마트폰과 wifi AP 연결을 통한 데이터 전송과 와이파이로 수신 …

+ 여기에 자세히 보기

Source: postpop.tistory.com

Date Published: 9/6/2021

View: 4195

[아두이노] 와이파이 모듈 ESP8266(ESP-01) 사용법

얼마 전 디바이스 마트에서 아두이노 와이파이 모듈인 ESP8266 시리얼 와이파이 모듈 ESP-01을 구매했습니다. 와이파이 기능을 구현해야 해서 …

+ 여기에 표시

Source: popcorn16.tistory.com

Date Published: 9/28/2021

View: 1996

【 아두이노모듈#25】ESP8266 esp-01 활용하기#1 : 펌웨어 …

ESP8266은 wifi 통신을 이용하고 인터넷(네트웍)이나 직접 연결(무선)로 제어가 가능한 모듈이며, cpu, 메모리, 입출력 핀을 내장하고 있어서 아두이노 …

+ 여기에 자세히 보기

Source: rasino.tistory.com

Date Published: 4/3/2021

View: 2037

ESP8266 Wifi 모듈/ESP-01/Arduino/아두이노/와이파이

ESP8266 Wifi 모듈/ESP-01/Arduino/아두이노/와이파이 … 전체 상세정보는 PC에서 확인해 주시기 바랍니다. 직거래 유도 주의 안내 판매자가 현금결제를 유도하는 경우 절대 …

+ 자세한 내용은 여기를 클릭하십시오

Source: shopping.interpark.com

Date Published: 7/9/2022

View: 9421

와이파이 모듈 ESP8266 아두이노 WIFI ESP-01 – 11번가

– 최근 3개월의 배송데이터 기반으로 분석하여 예측된 배송완료 예상률입니다. – 판매자, 택배사 사정으로 예측치와 다를 수 있습니다. 닫기.

+ 여기에 자세히 보기

Source: www.11st.co.kr

Date Published: 1/25/2021

View: 3594

ESP01 (ESP8266) 사용하기 – 조대협

아두이노 WIFI 모듈은 여러가지가 있는데, 아두이노용으로 나온 와이파이 실드의 경우에는 가격이 비싸다. (아두이노에서 WIFI 연결하는 방법은 …

+ 여기를 클릭

Source: bcho.tistory.com

Date Published: 6/4/2022

View: 1163

아두이노 WIFI 킷트 – 엘레파츠

개발보드/프로그래머 > 오픈소스H/W > 아두이노 > 키트 아두이노 WIFI 킷트 Arduino UNO R3(정품), NDsocket(WIFI모듈)을 이용하며 WIFI로 LED를 제어할 수 있는 키트 …

+ 더 읽기

Source: eleparts.co.kr

Date Published: 9/27/2021

View: 4593

주제와 관련된 이미지 아두 이노 wifi 모듈

주제와 관련된 더 많은 사진을 참조하십시오 [ESP8266] 드디어!! ESP8266을 인터넷에 접속 시켜보자!. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

[ESP8266] 드디어!! ESP8266을 인터넷에 접속 시켜보자!
[ESP8266] 드디어!! ESP8266을 인터넷에 접속 시켜보자!

주제에 대한 기사 평가 아두 이노 wifi 모듈

  • Author: 러봇랩
  • Views: 조회수 23,816회
  • Likes: 좋아요 206개
  • Date Published: 2019. 2. 27.
  • Video Url link: https://www.youtube.com/watch?v=3XhPvLlpggo

아두이노(Arduino) 인터넷 하기 – Wifi (ESP-01: ESP8266)연결하는 방법

아두이노(Arduino)로 인터넷을 연결하는 방법은 랜선(LAN)을 연결하는 방법인 이더넷 모듈(Ethernet module)을 사용하는 방법, Wifi를 연결하는 방법, 3G/LTE를 연결하는 방법이 있습니다. 지난 포스팅까지 주로 이더넷 모듈을 사용한 방법을 알아보았는데 사실 랜선(LAN) 선을 연결하는 것도 여간 귀찮은 게 아니죠 ㅎㅎ 그리고 저의 궁극적인 목표는 완전 무선인 형태로 프로젝트 완제품을 만드는 것이기 때문에 Wifi를 사용하는 방법을 알아보려고 합니다. 오늘은 Wifi 사용에 필요한 ESP-01 (ESP8266)모듈과 연결하는 방법에 대해서 알아보겠습니다. 앞서 말한 다른 인터넷 연결 방법 및 ENC28J60 이더넷 모듈 사용법에 관해서는 아래 링크 참조 부탁드립니다.

1. ESP8266 와이파이 모듈(Wifi module)

아두이노의 일반보드에는 기본적으로 내장된 와이파이 칩이 없기 때문에 와이파이 모듈을 사용합니다. 주로 ESP8266 와이파이를 많이 사용하는데 ESP8266 칩셋을 사용하기 때문에 ESP8266 와이파이 모듈이라고 합니다. 온라인상에서 검색하면 ESP-01 제품을 가장 많이 찾을 수 있으나 ESP 시리즈는 ESP-14까지 출시되어 있습니다. 기획하시는 프로젝트에 맞는 제품버전을 구입하여 다양한 사양과 기능을 활용하실 수 있습니다. 가격이 저렴하고 가장 보편적으로 사용할 수 있는 모델은 ESP-01이며 제가 기획한 프로젝트도 데이터 정도만 간단히 주고받으면 되기 때문에 ESP-01 모듈로도 충분히 잘 사용하고 있습니다.

아두이노 인터넷하기: ESP8266 Wifi module

ESP-01 802.11b/g/n Wi-Fi 모듈 구동 전압 (Operating voltage) 3.0V ~ 3.6V Power (Typical Values) Average: ~ 71mA, Peak: 300mA (Continuous Transmission) Power (절전 모드) Min. 20uA Interface UART/GPIO 지원 동작 명령어 UART AT command UART 전송 속도 Max. 4Mbps SPI Flash 8Mbit Default Frequency Range 2412 ~ 2484MHz 프로세서 속도 (Processor speed) Max. 160MHz Operating Temperature -20℃ ~ 85℃ Storage Environment -40℃~ 90℃, < 90%RH 2. ESP-01 와이파이 모듈(Wifi module) 배선 ESP-01 모듈 PIN 배열 ESP-01 모듈은 단순하게 생긴 것과 다르게 사용 방법이 좀 복잡합니다. 일단 배선이 복잡한데.. 위의 표에서 볼 수 있듯이 전류 소모량이 많고, TX와 RX 신호가 5V출력이기 때문에 아두이노 보드 pin에 바로 연결하면 정상적으로 작동이 안 되고 모듈이 고장 날 수도 있습니다. 또 하나의 문제는 아두이노와 보레이트(Baudrate) 9600 bps 속도로 시리얼 통신(Serial communication)을 주고 받아야 하는데 ESP-01 모듈은 115200 bps로 초기 설정되어 있습니다. 에?? 그럼 어떻게 하냐고요? ㅠ 그래서 펌웨어(Firmware)를 업데이트해서 모듈의 속도를 변경해야 하는 과정이 필요하다고 인터넷에 찾아보면 나오는데.. 과정이 좀 복잡합니다. 그리고 이러한 여러 가지 문제를 해결하는 보완책으로 저항을 사용해야 하거나 아래와 같이 복잡한 배선을 구성해야 합니다. ESP-01(ESP8266) Wifi module 펌웨어 업데이트(firmware update)를 위한 배선 출처: https://www.elec-cafe.com/esp8266-esp-01-firmware-update/ 아.. 복잡하죠... ㅠㅠ 뭐 할 때마다 이렇게 복잡해서야... 그래서~!! 복잡한 거 싫어하는 저는 방법을 찾았습니다!! 바로 ESP-01 어댑터라는 모듈을 사용하는 겁니다. 복잡한거 싫어하고 빵판으로 배선하는 것을 싫어하는 저를 위한 아주 유용한 아이템입니다. ESP-01 모듈을 어댑터에 연결하기만 하면 동작전압을 5V로 사용해야 하는 점 말고는 어댑터의 4 Pin(VCC, GND, RX, TX) 만으로 훨씬 편하게 배선을 할 수 있습니다. 어댑터를 사용하면 펌웨이 업데이트도 안해도 됩니다!! 완전~꿀!ㅎㅎㅎ 아두이노(Arduino) 인터넷 연결하기: ESP-01(ESP8266) 와이파이 모듈(Wifi module)과 어댑터 ESP-01 와이파이 모듈을 방향에 맞게 어댑터에 꼽고 어댑터 VCC 핀은 아두이노의 5V, GND는 GND와 연결합니다. 그리고 TX와 RX pin은 각각 아두이노의 2번 Pin과 3번 Pin에 연결합니다. 어? 왜 아두이노의 RX-pin0, TX-pin1에 맞춰서 연결하지 않나요? 맞습니다. 아두이노가 스케치를 통해 신호를 받을 때나 PC로 코딩된 프로그램을 업로드받을 때 시리얼 통신을 사용한다고 아실 겁니다. TX와 RX는 각각 Transmit(전송), Receive(수신)이란 뜻으로 시리얼 통신을 할 때 데이터를 전송하고 수신하는 통로가 됩니다. 그래서 이미 아두이노에 USB가 연결되어 있는 동안은 아두이노의 TX와 RX는 PC와 연결되어 있어서 아두이노와 ESP-01 와이파이 모듈 사이의 시리얼 통신을 위해 새로운 RX, TX를 디지털 Pin2번과 3번에 각각 지정을 해야 합니다. 실제로 아두이노의 RX-pin0, TX-pin1에 연결하고 프로그램을 업로드하면 정상적으로 업로드되지 않습니다. 그리고 주의하실 점은 전송(TX)---> 수신(RX) 짝으로 연결해야 합니다. ESP-01 모듈에서 전송(TX)한 데이터를 아두이노에서 수신(RX)하는 거고 또 반대로도 이뤄지기 때문입니다.

아두이노(Arduino) 인터넷 연결하기: ESP-01(ESP8266) 와이파이 모듈(Wifi module) 어댑터 배선

3. ESP-01 와이파이 모듈(Wifi module) 프로그램 코딩

아두이노와 ESP-01 와이파이 모듈을 위 그림과 같이 연결한 후 몇 가지 설정을 위해 간단한 프로그램 업로드가 필요합니다. 우선 아래 코드블럭과 같이 스케치(Sketch)로 코딩 후 아두이노에 업로드합니다.

앞서 언급하였듯이 ESP-01 모듈은 통신속도(Baudrate: 보레이트)가 115200 bps로 초기 설정되어 있기 때문에 ‘mySerial.begin(115200);’ 명령어에 115200이 우선 들어갑니다. 그러나 아두이노와 ESP-01 모듈이 통신을 하려면 둘의 통신속도를 맞춰야 하기 때문에 9600으로 변경하는 작업을 진행해야 합니다. (뒤에 설명)

#include SoftwareSerial mySerial(2,3); //RX, TX void setup() { Serial.begin(9600); mySerial.begin(115200); } void loop() { if(mySerial.available()) { Serial.write(mySerial.read()); } if(Serial.available()) { mySerial.write(Serial.read()); } }

아두이노와 ESP-01간에 통신은 UART(범용 비동기화 송수신기: Universal asynchronous receiver/transmitter)를 사용하는데.. UART는 “병렬 데이터의 형태를 직렬 방식으로 전환하여 데이터를 전송하는 컴퓨터 하드웨어의 일종이다.”라고 위키피디아에 나와있습니다. 그냥 시리얼 통신 일종이라 생각하면 마음이 편합니다. ㅎㅎ 여기서 사용되는 명령어가 AT command입니다.

그래서 업로드가 완료된 후 시리얼 모니터(Serial Monitor)를 통해 PC에서 아두이노를 거쳐 ESP-01 모듈에 ‘AT command’로 명령을 하여 필요한 설정 및 와이파이를 구동할 수 있습니다.

먼저 정상적으로 작동하는지 확인하기 위해 시리얼 모니터 상단의 입력란에 AT라고 입력합니다. 그럼 아래와 같이 OK라고 반응을 보입니다. 잠깐!! AT를 입력하기 전에 보레이트는 9600에 맞춰주시고(프로그램상에서 아두이노는 9600), 옆에 칸을 ‘Both NL & CR’로 설정을 변경해줘야 합니다. NL은 ‘Newline’ 약자이고, CR은 ‘Carriage return’ 약자입니다. 이렇게 두어야 return 값이 아래 줄에 출력됩니다.

아두이노(Arduino) ESP8266(ESP-01) 와이파이 모듈 사용하기: AT command 확인

OK 보셨나요? ㅎㅎ 이제 거의 다 했어요~ 그럼 ESP-01 모듈의 통신속도를 변경하기 위해 AT+UART_DEF=9600,8,1,0,0라고 입력합니다.

아두이노(Arduino) ESP8266(ESP-01) 와이파이 모듈 통신속도(baudrate) 변경하기

OK~!! 이제 ESP-01 모듈의 통신속도가 변경되었기 때문에 지금은 입력해도 아무 반응이 없을 겁니다. 그래서 스케치에서 아까 115200이었던 통신속도를 9600으로 변경 후 다시 아두이노로 업로드합니다.

아두이노 프로그램 ESP-01 모듈 속도 변경

그리고 다시 시리얼 모니터에 AT를 입력하면 역시나 OK로 잘 응답을 해줍니다. ^^ 그럼 이제 와이파이에 접속해 볼까요? AT+CWLAP 명령어는 주변 Wifi 목록을 검색해주는 명령어입니다. 아마 입력하면 바로 진행될 수도 있지만 안되시는 분들은 AT+CWMODE? 명령어로 현재 모드가 몇 번인지 확인하고 AT+CWMODE=1이라고 입력하셔서 모드를 변경합니다.

아두이노(Arduino) ESP8266(ESP-01) 와이파이 모듈 모드(MODE) 변경하기

ESP8266 와이파이 모듈은 네트워크 연결에 대해 3가지 모드를 제공합니다.

1. Station mode: ESP8266 모듈이 client로 wifi 기능만 함

2. AP mode: ESP8266 모듈이 Access Point가 됨

3. AP + Station mode: AP와 client 둘 다 됨

그래서 일반적으로 사용하실 때 모드는 1번으로 설정하면 됩니다. 그럼 다시 AT+CWLAP로 주변 Wifi 목록을 검색해 볼까요? 짠~!! 주변에 접속할 수 있는 와이파이를 찾을 수 있습니다.

아두이노(Arduino) ESP8266(ESP-01) 주변 와이파이 찾기

와이파이 접속 명령어는 AT+CWJAP=”SSID”,”비밀번호” 라고 입력하시면 됩니다. 그럼 정상적으로 접속이 되면 “WIFI CONNECTED, WIFI GOT IP”라고 응답이 출력됩니다. 그리고 할당된 IP를 확인하려면 AT+CIFSR 명령어를 입력하면 아래와 같이 IP 주소를 확인할 수 있습니다. 이제 와이파이가 됩니다~ 호~우!! ㅎㅎ

아두이노(Arduino) ESP8266(ESP-01) 와이파이 접속 및 IP 주소 확인하기

명령어 기능 설명 응답 AT AT command 작동 상태 확인 OK or 무응답 AT+RST 재시작 (Reset) OK… ready AT+UART_DEF=속도,8,0,0 AT 통신속도 변경 OK AT+CWMODE? Wifi 모드 확인 ‘+CWMODE: mode# AT+CWMODE=mode# Wifi 모드 설정 (ex> AT+CWMODE=1) OK AT+CWLAP 접속 가능한 Wifi 목록 검색 Wifi 목록 AT+CWJAP? 접속된 Wifi 확인 AT+CWJAP=”SSID”,”비밀번호” Wifi 접속 WIFI CONNECTED

WIFI GOT IP

OK AT+CWQAP Wifi 접속 종료 OK

WIFI DISCONNECT AT+CIFSR IP 주소 확인 +CIFSR: STAIP, “할당된 IP주소”

+CIFSR: STAMAC, “MAC주소”

여기까지 아두이노(Arduino)로 인터넷(Internet) 연결하는 방법 중 ESP-01 와이파이 모듈(ESP8266 Wifi module)을 사용하는 방법을 알아보았습니다. 인터넷도 되고, DB(Database)서버도 만들었고, 이제 거의 모든 준비가 되었습니다. 다음 포스팅에는 드디어!! 웹으로 데이터를 보내서 DB서버에 저장하는 방법에 대해 알아보도록 하겠습니다. 웹서버, DB서버 만드는 방법이 궁금하신 분은 아래 링크 참조 부탁드려요 ^^

오늘도 긴 글 읽어 주셔서 감사합니다. 궁금한 내용이나 추가적으로 원하시는 내용 있으면 언제든지 댓글로 남겨주세요~ 감사합니다.

[아두이노 강좌] WIFI ESP8266(ESP-01) 모듈 사용방법 알아보기

3.1 준비물

▶ 실습에 앞서 준비물이 필요합니다.

(링크를 클릭하면 해당 제품 페이지로 이동합니다.)

아두이노 우노 (DIP) : 링크 클릭

WIFI ESP8266(ESP-01) 모듈 : 링크 클릭

브레드보드 400홀(불투명) : 링크 클릭

점퍼 케이블 : 링크 클릭

저항(1K옴) : 링크 클릭

(저항은 1K옴을 사용하며 자세한 설명은 아래 ‘3.3 WIFI ESP8266 연결하기’에서

확인할 수 있습니다. )

3.2 ESP8266 초기 설정하기(펌웨어 업데이트)

▶ 아두이노 우노 보드와 WIFI ESP8266(ESP-01) 모듈의 연결은 시리얼 통신을 이용합니다.

우노 보드는 시리얼 통신핀을 1개만 가지고 있는데, 이 시리얼 통신핀을 PC와 통신하는데

이용됩니다. 이런 이유로 우노 보드와 WIFI ESP8266(ESP-01) 모듈의 통신을 위해서는 우노

보드의 디지털핀을 시리얼 통신핀으로 변경해 사용하는 ‘SoftwareSerial’ 방법을 이용해야

합니다.

ESP8266 모듈은 초기 통신 속도가 115200bps로 설정되어 있는 반면, ‘SoftwareSerial’은

통신 속도를 57600bps까지만 지원하므로 본 예제에서는 ESP8266 모듈의 통신 속도를

9600bps로 변경해서 사용합니다.

먼저 초기 설정을 하기 전, 아래와 같이 회로를 구성하고 필요한 프로그램을 다운로드 받습니다.

※ 통신 속도 변경은 초기에 한 번만 하고 계속 사용할 수 있습니다.

통신핀이 2개 이상인 아두이노 메가(Mega), 듀에(Due) 보드를 이용하면

(초기 설정 없이) 바로 사용이 가능합니다.

아두이노 – 와이파이, ESP01 wifi 모듈 무선 원격제어 그리고 시리얼 통신 – 6편

이번 글에서는 아두이노 와이파이(wifi) 모듈 ESP-01을 이용하여 wifi AP를 설정하고 스마트폰과 wifi AP 연결을 통한 데이터 전송과 와이파이로 수신된 데이터를 시리얼 통신을 통해 아두이노에서 받고 코드를 실행하는 원격제어를 할 수 있도록 코딩해 보자.

ESP-01 pin map

아두이노와 연결하기

TX -> 아두이노 RX

RX -> 아두이노 TX

VCC -> 아두이노 3.3V

CH_PD -> 아두이노 3.3V

GND -> 아두이노 GND

아두이노의 출력 핀 TTL 전압은 5V이고 ESP-01 모듈은 3.3V이다. 따라서 아두이노 TX핀에서 출력되는 신호 전압을 TTL 레벨 쉬프트를 통해 ESP-01 모듈의 RX 핀에 3.3V의 신호 전압으로 변경해주어야 하지만, 테스트상에서는 별 문제가 없어서 아래와 같이 TTL 레벨 쉬프트 없이 연결하였다. 이 연결 방식은 장시간 사용 시 ESP-01 모듈에 손상을 줄 가능성이 있다.

장시간 사용할 예정이라면 아두이노 TTL 레벨 쉬프트를 검색하여 적용하기 바란다.

연결을 하였다면 AT command를 통해 정상 작동 여부를 확인해 보자.

아래 파일을 아두이노에 업로드해준다.

#include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); void setup() { Serial.begin(115200); //시리얼 모니터 esp01.begin(115200); //와이파이 시리얼 } void loop() { if (esp01.available()) { Serial.write(esp01.read()); //블루투스 측 내용을 시리얼 모니터에 출력 } if (Serial.available()) { esp01.write(Serial.read()); //시리얼 모니터 내용을 블루투스 측에 쓰기 } }

ESP-01의 기본 baud rate는 115200이다. 현재 상태의 작동 여부를 확인하기 위해 하드웨어와 소프트웨어 시리얼 baud rate를 둘 다 115200으로 맞추어 주었다. 115200으로 해놓아도 AT command의 사용에는 지장이 없다.

아두이노 시리얼 모니터의 전송 옵션을 Both NL & CR, 보드 레이트를 115200으로 맞추어 주고 아두이노 시리얼 모니터 입력창에 AT를 입력하고 엔터를 친다.

응답으로 OK가 들어온다면 기기의 정상작동과 연결이 잘 되었음을 확인할 수 있다. 아래 그림처럼 수신된 데이터에 읽을 수 없는 문자가 섞여 있을 수 있다. 하지만 OK만 확인된다면 문제는 없다.

아두이노에서 softwareSerial을 통해 안정적으로 사용하기 위해서는 baud rate를 9600으로 변경해야 한다.

ESP-01의 baud rate를 변경하는 방법으로는 기본 baud rate가 9600으로 설정된 펌웨어를 모듈에 업데이트하는 방법과 AT command를 사용하여 변경해주는 방법이 있는데 이 글에서는 AT command를 사용하여 진행하겠다. 펌웨어 업데이트에 관해서는 인터넷상에 관련 글들이 많이 있으므로 참조하길 바란다.

아두이노 시리얼 모니터 입력창에 AT+UART_DEF=9600,8,1,0,0 를 복사한 뒤 붙여 넣고 엔터를 쳐준다.

아래처럼 OK 응답이 표시된다면 ESP-01의 baud rate가 9600으로 변경된 것이다.

ESP-01의 baud rate가 9600으로 변경되었으니 위의 코드의 baud rate를 115200에서 9600으로 아래 그림과 같이 변경해주고 업로드한다. 그리고 시리얼 모니터의 보드 레이트도 9600으로 변경한 뒤 AT를 입력하여 정상 작동 여부를 확인하면 준비는 끝나게 된다.

확인이 되었으면 스케치 상 보드 레이트를 9600 상태에서 저장을 시켜놓자. 이제 보드 레이트 115200은 사용하지 않게 된다.

ESP-01 wifi 모듈을 이용한 아두이노 원격제어의 방법은 아래와 같다.

ESP-01 모듈을 soft AP로 설정(공유기 기능)하여 스마트폰의 wifi가 AP의 ip로 연결할 수 있게 하고 또한, server로 설정하여 soft AP 통해 연결된 스마트폰이 server로 웹페이지를 요청할 수 있도록 하게 된다. 이렇게 함으로써, 만약 서버의 ip가 192.168.4.1로 설정되었을 경우, 스마트폰 웹브라우저 주소창에 http://192.168.4.1/on 입력하여 서버에 on 페이지에 대한 요청을 할 수 있게 된다. 이때 ESP-01 모듈은 들어온 웹페이지 요청 값을 시리얼 통신을 통해 아두이노에 전송하게 되고 아두이노는 수신된 웹페이지 요청 값을 코드에 따라서 원격제어에 필요한 on 만을 분리해내고 그 값에 해당하는 코드를 실행시켜 아두이노 원격제어를 구현하게 된다. 만약 on에 대한 응답 코드가 아두이노에 설정되어 있다면 아두이노는 시리얼 통신을 통해 ESP-01 모듈에 웹페이지 요청에 대한 응답을 보내라고 명령하게 되고 ESP-01 모듈은 그 명령에 따라 스마트폰에 응답을 보내게 된다. 이러한 과정을 통하여 스마트폰과 아두이노 간의 원격제어용 데이터 송신 및 수신이 이루어지게 된다.

상기의 작업을 수행할 수 있도록 ESP-01를 설정하는데 필요한 AT command에 대해 살펴보자.

AT+RST // ESP-01 리셋 AT+CWMODE=2 // 1 = Station mode (client), 2 = AP mode (host), 3 = AP + Station mode AT+CWSAP=”esp01″,”1234test”,5,3 // AT+CWSAP= softAP SSID, Password, channel id, ecn ecn(보안설정) : 0 = OPEN, 2 = WPA_PSK, 3 = WPA2_PSK, 4 = WPA_WPA2_PSK AT+CIFSR // AP IP 주소 AT+CIPMUX=1 // 0: Single connection, 1: Multiple connections (0 ~ 4), 서버 설정 시 “1” 강제 사항 AT+CIPSERVER=1,80 // AT+CIPSERVER= mode, port mode: 0: Delete server, 1: Create server, port number

상기의 AT command를 앞서 보드 레이트 변경 시와 같이 주석 앞부분을 복사하여 차례대로 아두이노 시리얼 모니터 입력창에 붙여 넣기 한 뒤 엔터를 치면 아래와 같이 ESP-01 모듈이 설정되는 것을 볼 수 있다.

ESP-01 모듈의 soft AP의 기본 설정 ip 주소는 192.168.4.1이다. 현재 soft AP의 주소가 기본 설정값인 192.168.4.1 임을 확인할 수 있다.

스마트폰에서 wifi 장치를 켜게 되면 상기에서 설정한 대로 SSID “esp01″이 검색될 것이다. 클릭하고 설정해 놓은 비밀번호를 입력하고 연결해 보자. 연결 후 네트워크 설정 관리에 들어가 보면 스마트폰이 할당받은 ip 주소를 확인할 수 있다. 아두이노 원격제어에서 우리가 할당받은 ip주소를 사용할 일은 거의 없다. 단지, soft AP의 주소와 비슷하여 혼동을 방지하기 위해 확인이 필요한 것뿐이다.

스마트폰이 soft AP에 접속이 되면 아래와 같이 시리얼 모니터상에 connection id: 0이 연결됐다는 표시와 +IPD,0,459:GET /hi HTTP/1.1 수신 데이터가 표시되고, 접속장비와 soft AP의 ip 주소를 확인할 수 있고 데이터 수신 후에 id 0번의 연결을 끊은걸 확인할 수 있다.

데이터의 수신

+IPD,0,158:GET / HTTP/1.1 // +IPD,id,len:GET /data HTTP/1.1 // id: id no. of connection, len: data length, data: data received

“+IPD,0,158:GET /” 이하가 수신된 데이터이다. 수신 시에는 AT+CIPMUX=1 옵션 설정에 따라 멀티 커넥션 id 0부터 4까지 자동으로 할당되어 사용하게 되며 수신이 완료되면 자동으로 연결을 닫게 되는데 연결을 닫기 전에 수신되는 데이터는 다른 커넥션 id로 자동 할당되어 수신되는 걸 테스트를 통해 확인할 수 있었다.

데이터의 전송

AT+CIPSEND=0,30 AT+CIPSEND=length // normal send (single connection). AT+CIPSEND=id,length // normal send (multiple connection), id: ID no. of connection, length: data length, MAX 048 bytes AT+CIPCLOSE=0 // id: ID no. of connection to close, Close TCP or UDP connection.For multiply connection mode

ESP-01을 통해 데이터 송신 시에는 아두이노에서 시리얼 통신을 통해 상기의 데이터 전송 AT command를 사용하여 전송 데이터와 함께 보내야만 데이터가 스마트폰으로 전송된다. 시리얼 통신으로 연결된다는 것 자체가 데이터의 전송 속도에 제한을 걸게 되는데, 이 상황에 더불어 모듈이 AT command를 수신하고 작동하는 시간이 소요되게 되어 아두이노에서 어떤 작동의 응답으로 ESP-01 모듈의 wifi를 통해 데이터 전송할 경우 약 1초 에서 2초의 시간이 걸리게 된다. 이 얘기는 짧은 시간 동안 연속되는 데이터의 전송하는 데 있어서 문제를 야기하게 된다고 할 수 있다. 필자는 ESP-01의 이러한 데이터 전송 특성 때문에 발생하는 사용의 불편함(긴 응답 시간)에 따라 이 기능의 효용성이 낮다고 보아 아두이노에서 스마트폰으로 데이터를 전송하는 기능을 아예 사용하지 않기로 하였다.

상기와 같이 아두이노 시리얼 모니터를 통해 ESP-01을 일일이 설정하는 것은 많이 불편하다. 코드상에서 아두이노 실행 시 자동으로 설정되도록 하는 코드를 인터넷에서 쉽게 찾아볼 수 있었고 이를 이용하기로 한다.

주요 코드를 아래와 같이 코딩해 주었다.

String sendData(String command, const int timeout, boolean debug) { // 스트링 타입 AT command 전송 함수 String response = “”; // 스트링 타입 지역변수 선언 및 초기화 esp01.print(command); // ESP-01 모듈에 스트링 타입의 AT command 전송 long int time = millis(); while( (time+timeout) > millis()) { // ESP-01 모듈의 명령 실행 후 응답에 필요한 시간이 경과되면 while(esp01.available()) { // 시리얼 버퍼에 ESP-01 모듈의 응답을 있을 경우 char c = esp01.read(); // 1byte 데이터를 char타입 변수 c에 저장 response+=c; // c에 저장된 문자를 문자열로 변경 } } if(debug) Serial.print(response); // debug가 참이면 시리얼 모니터에 출력 return response; }

전송 실행 함수: sendData(문자열 명령, 응답에 필요한 시간, 시리얼 모니터 출력 플래그);

sendData(“AT+RST\r

“,2000,DEBUG); //리셋 sendData(“AT+CWMODE=2\r

“,1000,DEBUG); // configure as access point (working mode: AP+STA) sendData(“AT+CWSAP=\”ESP-01\”,\”1234test\”,11,3\r

“,1000,DEBUG); // join the access point sendData(“AT+CIFSR\r

“,1000,DEBUG); // get ip address sendData(“AT+CIPMUX=1\r

“,1000,DEBUG); // configure for multiple connections sendData(“AT+CIPSERVER=1,80\r

“,1000,DEBUG); // turn on server on port 80

상기 코드 중 wifi 연결 시 비밀번호 연결을 비활성화하고자 한다면 아래처럼 3을 0으로 변경해주면 된다.

sendData(“AT+CWSAP=\”ESP-01\”,\”1234test\”,11,0\r

“,1000,DEBUG);

이제 수신 데이터를 필요한 값만 추출해내는 parsing에 대해 살펴보겠다.

parsing을 하기 위해서는 String class를 활용해야만 한다.

상기 AT command 설정 테스트에서 데이터 수신이 +IPD,0,158:GET / HTTP/1.1 형식으로 들어온 걸 확인했었다.

만약 웹브라우저에서 http://192.168.4.1/hi라고 입력하면 +IPD,0,459:GET /hi HTTP/1.1 데이터가 수신될 것이다. 즉, 모든 데이터 수신에는 +IPD,0,158:GET / 형식의 코드가 선행된다. 데이터 수신의 확인을 위해 “+IPD,”를 이용하여 하기로 하자.

if (esp01.find(“+IPD,”)) { // 만약 시리얼 버퍼에 “+IPD, “가 있으면, “+IPD,”가 확인될 경우 “+IPD,”는 삭제된다.

수신 데이터를 스트링 타입 income_wifi 변수에 저장해 주면 “0,158:GET / HTTP/1.1″라는 스트링이 저장된다.

income_wifi = esp01.readStringUntil(‘\r’); // 스트링 타입 income_wifi 변수에 ‘\r’ 문자까지 저장 웹브라우저 주소 끝에는 자동으로 ‘\r’ 문자가 붙는다.

필요한 data는 “GET /” 이후에 들어오고 종료 문자 역할을 하는 “HTTP/1.1″의 앞 공백 문자에서 끝나게 된다.

String class에서는 스트링 중의 일부를 떼어내어 저장할 수 있는 string.substring(start index, end index); 함수를 제공하고 있으며, 저장할 스트링의 시작 인덱스 번호와 종료 인덱스 번호를 필요로 한다. 이 함수를 이용하기 위해 “GET /”와 “HTTP/1.1″의 인덱스 번호를 알아내 보자.

income_wifi 스트링에서 “GET /”의 시작 인덱스 위치를 확인하는 코드는 income_wifi.indexOf(“GET /”)가 되고 “HTTP/1.1″의 시작 인덱스 위치를 확인하는 코드는 income_wifi.indexOf(“HTTP/1.1”)가 된다.

인덱스 번호를 사용하여 스트링에서 특정 위치의 스트링을 추출해내는 코드는 아래와 같게 된다.

income_wifi.substring(income_wifi.indexOf(“GET /”)+5, income_wifi.indexOf(“HTTP/1.1”)-1);

income_wifi.indexOf(“GET /”)는 “GET /”의 시작 인덱스 번호를 반환한다. 그러므로 필요한 위치의 인덱스 번호는 “GET /”의 글자 수 5를(공백 문자 포함) 더한 위치 값이 되게 된다.

income_wifi.indexOf(“HTTP/1.1”)는 “HTTP/1.1″의 시작 인덱스 번호를 반환한다. 하지만 앞에 공백 문자(space)가 있으므로 -1을 해준 위치 값이 필요로 하는 위치 값이 되고, 상기의 코드에서는 data가 없으므로 두 위치 값은 같은 값일 것이다.

아래 코드를 아두이노에 업로드하고 스마트폰에서 soft AP에 접속해 보자.

#include #define DEBUG true String income_wifi = “”; SoftwareSerial esp01(2,3); void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(“AT+RST\r

“,2000,DEBUG); // reset module sendData(“AT+CWMODE=2\r

“,1000,DEBUG); // configure as access point (working mode: AP+STA) sendData(“AT+CWSAP=\”ESP-01\”,\”1234test\”,11,0\r

“,1000,DEBUG); // join the access point sendData(“AT+CIFSR\r

“,1000,DEBUG); // get ip address sendData(“AT+CIPMUX=1\r

“,1000,DEBUG); // configure for multiple connections sendData(“AT+CIPSERVER=1,80\r

“,1000,DEBUG); // turn on server on port 80 } void loop() { if (esp01.available()) { if (esp01.find(“+IPD,”)) { income_wifi = esp01.readStringUntil(‘\r’); String wifi_temp = income_wifi.substring(income_wifi.indexOf(“GET /”)+5, income_wifi.indexOf(“HTTP/1.1”)-1); Serial.println(wifi_temp); } } } String sendData(String command, const int timeout, boolean debug) { String response = “”; esp01.print(command); // send the read character to the esp01 long int time = millis(); while( (time+timeout) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } } if(debug) Serial.print(response); return response; }

스마트폰 웹브라우저 주소창에서 192.168.4.1/hi를 입력하고 연결을 클릭하면 아래와 같이 시리얼 모니터에 hi가 표시된 것을 볼 수 있다.

앞에서 살펴본 AT command 설정 시에는 스마트폰 접속 시 관련 정보들이 시리얼 모니터에 출력되었었지만 지금은 data를 제외한 모든 값은 출력이 안되게 된다.

이렇게 추출된 스트링 데이터를 이용하여 LED의 제어를 할 수 있게 된다.

아래와 같이 아두이노 기본 LED를 웹브라우저를 통해 제어할 수 있도록 스트링 LED 제어 코드를 추가해 주었다.

업로드하고 스마트폰 웹브라우저에 http://192.168.4.1/on을 입력하면 LED가 켜지는 것을 볼 수 있고 http://192.168.4.1/off를 입력하면 LED가 꺼지는 것을 볼 수 있다. “on” 또는 “off”가 아닌 텍스트를 입력한다면 시리얼 모니터에 출력된다.

#include #define DEBUG true #define ledPin 13 String income_wifi = “”; SoftwareSerial esp01(2,3); void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different pinMode(ledPin, OUTPUT); sendData(“AT+RST\r

“,2000,DEBUG); // reset module sendData(“AT+CWMODE=2\r

“,1000,DEBUG); // configure as access point (working mode: AP+STA) sendData(“AT+CWSAP=\”ESP-01\”,\”1234test\”,11,0\r

“,1000,DEBUG); // join the access point sendData(“AT+CIFSR\r

“,1000,DEBUG); // get ip address sendData(“AT+CIPMUX=1\r

“,1000,DEBUG); // configure for multiple connections sendData(“AT+CIPSERVER=1,80\r

“,1000,DEBUG); // turn on server on port 80 } void loop() { if (esp01.available()) { if (esp01.find(“+IPD,”)) { income_wifi = esp01.readStringUntil(‘\r’); String wifi_temp = income_wifi.substring(income_wifi.indexOf(“GET /”)+5, income_wifi.indexOf(“HTTP/1.1”)-1); if(wifi_temp == “on”){ // wifi_temp는 지역변수로서 “if (esp01.find(“+IPD,”)){} 함수를 나가면 초기화됨. digitalWrite(ledPin, HIGH); } else if(wifi_temp == “off”){ digitalWrite(ledPin, LOW); } else { Serial.println(wifi_temp); } } } } String sendData(String command, const int timeout, boolean debug) { String response = “”; esp01.print(command); // send the read character to the esp01 long int time = millis(); while( (time+timeout) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } } if(debug) Serial.print(response); return response; }

이제 웹브라우저를 이용하는 대신 안드로이드 앱을 이용하여 원격제어를 해보자.

arduino bluetooth controller PWM 안드로이드 앱의 wifi를 이용한 원격제어용 데이터 전송 프로토콜은 다음과 같이 코딩해 주면 된다.

디지털 버튼 제어 프로토콜: “%%F0” + 스트링 값 + “%%F1” 스트링 값 = “10” 버튼1 off, 스트링 값 = “11” 버튼1 on, “20” 버튼2 off, “21” 버튼2 on, …… PWM 값 프로토콜: 1번 슬라이드 “%%F31” + 스트링 값 + “%%F1” 2번 슬라이드 “%%F32” + 스트링 값 + “%%F1” 3번 슬라이드 “%%F33” + 스트링 값 + “%%F1”

상기 예제 코드에서는 스트링을 parsing 할 때 시작 문자열로서 “GET /” 종료 문자열로서 “HTTP/1.1″를 사용했다. 이들을 상기 프로토콜에 적용하여 코드를 바꾸어 주었다. 또한 스트링으로 데이터를 한 번에 받기 때문에 “%%F1″와 “%%F0″가 스트링에 있다면 그 데이터의 검증이 완료된 것으로 볼 수 있다. 앞선 블루투스 원격제어에서는 검증 시 여러 단계가 필요했으나 스트링으로 데이터를 한꺼번에 받을 경우 코드가 간단해진다.

if (income_wifi.indexOf(“%%F1”) != -1) { // 만약 스트링 중에 “%%F1” 있고 if (income_wifi.indexOf(“%%F0”) != -1) { // “%%F0” 있으면 디지털 버튼 상태 값 검증이 되어 String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F0”)+4, income_wifi.indexOf(“%%F1”)); // 값 저장 if (income_wifi.indexOf(“%%F31”) != -1) { // 만약 스트링 중에 “%%F31” 있고 if (income_wifi.indexOf(“%%F0”) != -1) { // “%%F0” 있으면 슬라이드 1 PWM 값 검증이 되어 String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F31”)+5, income_wifi.indexOf(“%%F1”)); // 값 저장

기타 프로토콜에 해당되지 않는 텍스트는 앞선 parsing 방법을 사용한다.

String wifi_temp = income_wifi.substring(income_wifi.indexOf(“GET /”)+5, income_wifi.indexOf(“HTTP/1.1”)-1);

앞선 설명중 데이터 수신에서 멀티 커넥션 id에 관해 언급했었다. ESP-01 모듈은 데이터 수신 시 5개의 id를 사용하여 연결을 하게 되는데 그 id 번호는 0부터 4까지이다. 상기에 링크를 걸었던 ESP-01 모듈 AT command 참조 사이트에 의하면 만약 0 ~ 4까지 모두 사용하고 있는 상태에서 추가 연결이 있을 경우(id 값이 5가 될 경우) 모든 연결은 끊긴다고 한다. 필자가 확인해 본 결과 모두 끊기면서 더 이상 연결이 되지 않는다. 이런 상황이 되었을 경우 데이터의 송 수신이 안되게 되어 닫힌 멀티커넥션 기능을 열기 위해서는 리셋을 해주어야만 했다.

추가로 설명하자면, 데이터 수신 시 id 0번부터 받게 되고 수신이 완료되면 id 0번의 연결을 끊는 것을 앞선 예제에서 확인했었다. id 0번의 연결이 끊기게 되면 이때 id 0번이 다시 데이터를 받을 수 있는 상태로 초기화 되게 된다. 만약 id 0번의 연결이 끊기 전에 데이터가 들어오게 된다면, 다음 id인 1번으로 넘어가게 되고 다시 id 0번이 끊겨 초기화가 되면 다시 id 0번으로 데이터를 수신하게 된다. 즉 연속된 데이터를 id 순서대로 받다가 앞선 번호에서 초기화가 되면 그 id를 우선 사용하게 된다. 수신되는 데이터 간격이 길어 id 0번이 수신 완료하고 초기화되었다면 계속에서 id 0번을 사용하게 된다. 문제는 id의 연결을 끊고 초기화시키는데 시간이 걸린다는 것이다. 데이터가 빠르게 연속으로 들어올 경우 id가 초기화되기 전에 id 0부터 id 4까지 모두 연결된 상태가 되어 모든 연결을 끊고 더 이상 데이터를 수신하지 못하는 현상이 발생하게 되었다.

이를 해결하기 위해서 데이터를 읽는 시간 간격을 강제하고 활성화된 id를 AT command를 통해 강제로 끊는 코드를 아래와 같이 추가해 보았으나 그것 만으로는 충분하지 않았다.

connectionId = income_wifi.charAt(0); unsigned long int one_millis = 0; void wifi_delay() { // 50 millis 마다 연결된 id 가 있으면 그 아이디를 종료시키고 데이터 수신확인 if (millis() – one_millis > 50) { one_millis = millis(); if (connectionId == ‘0’) esp01.write(“AT+CIPCLOSE=0\r

“); else if (connectionId == ‘1’) esp01.write(“AT+CIPCLOSE=1\r

“); else if (connectionId == ‘2’) esp01.write(“AT+CIPCLOSE=2\r

“); else if (connectionId == ‘3’) esp01.write(“AT+CIPCLOSE=3\r

“); else if (connectionId == ‘4’) esp01.write(“AT+CIPCLOSE=4\r

“); wifi_read(); } }

또 다른 문제로는 수신된 데이터 각각의 id로 분산되어 받게 될 경우 그 순서가 뒤바뀔 수 있다는 것이다. 한 개의 아이디로 연속된 데이터를 받는다면 순서는 뒤바뀌지 않는다. 모듈에서 멀티 커넥션 id 연결 시 데이터 수신 시점의 시간 값에 대한 검증은 하지 않는 것 같으며 마지막에 출력되어야 할 값이 그전 값보다 먼저 출력되는 현상을 여러 번 확인했다.

사실 wifi 연결에 대한 응답 server의 구동에 있어 멀티 커넥션 자체가 다중 접속을 고려한 것이지 한 사용자의 연속된 데이터를 전송받기 위한 구성은 아닐 것이라 생각되며 웹페이지 요청 순서는 중요하지 않을 것이다.

어찌 되었든지 간에 원격제어를 하기 위해서는 신뢰할 수 있는 값의 순서가 필요하고 이런 문제를 해결하기 위해서는 한 개의 id만을 사용하여 받을 수 있도록 스마트폰에서 데이터를 전송하는 간격을 늘려주는 방법 외에는 찾을 수가 없었다.

ESP-01 wifi 모듈로 원격제어를 하는것은 블루투스 모듈의 사용에 비해 적당한 방법은 아니라고 생각이 되나 연결거리가 블루투스 보다 길어 또한 필요하게 된다.

ESP-01 wifi 모듈의 특징을 이해하고 모듈의 성능에 맞게 필요 기능이 적용되도록 코딩해야 한다.

1. 데이터 전송 시 시리얼 통신을 통하여 AT command를 매번 실행시켜주어야 한다. 2. 서버로서 데이터 수신 시 연결 옵션으로 멀티 커넥션 사용이 강제되어 있고 수신에 사용된 id가 사용 중이거나 종료되지 않은 경우에 추가되는 요청은 다음 id가 요청받게 된다. 3. 연결용 id 5개가 모두 연결된 상태에서 추가 요청이 올 경우 모두 닫힌다. -> 리셋해야만 다시 사용 가능해진다. 4. 3번의 경우를 방지하기 위해 데이터 수신이 완료되면 반드시 id연결을 끊고 대기 상태로 하여야 한다. 5. 연속되는 데이터를 받을 경우 id가 바뀌면서 데이터를 수신하게 되는데 그때 데이터 값의 순서가 바뀔 수 있다.

다음 편에 살펴볼 NODE MCU 1.0(ESP-12E, esp8266 칩셋)이나 ESP32 Dev Module의 경우 상기 ESP-01의 특징 중 2, 3, 5번은 동일한 거 같으나 모듈 자체에 wifi가 내장되어있어 ESP-01의 경우처럼 모듈과 wifi간 시리얼 통신을 사용하지 않을 뿐만 아니라 AT command도 사용하지 않게 되어 사용 id의 종료가 상대적으로 빠르다고 할 수 있다. 하지만 이 두 모델도 연속되는 빠른 데이터 수신 시 5번의 현상이 발견되었고 이를 해결하기 위해서 스마트 폰에서 데이터 전송 간격을 조정해주어야만 했다.

스마트폰에서 이 두 모듈의 데이터 전송 간격은 ESP-01 모듈보다는 짧고 블루투스 모듈보다는 길게 된다.

위의 코드를 아두이노에 업로드한 뒤 스마트폰에서 ESP-01의 soft AP에 접속한다.

arduino bluetooth controller PWM 안드로이드 앱을 실행한 뒤 wifi 아이콘을 클릭하고 ESP-01의 soft AP 192.168.4.1을 입력하고 esp01 체크 박스에 체크를 해준다. 앱에는 기본적으로 100 밀리 초마다 soft AP ip 주소로 응답 요청을 하도록 프로그램되어있다. 하지만 현재 ESP-01을 활용한 아두이노 스케치 코드에는 응답에 대한 어떠한 코드도 없으므로 스마트폰은 요청에 대한 응답을 받지 못하고 오류를 발생하게 된다. esp01 체크 박스에 체크를 해주면 100 밀리 초마다 soft AP ip 주소에 응답 요청을 하지 않게 되어 사용 가능하게 된다.

arduino bluetooth controller PWM – 아두이노 원격제어 안드로이드 앱 버전 3.5 다운로드

arduino bluetooth controller PWM 매뉴얼

(*** 앱에서 와이파이 연결은 안드로이드8 [갤럭시S7]이하 버전에서만 작동합니다 ***)

Confirm을 클릭한 뒤 버튼 1번을 클릭하면 아두이노 기본 LED가 켜지는 것을 볼 수 있고 버튼 2번 부터는 시리얼 모니터에 작동 상태가 표시된다. PWM 제어용 슬라이드는 천천히 움직일 경우 연속되는 데이터가 전송되고 빠르게 움직이면 최종 정지했을 때의 값만 전송된다.

ESP-01 모듈 연결 시는 안드로이드 앱에서 wifi를 통해 연결되었다는 어떠한 표시도 볼 수 없다. 아두이노에서 스마트폰으로 응답을 주는 코드가 없기 때문이다.

NODE MCU 1.0(ESP-12E, esp8266 칩셋)이나 ESP32 Dev Module의 경우 체크박스에 체크를 한 상태에서 Confirm을 클릭하게 되면 응답 요청을 하지 않게 되어 아두이노 측에서 입력된 값을 스마트폰에 출력을 하지 못하게 만든다. 아두이노 시리얼 모니터에 hello를 입력하면 스마트폰에 hello가 표시되어야 하나 표시가 되지 않는다. 이는 서버의 특징으로 스마트폰(클라이언트 또는 마스터)의 요청 시에만 서버(슬레이브)는 연결된 id를 통해 응답을 할 수 있기 때문에 요청이 없는 상태에서는 아두이노에서 스마트폰으로 데이터를 전송하지 못하게 된다. 또한 현재 연결되어 응답을 수신하고 있다는 표시도 할 수 없게 되어, 와이파이가 중간에 끊어져도 알 수 없게 된다. 하지만 ESP-01 모듈처럼 스마트폰에서 모듈의 제어를 하는 기능은 문제없이 사용 가능하다.

NODE MCU 1.0(ESP-12E, esp8266 칩셋)이나 ESP32 Dev Module의 경우에는 esp01 체크 박스에 체크하지 않고 Confirm을 클릭해야만 wifi를 통해 연결되었을 때 응답을 수신하고 현재 연결된 상태라는 것을 표시하게 되고 만약, 가변저항이 연결되어 있다면 가변저항의 조정 상태를 슬라이드 바로 표시할 수 있게 된다.

2019.11.22 추가

이제까지 ESP01의 soft AP에 연결하여 아두이노를 제어했다.

ESP01을 station모드로 공유기에 연결하고 내부 네트워크를 통한 아두이노 원격 제어해보자.

ESP01을 staion 모드로 공유기에 연결하면 공유기는 ESP01에 ip주소를 할당해 준다.

이 주소를 통해 내부 네트워크용 안에서 원격제어를 할 수 있게 되는데 이를 위해서는 반드시 시리얼 모니터에 표시되는 할당받은 ip주소를 확인한 뒤에 연결해야만 한다. (공유기에서 ESP01에 지정 ip를 할당하는 설정을 할 수 없는 경우) 또는 한번 받은 ip 주소를 메모해 두었다가 다시 연결 시 그 주소를 입력하여 사용할 수도 있다.

하지만 시리얼 모니터에서 ip주소를 확인하거나 ip주소가 변경되어 메모해둔 ip주소로 연결할 수 없는 경우도 발생할 수 있어 불편하다.

상기 이유로 내부 네트워크 이용 원격제어가 불필요하다고 생각하여 설명하지 않았었는데, 공유기에 스마트폰이 연결된 상태에서는 soft AP를 이용한 원격제어처럼 와이파이를 따로 연결하지 않아도 되는 편리한 점 때문에 설명을 추가하게 되었다.

ESP01을 station 모드로 공유기에 연결하기 위해서 아래와 같이 setup() 함수 코드를 변경해 주었다.

void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different pinMode(ledPin, OUTPUT); sendData(“AT+RST\r

“,2000,DEBUG); // reset module sendData(“AT+CWMODE=1\r

“,1000,DEBUG); // configure as access point (working mode: AP+STA) sendData(“AT+CWDHCP=1,1\r

“,1000,DEBUG); sendData(“AT+CWJAP=\””+ ssid +”\”,\””+pass+”\”\r

“,8000,DEBUG); sendData(“AT+CIFSR\r

“,1000,DEBUG); // get ip address sendData(“AT+CIPMUX=1\r

“,1000,DEBUG); // configure for multiple connections sendData(“AT+CIPSERVER=1,80\r

“,1000,DEBUG); // turn on server on port 80 }

아래 코드를 업로드하고 시리얼 모니터를 통해 공유기에서 할당받은 ip를 확인하고 ip 주소 192.168.4.1 대신 공유기에서 할당받은 ip를 입력하고 연결해 주면 된다.

2021.03.06 추가

일정 시간 경과 후 와이파이 연결 및 데이터 전송에 관한 테스트

공유기를 통해 테스트하였습니다.

공유기 아이디: skynet

공유기 비번: skynet00

스마트폰의 와이파이가 공유기 skynet에 연결된 상태에서 arduino bluetooth controller PWM 앱을 이용해 테스트했습니다.

아두이노 코드

#include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid = “skynet”; // your network SSID (name) const String pass = “skynet00”; // your network password const String ssid_AP = “ESP-01”; // your network SSID (name) const String pass_AP = “1234test”; // your network password String ip = “”; bool ipCheck = false; #define DEBUG true #define ledPin 13 uint8_t pin_val = 0; // 디지털 버튼 제어용 변수 uint16_t pwm1 = 0; // pwm 제어용 변수 uint16_t pwm2 = 0; uint16_t pwm3 = 0; String text = “”; char connectionId; // 연결 id 저장 변수 String income_wifi = “”; void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different pinMode(ledPin, OUTPUT); sendData(“AT+RST\r

“,2000,DEBUG); // reset module sendData(“AT+CWMODE=3\r

“,1000,DEBUG); // configure as access point (working mode: AP+STA) sendData(“AT+CWDHCP=1,1\r

“,1000,DEBUG); sendData(“AT+CWSAP=\””+ ssid_AP +”\”,\””+pass_AP+”\”,11,0\r

“,1000,DEBUG); // join the access point sendData(“AT+CWJAP=\””+ ssid +”\”,\””+pass+”\”\r

“,8000,DEBUG); sendData(“AT+CIFSR\r

“,1000,DEBUG); // get ip address sendData(“AT+CIPMUX=1\r

“,1000,DEBUG); // configure for multiple connections sendData(“AT+CIPSERVER=1,80\r

“,1000,DEBUG); // turn on server on port 80 } void loop() { wifi_delay(); if(Serial.available() > 0){ // 아두이노 모듈 작동 확인 String temp = Serial.readStringUntil(‘

‘); Serial.println(temp); } } unsigned long int one_millis = 0; void wifi_delay() { // 100 millis if (millis() – one_millis > 50) { one_millis = millis(); if (connectionId == ‘0’) esp01.write(“AT+CIPCLOSE=0\r

“); else if (connectionId == ‘1’) esp01.write(“AT+CIPCLOSE=1\r

“); else if (connectionId == ‘2’) esp01.write(“AT+CIPCLOSE=2\r

“); else if (connectionId == ‘3’) esp01.write(“AT+CIPCLOSE=3\r

“); else if (connectionId == ‘4’) esp01.write(“AT+CIPCLOSE=4\r

“); wifi_read(); } } void wifi_read() { if (esp01.available()) { // check if the esp is sending a message if (esp01.find(“+IPD,”)) { income_wifi = esp01.readStringUntil(‘\r’); Serial.println(income_wifi); connectionId = income_wifi.charAt(0); if (income_wifi.indexOf(“%%F1”) != -1) { if (income_wifi.indexOf(“%%F0”) != -1) { String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F0”)+4, income_wifi.indexOf(“%%F1”)); pin_val = wifi_temp.toInt(); Serial.println(pin_val); pin_control(); } else if (income_wifi.indexOf(“%%F31”) != -1) { String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F31”)+5, income_wifi.indexOf(“%%F1”)); pwm1 = wifi_temp.toInt(); Serial.print(“pwm1: “); Serial.println(pwm1); } else if (income_wifi.indexOf(“%%F32”) != -1) { String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F32”)+5, income_wifi.indexOf(“%%F1”)); pwm2 = wifi_temp.toInt(); Serial.print(“pwm2: “); Serial.println(pwm2); } else if (income_wifi.indexOf(“%%F33”) != -1) { String wifi_temp = income_wifi.substring(income_wifi.indexOf(“%%F33”)+5, income_wifi.indexOf(“%%F1”)); pwm3 = wifi_temp.toInt(); Serial.print(“pwm3: “); Serial.println(pwm3); } } else { // 텍스트 출력 코드 String wifi_temp = income_wifi.substring(income_wifi.indexOf(“GET /”)+5, income_wifi.indexOf(“HTTP/1.1”)); Serial.println(wifi_temp); } income_wifi = “”; } } } String sendData(String command, const int timeout, boolean debug) { String response = “”; if (command.indexOf(“CIFSR”) != -1) ipCheck = true; else ipCheck = false; esp01.print(command); // send the read character to the esp01 long int time = millis(); while( (time+timeout) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } } if (ipCheck) { ip = response.substring(response.indexOf(“STAIP,”)+7,response.indexOf(“+CIFSR:STAMAC”)-3); } if(debug) Serial.print(response); return response; } void pin_control() { if (pin_val != 0) { switch (pin_val) { case 11: digitalWrite(ledPin, true); // button 1 : on break; case 10: digitalWrite(ledPin, false); // button 1 : off break; case 21: Serial.println(“button 2 : on”); break; case 20: Serial.println(“button 2 : off”); break; case 31: Serial.println(“button 3 : on”); break; case 30: Serial.println(“button 3 : off”); break; case 41: Serial.println(“button 4 : on”); break; case 40: Serial.println(“button 4 : off”); break; case 51: Serial.println(“button 5 : on”); break; case 50: Serial.println(“button 5 : off”); break; case 61: Serial.println(“button 6 : on”); break; case 60: Serial.println(“button 6 : off”); break; case 71: Serial.println(“button 7 : on”); break; case 70: Serial.println(“button 7 : off”); break; case 81: Serial.println(“button 8 : on”); break; case 80: Serial.println(“button 8 : off”); break; case 91: Serial.println(“button 9 : on”); break; case 90: Serial.println(“button 9 : off”); break; case 101: Serial.println(“button 10 : on”); break; case 100: Serial.println(“button 10 : off”); break; case 111: Serial.println(“button 11 : on”); break; case 110: Serial.println(“button 11 : off”); break; case 121: Serial.println(“button 12 : on”); break; case 120: Serial.println(“button 12 : off”); break; } pin_val = 0; } }

상기 코드 업로드 후 시리얼 모니터에서 공유기에서 할당해준 ip 주소 192.168.1.9 확인

스마트폰 와이파이 공유기 연결

arduino bluetooth controller PWM 앱에서 esp01 ip 주소 설정

앱에서 텍스트 hi 전송 및 1번 버튼 온/오프 메시지

데이터 수신 및 동작 확인 후 일정 시간 지난 뒤 다시 제어할 경우 가끔씩 esp01 모듈이 sleep 상태로 전환되어 있는 것처럼 첫 번째 데이터를 수신하지 못하는 경우를 확인하였습니다.

모듈의 특성인지는 모르겠지만 앱에서 와이파이를 제어한다는 것이 인터넷 브라우저에서 제어하는 것과는 약간의 차이가 있게 됩니다. 웹브라우저는 서버에서 보내주는 “OK 200″확인 메시지를 받지 못하면 일정기간 또는 일정 횟수 동안 같은 메시지를 반복해서 보내게 되는데 앱에서는 한 번만 보내도록 되어 있어 발생하는 것으로 생각됩니다. 블루투스로 연결해서 사용할 경우에는 이러한 문제가 발생하지 않을 것입니다. 왜냐하면 블루투스는 상시 연결(BLE 제외)을 기준으로 하기 때문 일 것입니다.

일정 시간 뒤 버튼을 눌러 제어를 하고자 했는데 esp01 모듈이 데이트를 받지 못하는 상황을 방지하기 위해서는 텍스트 입력창에 어떤 텍스트라도 입력하여 전 송한 뒤 esp01이 데이터를 확실하게 수신할 수 있도록 깨워주는(?) 선행 작업이 필요할 것으로 생각됩니다.

2022년 5월 31일 업데이트

1. AT command의 딜레이 시간을 제거하고 회신 값에 따라 다음 코드가 실행되게 하여 오류 방지 및 setup 완료 시간 최적화

2. 공유기에 접속할 수 있도록 AT+CWJAP 추가

3. 공유기 연결 실패 시 재시도하도록 코드 추가

위 사진의 ip 주소처럼 정상적으로 wifi 공유기에 연결되고 ip 주소를 할당받은 경우에는 컴퓨터의 웹브라우저 주소창에 해당 아이피와 테스트 문구 “192.168.1.12/hi”를 입력하여 테스트할 수 있다.

#include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[33] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r

“); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘

‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“out”)); break; } } sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address } String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘

‘); if (income_wifi.startsWith(F(“+IPD,”))) { String wifi_temp = income_wifi.substring(income_wifi.indexOf(F(“GET /”))+5, income_wifi.indexOf(F(“HTTP/1.1”))-1); Serial.println(wifi_temp); } } }

웹페이지를 통한 요청에 대해 응답을 하도록 코드를 작성해 주었다.

void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; cip += Data.length()+19; cip += F("\r "); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r

\r

“)); // +19 esp01.print(Data); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; disconnectID(); }

웹페이지 주소창에서 할당받은 아이피 주소에 on/off/message를 입력해 보자.

주소창에 192.168.1.12/on 입력후 회신받은 메세지

주소창에 192.168.1.12/off 입력후 회신받은 메세지

주소창에 192.168.1.12/Hello World! 입력후 회신받은 메세지

#include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[33] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r

“); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } #define ledPin 13 void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘

‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“out”)); break; } } sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address } uint8_t connectionId = 255; // 연결 id 저장 변수 String Data = “”; void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; cip += Data.length()+19; cip += F("\r "); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r

\r

“)); // +19 esp01.print(Data); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; disconnectID(); } String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘

‘); if (income_wifi.startsWith(F(“+IPD,”))) { income_wifi.remove(0,5); connectionId = income_wifi.charAt(0); int ed = income_wifi.lastIndexOf(F(“HTTP/1.1”))-1; income_wifi.remove(ed); int st = income_wifi.indexOf(F(“GET /”))+5; income_wifi.remove(0,st); Serial.println(income_wifi); if(income_wifi == F(“on”)){ digitalWrite(ledPin, HIGH); Data += F(“

LED ON

“); } else if(income_wifi == F(“off”)){ digitalWrite(ledPin, LOW); Data += F(“

LED OFF

“); } else { income_wifi.replace(“%20″, ” “); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F(“

“); Data += income_wifi; Data += F(“

“); } http_response(); } income_wifi = “”; } }

웹페이지를 이용하여 아두이노 우노의 기본 LED를 제어해 보자

웹페이지 코드

const char HEADER[] PROGMEM = // HTML HEADER “” “” “

“; const char FOOTER[] PROGMEM = “

\r

“; // HTML FOOTER const char BACK[] PROGMEM = “

“; void ipPage() { Data = (const __FlashStringHelper *)HEADER; // 아두이노 PROGMEM 읽는 코드 Data += F(“

SSID: “); Data += ssid; Data += F(“

“); Data += F(“

IP Address: “); Data += ip; // 와이파이 공유기에서 할당받은 아이피 주소 Data += F(“

“); Data += F(“

“); Data += (const __FlashStringHelper *)FOOTER; } void buttonPage() { Data = (const __FlashStringHelper *)HEADER; Data += F(“

Pin Control

“); Data += F(“

“); Data += F(“

“); Data += F(“

“); // 데이터 폼 시작 Data += F(““); Data += F(“

“); // 데이터 폼의 값 전송 Data += F(“

“); // 데이터 폼 종료 Data += (const __FlashStringHelper *)BACK; Data += (const __FlashStringHelper *)FOOTER; }

주소창에 192.168.1.12 입력

Button을 클릭했을때 들어가는 페이지

버튼 1을 클릭하면 아두이노 우노의 기본 LED가 켜지고 버튼 1이 ON색상으로 변경된 웹페이지를 받게 된다.

상기 시리얼 모니터에 표시된 AT+CIPSEND=1,912중 “912”가 웹페이지 전체 문자열 길이이고 이 중 Data 스트링 변수의 전체 길이는 912 – 19 = 893이다.

스케치는 프로그램 저장 공간 12138 바이트(37%)를 사용. 최대 32256 바이트.

전역 변수는 동적 메모리 427바이트(20%)를 사용, 1621바이트의 지역변수가 남음. 최대는 2048 바이트.

상기 코드를 업로드한 후에 아두이노 IDE에 현재 가용 메모리가 1621바이트 남아있다고 한다. 실제로는 아두이노 부팅 후 사용되는 함수 안의 스트링 지역 변수 등은 돌려받게 되지만 남은 메모리 1621바이트 전체를 사용할 수 없는 게 일반적이다. 변수에 공간을 할당하고 회수하는 데에 있어서 흔적들 또는 유실되는 영역들이 발생하므로 실제 가용 메모리에 대해서는 추정적이나 실험적으로 결정해야 한다. 버튼 웹페이지의 Data 문자열 길이가 현재보다 길어진다면 메모리 부족으로 인해 데이터가 일부만 전송될 수 있다. PROGMEM을 이용한 추가적인 페이지는 더 만들 수 있으나 상기 코드에서는 웹페이지의 Data 문자열 변수의 길이를 대략 900 이하로 맞추어 주어야 한다.

#include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[33] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r

“); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } #define ledPin 13 void setup() { pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘

‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“out”)); break; } } sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address } uint8_t connectionId = 255; // 연결 id 저장 변수 String Data = “”; void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; cip += Data.length()+19; cip += F("\r "); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r

\r

“)); // +19 esp01.print(Data); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; disconnectID(); } #include “webPage.h” String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘

‘); if (income_wifi.startsWith(F(“+IPD,”))) { income_wifi.remove(0,5); connectionId = income_wifi.charAt(0); int ed = income_wifi.lastIndexOf(F(“HTTP/1.1”))-1; income_wifi.remove(ed); int st = income_wifi.indexOf(F(“GET /”))+5; income_wifi.remove(0,st); Serial.println(income_wifi); if(income_wifi == F(“on”)){ digitalWrite(ledPin, HIGH); Data += F(“

LED ON

“); } else if(income_wifi == F(“off”)){ digitalWrite(ledPin, LOW); Data += F(“

LED OFF

“); } else { if (income_wifi.indexOf(F(“ip”)) != -1) ipPage(); else if (income_wifi.indexOf(F(“Button”)) != -1) buttonPage(); else if (income_wifi.indexOf(F(“button”)) != -1) { String temp = income_wifi.substring(income_wifi.indexOf(‘?’)+4); uint8_t val = temp.toInt(); if (val == 10) digitalWrite(ledPin, LOW); else digitalWrite(ledPin, HIGH); buttonPage(); } else { Serial.println(F(“enter”)); if (income_wifi == “”) ipPage(); else { income_wifi.replace(“%20″, ” “); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F(“

“); Data += income_wifi; Data += F(“

“); } } } http_response(); } income_wifi = “”; } if(Serial.available() > 0){ // 아두이노 모듈 작동 확인 String temp = Serial.readStringUntil(‘

‘); Serial.println(temp); if (temp.startsWith(F(“AT”))) { temp.remove(0,3); Serial.println(temp); sendData(temp); } else if (temp == F(“1”)) { } } }

상기의 Data 문자열 변수의 길이를 줄여 메모리 문제를 해결하기 위해 boolean 변수 page를 설정하고 page 변수에 따라 웹페이지의 html header와 footer를 Data 문자열 변수에 저장하지 않고 PROGMEM에서 바로 읽어서 전송할 수 있도록 코드를 수정해 주었다.

void http_response(bool page) { String cip = F(“AT+CIPSEND=”); cip += connectionId-48; cip += ‘,’; if (page) cip += Data.length()+19+sizeofHeader+sizeofFooter; else cip += Data.length()+19; cip += F(“\r

“); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r

\r

“)); // +19 if (page) { esp01.print((const __FlashStringHelper *)HEADER); esp01.print(Data); esp01.print((const __FlashStringHelper *)FOOTER); } else esp01.print(Data); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; page = false; disconnectID(); }

#include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[33] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r

“); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } #define ledPin 13 uint16_t sizeofHeader = 0; uint16_t sizeofFooter = 0; bool page = false; String Data = “”; #include “webPage.h” void setup() { pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘

‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“out”)); break; } } sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address sizeofHeader = sizeof(HEADER)-1; // -1: ‘\0’ sizeofFooter = sizeof(FOOTER)-1; // -1: ‘\0’ } uint8_t connectionId = 255; // 연결 id 저장 변수 void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; if (page) cip += Data.length()+19+sizeofHeader+sizeofFooter; else cip += Data.length()+19; cip += F("\r "); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r

\r

“)); // +19 if (page) { esp01.print((const __FlashStringHelper *)HEADER); esp01.print(Data); esp01.print((const __FlashStringHelper *)FOOTER); } else esp01.print(Data); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; page = false; disconnectID(); } String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘

‘); if (income_wifi.startsWith(F(“+IPD,”))) { income_wifi.remove(0,5); connectionId = income_wifi.charAt(0); int ed = income_wifi.lastIndexOf(F(“HTTP/1.1”))-1; income_wifi.remove(ed); int st = income_wifi.indexOf(F(“GET /”))+5; income_wifi.remove(0,st); Serial.println(income_wifi); if (!income_wifi.startsWith(F(“fav”))) { // favicon.ico 는 통과 if(income_wifi == F(“on”)){ digitalWrite(ledPin, HIGH); Data += F(“

LED ON

“); } else if(income_wifi == F(“off”)){ digitalWrite(ledPin, LOW); Data += F(“

LED OFF

“); } else { if (income_wifi.indexOf(F(“ip”)) != -1) ipPage(); else if (income_wifi.indexOf(F(“Button”)) != -1) buttonPage(); else if (income_wifi.indexOf(F(“button”)) != -1) { String temp = income_wifi.substring(income_wifi.indexOf(‘?’)+4); uint8_t val = temp.toInt(); if (val == 10) digitalWrite(ledPin, LOW); else digitalWrite(ledPin, HIGH); buttonPage(); } else { Serial.println(F(“enter”)); if (income_wifi == “”) ipPage(); else { income_wifi.replace(“%20″, ” “); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F(“

“); Data += income_wifi; Data += F(“

“); } } } http_response(); } } income_wifi = “”; } if(Serial.available() > 0){ // 아두이노 모듈 작동 확인 String temp = Serial.readStringUntil(‘

‘); Serial.println(temp); if (temp.startsWith(F(“AT”))) { temp.remove(0,3); Serial.println(temp); sendData(temp); } else if (temp == F(“1”)) { } } }

와이파이 매니저

게시글 [arduino] – 아두이노 – ESP01 와이파이 매니저, soft AP이용 공유기 연결용 아이디와 비밀번호 설정하기, wifimanager에서 구현한 와이파이 매니저를 WiFiEsp.h 라이브러리를 사용하지 않고 AT commnad를 사용하여 구현하였다.

* 아두이노 IDE에서 와이파이 설정값 변경한 경우 EEPROM에 값 반영하는 방법

리부팅시 변경된 와이파이 설정값을 반영해주기 위해서는 시리얼 모니터에서 “1”을 입력하고 엔터를 쳐준 뒤에 아두이노를 리부팅 해준다.

설정에 따라 공유기에 연결이 안된 경우

Wifi 설정 페이지 – 와이파이 연결유무, 아이디, 패스워드 설정

공유기 연결 설정

설정 저장 및 공유기 연결중 메세지

공유기 연결 후 할당받은 아이피 표시

웹페이지 코드

//web page String const char HEADER[] PROGMEM = “” “” “

“; const char FOOTER[] PROGMEM = “

\r

“; const char BACK[] PROGMEM = “

“; void ipPage() { Data += F(“

SSID: “); Data += ssid; Data += F(“

“); Data += F(“

IP Address: “); Data += ip; Data += F(“

“); Data += F(“

“); Data += F(“

“); page = true; } void buttonPage() { Data += F(“

Pin Control

“); Data += F(“

“); Data += F(“

“); Data += F(“

“); Data += F(““); Data += F(“

“); Data += F(“

“); Data += (const __FlashStringHelper *)BACK; page = true; } void wifiPage() { Data += (const __FlashStringHelper *)BACK; Data += F(“

“); Data += F(“ connect To wifi Router

“); Data += F(“
“); Data += F(“
“); Data += F(“

“); page = true; } void messagePage() { if (wifiRouter) { Data += F(“

SSID: “); Data += ssid; Data += F(“

“); Data += F(“

PASS: “); Data += pass; Data += F(“

“); Data += F(“

Credentials Saved.

“); Data += F(“

Trying to connect ESP01 to Router.

“); } else Data += F(“

disconnect from Router.

“); Data += (const __FlashStringHelper *)BACK; page = true; }

#include #include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password bool wifiRouter = true; // 공유기 연결 유무 char ssid[21] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r

“); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } #define ledPin 13 uint16_t sizeofHeader = 0; uint16_t sizeofFooter = 0; String Data = “”; bool page = false; #include “webPage.h” void setWifi() { sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘

‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“Set”)); break; } } if (wifiRouter) sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) else sendData(F(“CWMODE=2”)); if (wifiRouter) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 if (wifiRouter) { retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } } ipCheck(sendData(F(“CIFSR”))); // get ip address } void wifi_eeprom_read() { // 아이디 / 비밀번호 읽기 for (int i = 0; i < 20; i++) ssid[i] = EEPROM.read(981 + i); // sizeof(ssid)-1 for (int i = 0; i < 20; i++) pass[i] = EEPROM.read(1001 + i); // sizeof(pass)-1 } void wifi_eeprom_write() { // 아이디 / 비밀번호 쓰기 for (int i = 0; i < 20; i++) EEPROM.write(981 + i, ssid[i]); // sizeof(ssid)-1 for (int i = 0; i < 20; i++) EEPROM.write(1001 + i, pass[i]); // sizeof(pass)-1 } void setup() { pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); if(EEPROM.read(1023) != 1) { for (int i = 0 ; i < EEPROM.length() ; i++) EEPROM.write(i, 0); // EEPROM Clear EEPROM.write(1023, 1); // eeprom 저장 플래그 EEPROM.write(980, wifiRouter); wifi_eeprom_write(); // 최초 초기화시 아이디 / 비밀번호 쓰기 } else { wifiRouter = EEPROM.read(980); wifi_eeprom_read(); // 아두이노 리셋시 저장된 아이디 / 비밀번호 읽기 } Serial.begin(9600); esp01.begin(9600); // your esp's baud rate might be different setWifi(); sizeofHeader = sizeof(HEADER)-1; // -1: '\0' sizeofFooter = sizeof(FOOTER)-1; // -1: '\0' } uint8_t connectionId = 255; // 연결 id 저장 변수 void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; if (page) cip += Data.length()+19+sizeofHeader+sizeofFooter; else cip += Data.length()+19; cip += F("\r "); Serial.println(cip); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } esp01.print(F(“HTTP/1.1 200 OK\r

\r

“)); // +19 if (page) { esp01.print((const __FlashStringHelper *)HEADER); esp01.print(Data); esp01.print((const __FlashStringHelper *)FOOTER); } else esp01.print(Data); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; page = false; disconnectID(); } String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘

‘); if (income_wifi.startsWith(F(“+IPD,”))) { income_wifi.remove(0,5); connectionId = income_wifi.charAt(0); int ed = income_wifi.lastIndexOf(F(“HTTP/1.1”))-1; income_wifi.remove(ed); int st = income_wifi.indexOf(F(“GET /”))+5; income_wifi.remove(0,st); Serial.println(income_wifi); if (!income_wifi.startsWith(F(“fav”))) { // favicon.ico 는 통과 bool wifiChanged = false; if(income_wifi == F(“on”)){ digitalWrite(ledPin, HIGH); Data += F(“

LED ON

“); } else if(income_wifi == F(“off”)){ digitalWrite(ledPin, LOW); Data += F(“

LED OFF

“); } else { if (income_wifi.indexOf(F(“ip”)) != -1) ipPage(); else if (income_wifi.indexOf(F(“Button”)) != -1) buttonPage(); else if (income_wifi.indexOf(F(“button”)) != -1) { String temp = income_wifi.substring(income_wifi.indexOf(‘?’)+4); uint8_t val = temp.toInt(); if (val == 10) digitalWrite(ledPin, LOW); else digitalWrite(ledPin, HIGH); buttonPage(); } else if (income_wifi.indexOf(F(“Wifi”)) != -1) wifiPage(); else if (income_wifi.indexOf(F(“wifi”)) != -1) { // ed = income_wifi.lastIndexOf(‘&’); String temp = income_wifi.substring(ed+3); String check = “”; if (temp.length() > 7) { // 비밀번호 길이가 8 이상인경우 check = pass; if (temp != check) { wifiChanged = true; for (int i = 0; i < temp.length(); i++) pass[i] = temp[i]; pass[temp.length()] = '\0'; } } income_wifi.remove(ed); ed = income_wifi.lastIndexOf(F("s=")); temp = income_wifi.substring(ed+2); Serial.println(temp); check = ssid; if (temp != check) { wifiChanged = true; for (int i = 0; i < temp.length(); i++) ssid[i] = temp[i]; ssid[temp.length()] = '\0'; } st = income_wifi.indexOf('?'); temp = income_wifi.substring(st+1, st+4); bool oldWifiRouter = wifiRouter; if (temp == F("use")) wifiRouter = true; else wifiRouter = false; if (oldWifiRouter != wifiRouter) { EEPROM.write(980, wifiRouter); wifiChanged = true; } if (wifiChanged) { wifi_eeprom_write(); messagePage(); } else wifiPage(); } else { if (income_wifi == "") ipPage(); else { income_wifi.replace("%20", " "); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F("

“); Data += income_wifi; Data += F(“

“); } } } http_response(); if (wifiChanged) setWifi(); } } income_wifi = “”; } if(Serial.available() > 0){ // 아두이노 모듈 작동 확인 String temp = Serial.readStringUntil(‘

‘); Serial.println(temp); if (temp.startsWith(F(“AT”))) { temp.remove(0,3); Serial.println(temp); sendData(temp); } else if (temp == F(“1”)) { EEPROM.write(1023, 0); } else if (temp == F(“2”)) { Serial.println(ssid); Serial.println(pass); } } }

웹페이지 로그인

와이파이를 통해 아두이노를 원격 제어할 때 Soft AP(192.168.4.1)를 사용할 경우에는 Soft AP의 비밀번호를 설정함으로써 보안이 설정되는데 (휴대폰의 와이파이 연결에서 AP연결 시 비밀번호 입력 필요), 아두이노가 와이파이 공유기에 연결되고 IP를 할당받은 경우에는 공유기 네트워크 내에 연결된 누구라도 아두이노가 연결된 IP주소만 알면 연결 및 제어가 가능하게 된다. 이를 방지하기 위해 Cookie를 사용하여 웹 로그인 기능을 구현하였다. 원격제어는 한 명만 제어가 가능해야 하며, 따라서 멀티 로그인은 배제한다.

1. 웹 로그인 사용 유무 설정

2. Soft AP(102.168.4.1)에 비밀번호가 설정되어 있는 경우에만 웹 로그인 활성화

* 비밀번호는 8 문자 이상 입력해야 설정됨

3. 웹 로그인 사용 시 Soft AP(102.168.4.1)를 통한 연결은 AP연결 시 비밀번호를 입력하므로 로그인 확인 안 함.

4. 공유기 네트워크에 로그인되어있더라도 Soft AP(102.168.4.1) 및 다른 브라우저 로그인을 통한 연결 시 밀어내기 기능 – Soft AP 접속 우선 제어 권한

5. 웹 로그인 비밀번호는 Soft AP 비밀번호를 사용한다.

웹로그인 페이지

웹로그인 비밀번호 입력

웹로그인 확인 후 페이지 표시

웹로그인 설정화면

웹로그인 시 시리얼모니터 표시

로그인 웹페이지 및 쿠기 생성 코드, 비밀번호 검증 코드

void loginPage() { if (connectedAP) { Data += F(“
occupied connection by AP
“); } else { Data += F(“

“); Data += F(“
“); Data += F(“

“); Data += F(“

“); } page = true; } // login code String cooValue = “u7Dv0”; uint8_t cooLength = 5; bool newCoo = true; String makeCooValue() { cooValue = “”; uint8_t temp = 0; for (int i = 0; i < cooLength; i++) { temp = random(39, 123); //random(39, 123); // 39 ~ 122 pick if (temp == 47 || temp == 59 || temp == 60 || temp == 62 || temp == 92 || temp == 94 || temp == 96) temp = 41; cooValue += char(temp); } Serial.print(F("send coo: ")); Serial.println(cooValue); return cooValue; } bool checkLogin() { bool confirm = false; String tempId = ""; tempId = esp01.readStringUntil(' '); while(1) { tempId = esp01.readStringUntil(' '); if (tempId.startsWith(F("\r"))) { tempId = esp01.readStringUntil(' '); break; } } int index = tempId.lastIndexOf('&'); String tempPass = tempId.substring(index+3); tempId.remove(index); index = tempId.lastIndexOf('?'); tempId = tempId.substring(index+3); Serial.print("tempPass: "); Serial.println(tempPass); Serial.print("tempId: "); Serial.println(tempId); if (tempId == ssid_AP && tempPass == pass_AP) { confirm = true; login = true; newCoo = true;} return confirm; } #include #include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password bool wifiRouter = true; // 공유기 연결 유무 char ssid[21] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; bool useLogin = true; bool connectedAP = false; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ip); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r

“); esp01.print(command); // send the read character to the esp01 long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } #define ledPin 13 uint16_t sizeofHeader = 0; uint16_t sizeofFooter = 0; bool page = false; bool login = false; String Data = “”; #include “webPage.h” void setWifi() { sendData(F(“RST”)); // disconnect AP if connected unsigned long int time = millis(); String temp = “”; while (time+20000 > millis()) { temp = esp01.readStringUntil(‘

‘); if (temp.indexOf(F(“ready”)) != -1) { Serial.println(F(“Set”)); break; } } if (wifiRouter) sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) else sendData(F(“CWMODE=2”)); if (wifiRouter) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 if (wifiRouter) { retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } } ipCheck(sendData(F(“CIFSR”))); // get ip address } void wifi_eeprom_read() { // 아이디 / 비밀번호 읽기 for (int i = 0; i < 20; i++) ssid[i] = EEPROM.read(981 + i); // sizeof(ssid)-1 for (int i = 0; i < 20; i++) pass[i] = EEPROM.read(1001 + i); // sizeof(pass)-1 } void wifi_eeprom_write() { // 아이디 / 비밀번호 쓰기 for (int i = 0; i < 20; i++) EEPROM.write(981 + i, ssid[i]); // sizeof(ssid)-1 for (int i = 0; i < 20; i++) EEPROM.write(1001 + i, pass[i]); // sizeof(pass)-1 } void setup() { pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); if(EEPROM.read(1023) != 1) { for (int i = 0 ; i < EEPROM.length() ; i++) EEPROM.write(i, 0); // EEPROM Clear EEPROM.write(1023, 1); // eeprom 저장 플래그 EEPROM.write(980, wifiRouter); EEPROM.write(979, useLogin); wifi_eeprom_write(); // 최초 초기화시 아이디 / 비밀번호 쓰기 } else { useLogin = EEPROM.read(979); wifiRouter = EEPROM.read(980); wifi_eeprom_read(); // 아두이노 리셋시 저장된 아이디 / 비밀번호 읽기 } if (pass_AP == "" || pass_AP.length() < 8) useLogin = false; // Soft AP의 비밀번호가 활성화되지않은 경우 Serial.begin(9600); esp01.begin(9600); // your esp's baud rate might be different setWifi(); sizeofHeader = sizeof(HEADER)-1; // -1: '\0' sizeofFooter = sizeof(FOOTER)-1; // -1: '\0' } uint8_t connectionId = 255; // 연결 id 저장 변수 void disconnectID() { if (connectionId < 255) { String command = F("AT+CIPCLOSE="); command += connectionId-48; command += F("\r "); esp01.print(command); connectionId = 255; } } void http_response() { String cip = F("AT+CIPSEND="); cip += connectionId-48; cip += ','; if (page) { uint8_t len = 50+4; if (!connectedAP && useLogin) { len += 4; if (login) { if (newCoo) len += cooLength; } } cip += Data.length()+len+sizeofHeader+sizeofFooter; } else cip += Data.length()+19; cip += F("\r "); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } if (page) { esp01.print(F(“HTTP/1.1 200 OK

Content-type:text/html

Set-Cookie:”)); // +52 -2 = 50 if (!connectedAP && useLogin) { esp01.print(F(“%%F5”)); // +4 if (login) { if (newCoo) esp01.print(makeCooValue()); // +cooLength } } esp01.print(F(“\r

\r

“)); // +8 -4 = 4 esp01.print((const __FlashStringHelper *)HEADER); esp01.print(Data); esp01.print((const __FlashStringHelper *)FOOTER); } else { esp01.print(F(“HTTP/1.1 200 OK\r

\r

“)); // 23 – 4 = +19 esp01.print(Data); } time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“out”)); break; } } Data = “”; page = false; disconnectID(); } String income_wifi = “”; void loop() { while (esp01.available()) { income_wifi = esp01.readStringUntil(‘

‘); bool parsing = false; if (income_wifi.startsWith(F(“+”))) { if (income_wifi.startsWith(F(“+IPD”))) parsing = true; else if (income_wifi.startsWith(F(“+STA_CON”))) { connectedAP = true; Serial.println(F(“connectedAP”)); } else if (income_wifi.startsWith(F(“+STA_DIS”))) { connectedAP = false; Serial.println(F(“disconnectedAP”)); } } if (parsing) { income_wifi.remove(0,5); connectionId = income_wifi.charAt(0); int ed = income_wifi.lastIndexOf(F(“HTTP/1.1”))-1; income_wifi.remove(ed); int st = income_wifi.indexOf(F(“GET /”))+5; income_wifi.remove(0,st); Serial.println(income_wifi); if (!income_wifi.startsWith(F(“fav”))) { // favicon.ico 는 통과 bool OK = false, rootPage = false; bool wifiChanged = false; if (useLogin) { if (connectedAP) { OK = true; if (login) { login = false; makeCooValue(); } // 로그인 밀어내기 old Cookie terminate } else { if (!login) { // 현재 로그인 상태가 아닌 경우 if (income_wifi.indexOf(F(“Logi”)) != -1) { Serial.println(“enter”); rootPage = checkLogin(); // 비밀번호 검증 start sending Cookie Serial.println(rootPage); } } else { newCoo = false; if (income_wifi.indexOf(F(“Logi”)) != -1) { // 밀어내기 로그인 rootPage = checkLogin(); } else { uint16_t len = 0; String temp = “”; while(1) { temp = esp01.readStringUntil(‘

‘); len = temp.length(); if (temp.startsWith(F(“Coo”)) || len < 3) break; } if (len > 2) { ed = temp.indexOf(F(“%%F5”))+4; if (ed != -1) { temp = temp.substring(ed, ed+cooLength); if (temp == cooValue) { OK = true; newCoo = true; } } } if (OK) { // 웹페이지 출력 if (income_wifi.indexOf(F(“Logo”)) != -1) { // Logout login = false; OK = false; makeCooValue(); // cookie 값 변경 } } } } } } else { OK = true; } if (OK) { if(income_wifi == F(“on”)){ digitalWrite(ledPin, HIGH); Data += F(“

LED ON

“); } else if(income_wifi == F(“off”)){ digitalWrite(ledPin, LOW); Data += F(“

LED OFF

“); } else { if (income_wifi.indexOf(F(“ip”)) != -1) ipPage(); else if (income_wifi.indexOf(F(“Button”)) != -1) buttonPage(); else if (income_wifi.indexOf(F(“button”)) != -1) { String temp = income_wifi.substring(income_wifi.indexOf(‘?’)+4); uint8_t val = temp.toInt(); if (val == 10) digitalWrite(ledPin, LOW); else digitalWrite(ledPin, HIGH); buttonPage(); } else if (income_wifi.indexOf(F(“Wifi”)) != -1) wifiPage(); else if (income_wifi.indexOf(F(“wifi”)) != -1) { // ed = income_wifi.lastIndexOf(‘&’); String temp = income_wifi.substring(ed+3); if (temp == F(“G=on”)) { useLogin = true; EEPROM.write(979, useLogin); income_wifi.remove(ed); ed = income_wifi.lastIndexOf(‘&’); temp = income_wifi.substring(ed+3); } else { useLogin = false; EEPROM.write(979, useLogin); } String check = “”; if (temp.length() > 7) { // 비밀번호 길이가 8 이상인경우 check = pass; if (temp != check) { wifiChanged = true; for (int i = 0; i < temp.length(); i++) pass[i] = temp[i]; pass[temp.length()] = '\0'; } } income_wifi.remove(ed); ed = income_wifi.lastIndexOf(F("s=")); temp = income_wifi.substring(ed+2); Serial.println(temp); check = ssid; if (temp != check) { wifiChanged = true; for (int i = 0; i < temp.length(); i++) ssid[i] = temp[i]; ssid[temp.length()] = '\0'; } st = income_wifi.indexOf('?'); temp = income_wifi.substring(st+1, st+4); bool oldWifiRouter = wifiRouter; if (temp == F("ROU")) wifiRouter = true; else wifiRouter = false; if (oldWifiRouter != wifiRouter) { EEPROM.write(980, wifiRouter); wifiChanged = true; } if (wifiChanged) { wifi_eeprom_write(); messagePage(); } else wifiPage(); } else { if (income_wifi == "") ipPage(); else { income_wifi.replace(F("%20"), F(" ")); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F("

“); Data += income_wifi; Data += F(“

“); } } } } else { if (useLogin) { if (rootPage) ipPage(); else loginPage(); } else { if (income_wifi == “”) ipPage(); else { income_wifi.replace(F(“%20″), F(” “)); // URL Decoding 공백문자 변경 Serial.println(income_wifi); Data += F(“

“); Data += income_wifi; Data += F(“

“); } } } http_response(); if (wifiChanged) setWifi(); } } income_wifi = “”; } if(Serial.available() > 0){ // 아두이노 모듈 작동 확인 String temp = Serial.readStringUntil(‘

‘); Serial.println(temp); if (temp.startsWith(F(“AT”))) { temp.remove(0,3); Serial.println(temp); sendData(temp); } else if (temp == F(“1”)) { EEPROM.write(1023, 0); } } }

ESP01 펌웨어 업로드하기

웹 로그인 구현 코드상에 Soft AP로 연결된 상태를 확인하는 코드는 아래와 같다.

if (income_wifi.startsWith(F(“+”))) { if (income_wifi.startsWith(F(“+IPD”))) parsing = true; else if (income_wifi.startsWith(F(“+STA_CON”))) { connectedAP = true; Serial.println(F(“connectedAP”)); } else if (income_wifi.startsWith(F(“+STA_DIS”))) { connectedAP = false; Serial.println(F(“disconnectedAP”)); } }

상기 코드는 ESP01 펌웨어에서 Soft AP에 연결/종료 이벤트가 발생하면 시리얼 통신을 통해 아두이노로 보내주는 메시지 “+STA_CONNECTED / +STA_DISCONNECTED”를 확인하고 현재 Soft AP에서 연결된 상태인지 아닌지를 결정하는 코드이다. 따라서 ESP01의 펌웨어 프로그램에서 해당 메시지를 정상적으로 보내주지 않는다면 웹로그인 기능은 작동할 수 없게된다. 일부 펌웨어 버전이 탑제된 ESP01은 Soft AP 연결/종료 이벤트 발생시 해당 메세지를 전송하지 않는 오류가 있다고 한다. 만약 Soft AP로 연결을 했는데 시리얼 모니터에 “connectedAP”라는 메시지가 표시되지 않는다면 최신 펌웨어를 ESP01에 업로드해야 한다.

1. 아두이노에 EMPTY CODE 업로드

2. ESP01과 아두이노의 연결을 펌웨어 업로드용으로 변경

ESP01 TX -> 아두이노 TX

ESP01 RX -> 아두이노 RX

ESP01 VCC -> 아두이노 3.3V

ESP01 CH_PD -> 아두이노 3.3V

ESP01 GND -> 아두이노 GND

ESP01 GPIO0 -> 아두이노 GND

ESP01 RST -> 아두이노 GND 연결 대기

ESP01 핀맵

3. ESP01 펌웨어 / 펌웨어 업로드 프로그램 다운로드 및 압축 풀기

펌웨어 업로드 프로그램

펌웨어 V1.7.5_1

https://www.espressif.com/en/products/sdks/esp-at/resource

파일 경로상에 한글이 있으면 정상 작동하지 않으므로 다운로드한 펌웨어 / 업로드 프로그램은 C드라이브 또는 D드라이브에 복사하고 압축을 풀어준다.

펌웨어 업로드 프로그램 경로

펌웨어 경로

4. ESP01 설치되어있는 펨웨어 지우기

4-1. flash_download_tools_v3.6.5.exe를 실행하고 ESP8266 DownloadTool을 선택한다.

4-2. DownloadTool에서 아두이노가 연결된 COM PORT를 설정해준다. 만약 아두이노 IDE의 시리얼 모니터가 열려있다면 닫아준다.

아두이노 IDE의 COM 포트 확인

4-3. ESP01을 업로드 모드로 전환하고 지우기

ESP01의 RST핀에 연결해놓은 선을 아두이노 GND에 1초 정도 연결한 뒤 떼면 ESP01에 내장되어 있는 파란색 LED가 켜졌다 꺼지면서 업로드 모드로 전환된다. 파란색 LED가 켜졌다 꺼지지 않으면 업로드할 수 없다. ESP01과 아두이노의 연결이 잘못되었거나 아두이노에 EMPTY CODE가 업로드되지 않았을 수 있다. ERASE 버튼을 클릭한다.

정상적으로 펌웨어가 지워지면 아래와 같은 메시지와 함께 FINISH라고 표시된다.

만약 아래 사진처럼 점선이 표시된다면 정상적으로 진행되지 않고 있다는 것이다. 이때는 STOP을 누르고 COM PORT를 확인하거나 “업로드 모드”로 전환하기를 다시 한 뒤 해본다. 펌웨어 지우기를 할 수 없다면, 펌웨어 업로드도 할 수 없게 된다.

5. 펌웨어 설정 경로 확인하고 설정하기

D:\ESP8266_NonOS_AT_Bin_V1.7.5_1\ESP8266_NonOS_AT_Bin_V1.7.5\bin\at 경로의 README.md 파일을 메모장으로 열어보면 아래와 같은 경로 설정을 확인할 수 있다.

### Flash size 8Mbit: 512KB+512KB

boot_v1.2+.bin 0x00000

user1.1024.new.2.bin 0x01000

esp_init_data_default.bin 0xfc000

blank.bin 0x7e000 & 0xfe000

설정 방법에 따라 아래와 같이 순서대로 경로 창에 입력해 준다.

1.D:\ESP8266_NonOS_AT_Bin_V1.7.5_1\ESP8266_NonOS_AT_Bin_V1.7.5\bin\boot_v1.7.bin을 선택하고 우측에 “0x00000″을 입력.

2.D:\ESP8266_NonOS_AT_Bin_V1.7.5_1\ESP8266_NonOS_AT_Bin_V1.7.5\bin\at\512+512\user1.1024.new.2.bin을 선택하고 우측에 “0x01000″을 입력.

3.D:\ESP8266_NonOS_AT_Bin_V1.7.5_1\ESP8266_NonOS_AT_Bin_V1.7.5\bin\esp_init_data_default_v08.bin을 선택하고 우측에 “0xfc000″을 입력.

4.D:\ESP8266_NonOS_AT_Bin_V1.7.5_1\ESP8266_NonOS_AT_Bin_V1.7.5\bin\blank.bin을 선택하고 우측에 “0x7e000″을 입력. 그 아래 같은 파일을 한번 더 선택하고 우측에 “0xfe000″을 입력

입력한 다섯 개 항목의 체크박스에 체크를 해준다.

6. 설정이 완료됐으면 SPI SPEED: 40MHz, SPI MODE: QIO, FLASH SIZE: 8Mbit를 추가로 설정해주고

4-1 업로드 모드로 전환하기를 다시 실행한 뒤 “START” 버튼을 클릭

업로드 모드는 펌웨어 지우기 또는 펌웨어 업로드의 시도가 있은 후에는 그 성공 여부에 상관없이 초기화되므로 매번 업로드 모드로 전환한 후에 실행해야함.

펌웨어 업로드가 완료되면 ESP01 모듈의 보드 레이트는 초기값인 115200으로 변경된다. 아두이노에서 사용할 수 있도록 보드 레이트를 9600으로 변경해주어야 한다.

현재 아두이노에는 EMPTY CODE가 업로드 되어 있다. 이 상태에서 아두이노 IDE의 시리얼 모니터를 열고 보드 레이트는 115200, 전송옵션은 “Both NL & CR”로 설정한 뒤에 현재 아두이노 GND에 연결되어 있는 GPIO0핀의 연결을 해제한다. GPIO0핀이 연결해제된 상태에서 RST핀을 아두이노의 GND핀에 연결했다 해제하면 시리얼 모니터에 아래와 같이 “ready”라는 메시지가 출력된다.

시리얼 모니터 입력창에 “AT+UART_DEF=9600,8,1,0,0″를 입력하고 엔터를 치면 “OK”라는 메세지가 출력되고 ESP01의 보드레이트는 9600으로 변경된다.

보드 레이트가 9600으로 변경되었으므로 시리얼 모니터의 보드 레이트를 9600으로 변경한 뒤 시리얼 모니터 입력창에 “AT”를 입력하고 엔터를 치면 “OK”라는 메시지를 확인 할 수 있다.

이제 펌웨어 업로드와 보드 레이트 변경까지 완료 하였다. 아두이노와 ESP01의 연결을 이전으로(제어용) 변경해 준다.

기상청 및 오픈 웨더 맵에서 날씨 정보 받기

기상청

스케치는 프로그램 저장 공간 13142 바이트(40%)를 사용. 최대 32256 바이트.

전역 변수는 동적 메모리 437바이트(21%)를 사용, 1611바이트의 지역변수가 남음. 최대는 2048 바이트.

#include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[21] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; String ap = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ap = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ap); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r

“); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“CWQIF”)); // disconnect AP if connected sendData(F(“CWQAP”)); // disconnect wifi if connected sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address } // http://www.kma.go.kr/wid/queryDFSRSS.jsp?zone=1159068000 const char host[] PROGMEM = “www.kma.go.kr”; const char url[] PROGMEM = “/wid/queryDFSRSS.jsp?zone=1159068000”; bool OK200 = false; bool sentREQ = false; bool gotWeather = false; void get_weather() { if (!sentREQ) { Serial.println(F(“Starting connection to server…”)); bool connectOK = false; String cip = F(“AT+CIPSTART=3,”); // connection ID 3 (ID: 0 ~ 4) cip += ‘”‘; cip += F(“TCP”); cip += ‘”‘; cip += ‘,’; cip += ‘”‘; cip += (const __FlashStringHelper *)host; cip += ‘”‘; cip += ‘,’; cip += F(“80”); // port number cip += F(“\r

“); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { connectOK = true; Serial.println(F(“OK”)); break; } else if (cip.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } } if (connectOK) { Serial.println(F(“Connected to server”)); String temp = F(“GET “); temp += (const __FlashStringHelper *)url; temp += F(” HTTP/1.1\r

Host: “); temp += (const __FlashStringHelper *)host; temp += F(“\r

Connection: close\r

\r

“); cip = F(“AT+CIPSEND=”); cip += 3; // connection ID 3 (ID: 0 ~ 4) cip += ‘,’; cip += temp.length(); cip += F(“\r

“); esp01.print(cip); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“OK”)); break; } else if (cip.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } } esp01.print(temp); sentREQ = true; gotWeather = true; } } } // RSS 날씨 정보 저장 변수 // RSS 날씨 정보 저장 변수 String line0 = “”; String line1 = “”; uint8_t count = 0; // RSS 날씨 정보 분류 카운터 uint8_t tryCount = 0; // 온도 저장 변수 float temp0; float temp1; void parsing() { String announce_time; int tm_start= line0.indexOf(F(““)); // ““문자가 시작되는 인덱스 값(‘<'의 인덱스)을 반환한다. int tm_end= line0.indexOf(F("“)); announce_time = line0.substring(tm_start + 4, tm_end); // +4: ““스트링의 크기 4바이트, 4칸 이동 Serial.print(F(“announce_time: “)); Serial.println(announce_time); String hour; int hour_start= line0.indexOf(F(““)); int hour_end= line0.indexOf(F(““)); hour = line0.substring(hour_start + 6, hour_end); Serial.print(F(“hour: “)); Serial.println(hour); String temp; int temp_start= line0.indexOf(F(““)); int temp_end= line0.indexOf(F(““)); temp = line0.substring(temp_start + 6, temp_end); Serial.print(F(“temp: “)); Serial.println(temp); temp0 = temp.toFloat(); // 자료형 변경 String -> float Serial.print(F(“temp0: “)); Serial.println(temp0); String wfEn; int wfEn_start= line0.indexOf(F(““)); int wfEn_end= line0.indexOf(F(““)); wfEn = line0.substring(wfEn_start + 6, wfEn_end); Serial.print(F(“weather: “)); Serial.println(wfEn); line0 = “”; // 스트링 변수 line0 데이터 추출 완료 Serial.println(); hour_start= line1.indexOf(F(““)); hour_end= line1.indexOf(F(““)); hour = line1.substring(hour_start + 6, hour_end); Serial.print(F(“hour: “)); Serial.println(hour); temp_start= line1.indexOf(F(““)); temp_end= line1.indexOf(F(““)); temp = line1.substring(temp_start + 6, temp_end); Serial.print(F(“temp: “)); Serial.println(temp); temp1 = temp.toFloat(); // 자료형 변경 String -> float Serial.print(F(“temp1: “)); Serial.println(temp1); wfEn_start= line1.indexOf(F(““)); wfEn_end= line1.indexOf(F(““)); wfEn = line1.substring(wfEn_start + 6, wfEn_end); Serial.print(F(“weather: “)); Serial.println(wfEn); line1 = “”; // 스트링 변수 line1 데이터 추출 완료 } bool header = false; void loop() { if (!ip.startsWith(F(“0”))) { // 공유기로부터 IP주소를 할당받은 경우 if (!gotWeather) { if (tryCount < 3) { get_weather(); tryCount++; } } } if (sentREQ) { // 날씨 정보가 들어오는 동안 if (!OK200) { if (esp01.find('+')) { line0 = esp01.readStringUntil(' '); if (line0.indexOf(F("200")) != -1) OK200 = true; line0 = ""; } else { // gotWeather = true; -> 날씨 작업 종료 후 나머지 데이터 삭제 line0 = esp01.readStringUntil(‘

‘); if (line0.endsWith(F(“D”))) { if (line0.endsWith(F(“CLOSED”))) sentREQ = false; // HTTP connection closed } } } else { if (!header) { line0 = esp01.readStringUntil(‘

‘); if (line0.indexOf(F(“

“)) != -1) { header = true; line0 = “”; } } else { bool finish = false; while (esp01.available()) { char c = esp01.read(); if (c == ‘<') count++; if (count <= 50) line0 += c; else if (count > 50 && count <= 90) line1 += c; else if (count > 90) { finish = true; break; } } if (finish) { Serial.println(F(“Finished Reading”)); Serial.println(line0); Serial.println(line1); parsing(); gotWeather = true; // 날씨 작업 종료 count = 0; header = false; OK200 = false; tryCount = 0; // 초기화 sentREQ = false; } } } } else { // 날씨 이외의 경우 if (esp01.available()) { line0 = esp01.readStringUntil(‘

‘); Serial.println(line0); } } }

OPEN WEATER MAP

스케치는 프로그램 저장 공간 10142 바이트(31%)를 사용. 최대 32256 바이트.

전역 변수는 동적 메모리 407바이트(19%)를 사용, 1641바이트의 지역변수가 남음. 최대는 2048 바이트.

#include #define rxPin 3 #define txPin 2 SoftwareSerial esp01(txPin, rxPin); // SoftwareSerial NAME(TX, RX); const String ssid_AP = “ESP01”; // your network SSID (name) const String pass_AP = “12345678”; //”1234test”; // your network password char ssid[21] = “skynet”; // “SK_WiFiGIGA40F7” your network SSID (name) char pass[21] = “skynet00”; // “1712037218” your network password String ip = “”; String ap = “”; void ipCheck(String response) { int st, ed; if (response.indexOf(F(“PIP”)) != -1) { st = response.indexOf(F(“PIP”))+5; ed = response.indexOf(‘”‘, st+1); ap = response.substring(st, ed); response.remove(0, ed+1); Serial.print(F(“ap: “)); Serial.println(ap); } if (response.indexOf(F(“AIP”)) != -1) { st = response.indexOf(F(“AIP”))+5; ed = response.indexOf(‘”‘, st+1); ip = response.substring(st, ed); Serial.print(F(“ip: “)); Serial.println(ip); } } uint8_t retry = 1; String sendData(String order) { String command = F(“AT+”); command += order; command += F(“\r

“); esp01.print(command); // send the read character to the esp01 unsigned long int time = millis(); String response = “”; while( (time+20000) > millis()) { while(esp01.available()) { // The esp has data so display its output to the serial window char c = esp01.read(); // read the next character. response+=c; } if (response.indexOf(F(“OK”)) != -1) { retry = 0; Serial.println(F(“OK”)); break; } else if (response.indexOf(F(“FAIL”)) != -1 || response.indexOf(F(“ERROR”)) != -1) { if (response.indexOf(F(“FAIL”)) != -1) retry++; else if (response.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } Serial.print(command); Serial.println(F(“Failed”)); break; } } return response; } String addID(String order, String ssid_AP, String pass_AP) { String temp = order+'”‘+ssid_AP+'”‘+’,’+'”‘+pass_AP+'”‘; return temp; } void setup() { Serial.begin(9600); esp01.begin(9600); // your esp’s baud rate might be different sendData(F(“CWQIF”)); // disconnect AP if connected sendData(F(“CWQAP”)); // disconnect wifi if connected sendData(F(“CWMODE=3”)); // configure as access point (working mode: AP+STA) sendData(F(“CWDHCP=1,1”)); sendData(addID(F(“CWSAP=”),ssid_AP,pass_AP)+’,’+String(10)+’,’+String(3)); retry = 1; while(retry) { sendData(addID(F(“CWJAP=”),ssid,pass)); if (retry > 1) { Serial.print(F(“Retrying to connect: “)); Serial.println(retry-1); } if (retry > 4) { Serial.println(F(“connection failed”)); retry = 0; } } sendData(F(“CIPMUX=1”)); // configure for multiple connections sendData(F(“CIPSERVER=1,80”)); // turn on server on port 80 ipCheck(sendData(F(“CIFSR”))); // // get ip address } String json_parser(String s, String a) { String val; if (s.indexOf(a) != -1) { int st_index = s.indexOf(a); int val_index = s.indexOf(‘:’, st_index); if (s.charAt(val_index + 1) == ‘”‘) { int ed_index = s.indexOf(‘”‘, val_index + 2); val = s.substring(val_index + 2, ed_index); } else { int ed_index = s.indexOf(‘,’, val_index + 1); val = s.substring(val_index + 1, ed_index); } } else { Serial.print(a); Serial.println(F(” is not available”)); } return val; } // OPEN WEATHER MAP // https://api.openweathermap.org/data/2.5/weather?q=Seoul,KR&APPID=YOUR_API_KEY const char host[] PROGMEM = “api.openweathermap.org”; const char url[] PROGMEM = “/data/2.5/weather?q=Seoul,KR&APPID=YOUR_API_KEY”; // YOUR_API_KEY 수정 bool OK200 = false; bool sentREQ = false; bool gotWeather = false; void get_weather() { Serial.println(F(“Starting connection to server…”)); bool connectOK = false; String cip = F(“AT+CIPSTART=3,”); // connection ID 3 (ID: 0 ~ 4) cip += ‘”‘; cip += F(“TCP”); cip += ‘”‘; cip += ‘,’; cip += ‘”‘; cip += (const __FlashStringHelper *)host; cip += ‘”‘; cip += ‘,’; cip += F(“80”); // port number cip += F(“\r

“); esp01.print(cip); unsigned long int time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { connectOK = true; Serial.println(F(“OK”)); break; } else if (cip.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } } if (connectOK) { Serial.println(F(“Connected to server”)); String temp = F(“GET “); temp += (const __FlashStringHelper *)url; temp += F(” HTTP/1.1\r

Host: “); temp += (const __FlashStringHelper *)host; temp += F(“\r

Connection: close\r

\r

“); cip = F(“AT+CIPSEND=”); cip += 3; // connection ID 3 (ID: 0 ~ 4) cip += ‘,’; cip += temp.length(); cip += F(“\r

“); esp01.print(cip); time = millis(); while (time+2000 > millis()) { cip = esp01.readStringUntil(‘

‘); if (cip.indexOf(F(“OK”)) != -1) { Serial.println(F(“OK”)); break; } else if (cip.indexOf(F(“ERROR”)) != -1) { Serial.println(F(“ERROR”)); break; } } esp01.print(temp); sentREQ = true; gotWeather = true; } } // RSS 날씨 정보 저장 변수 String line = “”; uint8_t tryCount = 0; void loop() { if (!ip.startsWith(F(“0”))) { // 공유기로부터 IP주소를 할당받은 경우 if (!gotWeather) { if (tryCount < 3) { get_weather(); tryCount++; } } } while (esp01.available()) { line = esp01.readStringUntil(' '); Serial.println(line); if (sentREQ) { if (!OK200) { if (line.startsWith(F("+"))) { if (line.indexOf(F("200")) != -1) OK200 = true; else { OK200 = false; gotWeather = false; } } } else { if (line.startsWith(F("{"))) { Serial.println(line); Serial.println(F("weather data for parsing")); String description = json_parser(line, F("description")); Serial.print(F("description: ")); Serial.println(description); String pressure = json_parser(line, F("pressure")); Serial.print(F("pressure: ")); Serial.println(pressure); String wind = json_parser(line, F("speed")); Serial.print(F("wind: ")); Serial.println(wind); String Temp = json_parser(line, F("temp")); Serial.print(F("Temp: ")); Serial.println(Temp); line = ""; gotWeather = true; // 날씨 작업 종료 tryCount = 0; OK200 = false; sentREQ = false; // 초기화 } } } else { Serial.println(line); } } } 날씨 코드 설명 : [arduino] - 아두이노 - ESP01 모듈, 기상청 RSS / 오픈 웨더 맵 API 날씨 정보 받기 참조사이트 http://allaboutee.com/2014/12/30/esp8266-and-arduino-webserver/ https://room-15.github.io/blog/2015/03/26/esp8266-at-command-reference/ 관련 글 [arduino] - 아두이노 - 안드로이드를 이용한 무선 원격제어 그리고 시리얼 통신 - 1편 [arduino] - 아두이노 - 안드로이드를 이용한 무선 원격제어 그리고 시리얼 통신 - 2편 [arduino] - 아두이노 - 안드로이드를 이용한 무선 원격제어 그리고 시리얼 통신 - 3편 [arduino] - 아두이노 - 안드로이드를 이용한 무선 원격제어 그리고 시리얼 통신 - 4편 [arduino] - 아두이노 - 안드로이드를 이용한 무선 원격제어 그리고 시리얼 통신 - 5편 [arduino] - 블루투스 4.0 BLE 이용 아두이노 및 ESP32 원격제어 [arduino] - 아두이노 - 시리얼통신 주요 함수와 예제, String class [arduino] - 아두이노 - ESP01 wifi 모듈 무선 원격제어 그리고 시리얼 통신 - 6편 [arduino] - ESP8266 - NodeMcu 1.0 와이파이 이용 원격제어(soft AP, wifi) [arduino] - ESP32 - Dev Module 와이파이 이용 원격제어(soft AP, wifi) [arduino] - 아두이노 - 와이파이 모듈 ESP01, WiFiEsp.h 라이브러리 이용 웹페이지에서 디지털핀 원격제어 arduino bluetooth controller PWM - 아두이노 원격제어 안드로이드 앱 버전 3.5 다운로드 arduino bluetooth controller PWM 매뉴얼

[아두이노] 와이파이 모듈 ESP8266(ESP-01) 사용법

ESP-01

얼마 전 디바이스 마트에서 아두이노 와이파이 모듈인 ESP8266 시리얼 와이파이 모듈 ESP-01을 구매했습니다. 와이파이 기능을 구현해야 해서 모르겠고 일단 주문부터 덜컥했습니다.

디바이스 마트 ESP8266 시리얼 와이파이 모듈 ESP-01

logic level 컨버터까지 같이 구입해야 쉽게 통신이 가능하다는 걸 배송받고 알았습니다. 하지만 logic level 컨버터가 없으면 통신이 안 되는 건 아니고, 보드 연결이 귀찮아지는 정도입니다. 다시 주문하면 배송비가 또 붙으니까 그건 싫어서 컨버터 없이 쌩으로 연결했습니다.

디바이스 마트에서 제공하는 상품 상세 설명의 주의사항입니다.

상품상세설명

요약하면 다음과 같습니다.

1. 별도의 펌웨어 업로드는 필요 없다.

2. 보드 레이트는 115200으로 설정되어 있다.

3. 3.3V 전원을 인가해야 한다.

펌웨어 업데이트가 복잡하기 때문에 웬만하면 펌웨어 업데이트가 필요 없는 부품으로 구매하시기 바랍니다.

1. 보드 구성

ESP-01 모듈을 연결하기 위해서 아두이노 우노를 사용했습니다. 주의사항에서 알려준 것처럼 3.3V를 인가해야 하는데, 5V → 3.3V로 변환하는 회로 구성을 헤매다가 에듀이노 블로그 포스팅을 발견했습니다.

ESP-01, 아두이노 우노 연결 회로도 (출처 : 에듀이노 블로그)

위 회로도에서 사용된 저항은 모두 1KΩ입니다. 위와 똑같이 연결해주시면 됩니다.

보드 구성

2. AT 명령어

이제 AT Command를 통해 와이파이 모듈을 세팅해 줄 차례입니다. 아까 주의사항에서 ESP01 모듈의 기본 보드 레이트가 115200이라고 알려줬었습니다. 그래서 아두이노 우노와 와이파이 모듈의 보드 레이트를 모두 115200으로 설정해줬습니다.

#include int RX = 2; int TX = 3; SoftwareSerial ESP01(RX, TX); void setup() { Serial.begin(115200); //아두이노 우노 보드레이트 115200 ESP01.begin(115200); //와이파이 모듈 보드레이트 115200 ESP01.setTimeout(5000); delay(1000); } void loop() { if (Serial.available()){ ESP01.write(Serial.read()); } if (ESP01.available()) { Serial.write(ESP01.read()); } }

위 코드를 보드에 업로드하고 시리얼 모니터를 실행시킵니다. 시리얼 모니터의 보드 레이트 또한 115200으로 변경해주세요.

시리얼 모니터

이제 AT를 쳤을 때 OK가 출력되면 정상적으로 연결이 된 것입니다.

AT 명령어 성공

여기서 AT가 무응답이라면 아래 3가지를 확인해주세요.

1. 모듈 구매처에서 펌웨어 버전 확인 (펌웨어 업데이트가 필요할 수도 있습니다.)

2. 모듈 구매처에서 기본 보드레이트 확인 후 115200이 아니라면 코드 변경

3. 시리얼 모니터 보드레이트 확인

4. line ending 없음, 새 줄, 캐리지 리턴, Both NL&CR 돌아가면서 확인

이 모듈 자체가 워낙 저가라서 잘 고장난다고 합니다. 위 사항을 모두 체크해도 명령어가 먹지 않는다면 점퍼 케이블이나 모듈에 이상이 있을 수도 있으니 다른 전선&모듈로 확인하시기 바랍니다.

이제 AT 명령어로 WIFI 모드를 설정하고 주변 와이파이를 스캔했습니다.

AT+CWMODE = 1 // Station Mode AT+CWLAP // 주변 AP 리스트 출력

주변 AP 리스트 출력 -실패

글자가 다 깨져서 출력이 되었습니다. 보드레이트가 115200라서 통신 속도가 빨라서 글자가 깨진 것 같았습니다. 그래서 AT+UART_DEF=명령어를 통해서 와이파이 모듈의 보드레이트를 9600으로 변경하고, 코드를 변경했습니다.

AT+UART_DEF=9600,8,1,0,0 // 와이파이 모듈 보드레이트 9600으로 변경

#include int RX = 2; int TX = 3; SoftwareSerial ESP01(RX, TX); void setup() { Serial.begin(9600); //아두이노 우노 보드레이트 9600 ESP01.begin(9600); //와이파이 모듈 보드레이트 9600 ESP01.setTimeout(5000); delay(1000); } void loop() { if (Serial.available()){ ESP01.write(Serial.read()); } if (ESP01.available()) { Serial.write(ESP01.read()); } }

주변 AP 리스트 출력 – 성공

보드레이트를 9600으로 변경하고 나니 정상적으로 출력이 되었습니다.

AT+CWJAP=”SSID”,”PASSWORD” // 와이파이 연결 AT+CWJAP? // 연결된 와이파이 출력 AT+CWQAP // 와이파이 연결 해제

와이파이 연결, 해제

와이파이 모듈은 처음 사용해봤는데 어마어마하게 삽질했습니다. 성공해서 다행이지 실패했다면 4개나 산 모듈을 처분하지도 못하고 울고있었을것 같습니다 😭 초기세팅은 성공해서 마음이 놓이네요. 삽질하면서 블로그를 많이 찾아봤는데 너무 복잡한 방법이 많아서 단순하게 정리해봤습니다. 세팅하는데 어려움을 겪고 있다면 언제든지 댓글로 물어봐주세요 🙂

잘못된 내용이 있다면 언제든지 댓글이나 메일로 알려주시면 감사하겠습니다.

이 포스팅이 도움이 되었다면 공감 부탁드립니다.

궁금한 점은 언제든지 댓글 남겨주시면 답변해드리겠습니다 😀

라즈이노 iOT :: 【 아두이노모듈#25】ESP8266 esp-01 활용하기#1 : 펌웨어 업뎃(내용보강-완료, 영상추가)

espressif/ESP8266_AT

This project is not maintained, please use https://github.com/espressif/esp-at. – espressif/ESP8266_AT

github.com

ESP8266 Wifi 모듈/ESP-01/Arduino/아두이노/와이파이

해외 및 국내 판매자의 “해외 브랜드 상품”을 여러 배송방법 (국내배송, 해외직배송 등)을 통해 판매하고 있으며, 국내에서 접하기 힘든 다양한 해외 현지 상품을 보다 안전하고 저렴하게 구매할 수 있습니다.

개인통관고유부호의 신규발급 및 사용내역, 통관정보, 예상 세액 조회 등은 관세청 홈페이지의 “해외직구 여기로” 사이트를 통해 확인 가능합니다. 해외직구 여기로

개인 식별을 위한 고유번호로, 관세청 전자통관시스템에서 신청 즉시 발급 가능하며 한 번 발급된 번호로 계속 사용 가능합니다. 개인통관고유번호 신청하러가기

관세

구매대행업자를 통한 수입인 경우에도 납세의무, 수입요건 확인 등은 구매자에게 책임이 있습니다.

해외직배송 상품 구매 시 개인이 자가사용 목적으로 수입하는 개인 수입 통관 원칙에 의거, 총 구매금액이 약 $150(미국 목록통관 물품의 경우 $200)이 넘는 경우 고객님께서 대한민국 세관에 관세 및 수입부가세를 납부해주셔야 하며, 환율 변동에 따라 관부가세가 달라질 수 있습니다.

해외직구로 구매한 여러 개의 물품이 동일한 날짜에 통관 될 경우 합산과세(별개의 과세단위를 서로 합하여 과세)가 부과될 수 있습니다.

– 수령인이 동일한 2건 이상의 물품이 같은 날짜에 통관이 진행되어 당일 관세신고 금액이 무관세

기준을 초과하는 경우 (단, 서로 다른 국가에서 발송되었다면 제외)

– $150 이하의 상품을 복수개 구매하여 총 결제금액이 약 $150를 초과하는 경우 등

와이파이 모듈 ESP8266 아두이노 WIFI ESP-01

상품 수령 후 7일 이내에 신청하실 수 있습니다. 단, 제품이 표시·광고 내용과 다르거나, 계약과 다르게 이행된 경우는 제품 수령일부터 3개월 이내, 그 사실을 안 날 또는 알 수 있었던 날부터 30일 이내에 교환/반품이 가능합니다.

추가적으로 다음의 경우 해당하는 반품/교환은 신청이 불가능할 수 있습니다. 소비자의 책임 있는 사유로 상품 등이 멸실 또는 훼손된 경우 (단지, 상품 확인을 위한 포장 훼손 제외) 소비자의 사용 또는 소비에 의해 상품 등의 가치가 현저히 감소한 경우 시간의 경과에 의해 재판매가 곤란할 정도로 상품 등의 가치가 현저히 감소한 경우 복제가 가능한 상품 등의 포장을 훼손한 경우 소비자의 주문에 따라 개별적으로 생산되는 상품이 제작에 들어간 경우

ESP01 (ESP8266) 사용하기

아두이노 ESP01 모듈 사용하기

조대협 (http://bcho.tistory.com)

아두이노 WIFI 모듈

아두이노 WIFI 모듈은 여러가지가 있는데, 아두이노용으로 나온 와이파이 실드의 경우에는 가격이 비싸다. (아두이노에서 WIFI 연결하는 방법은 http://bcho.tistory.com/1280 자료 참고) 그래서 가장 범용적으로 사용되는 칩셋은 ESP8266 칩셋인데, ESP8266 칩셋으로 나온 보드는 여러가지가 있다. ESP01~ESP14 모듈등이 있고, 조금더 사용이 편한 모듈로는 nodemcu와 같은 모듈이 있다.

ESP8266 모듈 시리즈 https://en.wikipedia.org/wiki/ESP8266

오늘 다루는 모듈은 이중에서 가장 저렴한 ESP01 모듈이다.

아두이노에서 이모듈을 사용하기에는 몇가지 넘어야할 산이 있다.

전원

ESP 01은 3V로 동작을 하는데, 전류 소모량이 많다. 그래서 아두이노 보드의 3.3V 단자에 연결하게 되면 전력양이 낮아서 오작동하는 경우가 많고 GND와 전원으로 들어가는 선이 많아서, 아래와 같이 배선이 복잡해진다.

<출처 : https://m.blog.naver.com/roboholic84/221261124179>

통신속도와 펌웨어 업그레이드

그리고 가장 난관중 하나가, 아두이노의 시리얼 통신의 경우 9600bps를 사용하는데, 불행하게도 ESP01의 기본 통신속도는 115200bps로 설정되어 있기 때문에 펌웨어 업그레이드를 통해서 디폴트 통신 속도를 9600 bps로 변경해줘야 한다. 이 과정에 여러 배선 설계를 해야 하고 별도의 펌웨어 업그레이드 프로그램을 설치해야하기 때문에 그 과정이 까다롭다.

<그림 USB to ESP01 연결 아답터>

그래서 아두이노 보드를 거치지 않고 바로 PC USB에서 ESP01로 연결을해서 쉽게 펌웨어를 업데이트할 수 있게 해주는 USB to ESP01 아답터가 있기는 하지만 여전히 펌웨어 업데이트가 필요하다.

ESP01 아답터

그래서 검색을 하다 찾은 아답터가 ESP01 아답터 이다.

이렇게 아답터 위에 ESP01 보드를 설치하면 되는 형태이다. (구매 링크)

https://m.blog.naver.com/roboholic84/221261124179 글에 상세한 소개와 설명이 잘 나와 있는데, 따라해보니 ESP01의 펌웨어 자체가 업그레이드 되어 있어서, 명령어가 동작하지 않는 부분이 있어서 몇가지 수정을 하였다. 포스팅 내용을 참고하여 몇가지 부분을 수정하였다.

배선 작업은 아래와 같다.

대략 빵판에 연결하면 다음과 같은 모습이된다.

레큘레이터가 내장되어 있기 때문에 아두이노 5V에 VCC를 연결하면 되고, RX와 TX를 각각 3번과 2번 포트에 연결한다.

다음에 아래와 같은 코드를 작성하여 실행한다.

#include

SoftwareSerial mySerial(2, 3); // RX, TX

void setup() {

Serial.begin(9600);

mySerial.begin(115200);

}

void loop() {

if (mySerial.available()) {

Serial.write(mySerial.read());

}

if (Serial.available()) {

mySerial.write(Serial.read());

}

}

위의 예제는 아두이노 콘솔에서 받은 명령을 ESP01 시리얼 포트로 전송하고 ESP01 에서 나온 결과값을 아두이노 콘솔에 출력하도록 하는 코드이다. ESP01의 디폴트 통신속도가 115200이기 때문에 mySerial.begin에서 통신 속도를 115200으로 설정하였다. (추후 바꿀것이다.)

를 실행해서 AT 명령을 실행해보자. 연결이 제대로 되었으면 아래와 그림과 같이 OK 응답이 오는 것을 볼 수 있다.

다음 ESP01 보드의 통신 속도를 변경해보자,원본 문서에는 AT+CIOBAUD=9600 명령으로 변경하도록 되어 있는데, 이 명령은 최신 펌웨어에서는 동작하지 않고 AT+IPR이라는 명령을 사용해야 하는데, 이 명령은 연결되어 있는 동안만 통신 속도를 변경하고 다시 ESP01 디바이스를 뺐다가 다시 끼면 원래 통신속도로 돌아간다.

ESP01의 통신속도를 영구적으로 바꿔줄 수 있는 명령이 있는데, AT_UART_DEF라는 명령을 사용하면 된다. (참고 : https://www.esp8266.com/viewtopic.php?f=13&t=718)

사용법 : AT+ UART_DEF=,,,,

통신속도를 9600으로 영구적으로 변경하기 위해서는 아래 명령을 수행한다.

AT+UART_DEF=9600,8,1,0,0

통신 속도를 9600으로 변경하였기 때문에 코드상에서도 ESP01로 통신하는 속도를 9600으로 변경해줘야 한다.

mySerial.begin(115200);

부분을

mySerial.begin(9600);

으로 변경하여 실행하자

WIFI 연결 테스트

네트워크 모드

ESP8266은 네트워크 연결에 대해 3가지 모드를 제공한다.

1 : Stand alone

2 : AP

3 : AP + Standalone

Stand alone 모드는 클라이언트로 작동하는 모드로 AP에 붙어서 네트워크 통신을 할 수 있다.

AP 모드는 ESP8266이 서버가 되는 모드로 다른 단말이 ESP8266에 Wifi로 연결될 수 있게 한다. 그리고 AP+Stand alone 모드는 서버와 클라이언트를 동시에 지원하는 모드이다. 여기서는 1번 AP+Standalone 모드를 사용하도록 하겠다.

모드 전환은 AT+CWMODE={모드 번호}로 가능하다

WIFI 연결하기

클라이언트 모드로 연결을 하였으면 WIFI에 연결해보자.

WIFI 목록을 찾는 명령은 AT+CWLAP 이다. 명령을 실행하면 아래 그림과 같이 연결 가능한 WIFI 목록이 출력된다.

다음 AT+CWJAP=”SSID”,”비밀번호” 명령을 이용하여 연결하고자 하는 WIFI 네트워크에 연결이 가능하다. 여기서는 U+NetC070 네트워크에 연결해보도록 하겠다

AT+CWJAP=”U+NetC070″,”WIFI비밀번호”

명령을 실행하면 아래와 같이 WIFI에 연결이 된것을 확인할 수 있다.

연결이 완료 되었으면

AT+CIFSR

명령을 이용하면 연결된 IP 주소를 읽어낼 수 있다.

이렇게 연결이 된 상태에서는 아두이노의 전원을 껐다가 켜도 다시 같은 네트워크로 자동으로 붙기 때문에, 연결을 명시적으로 끊으려면

AT+CWQAP

명령을 이용하여 명시적으로 연결을 끊어줘야 한다.

다음글에서는 ESP01 모듈을 이용하여 서버와 HTTP 통신을 하는 방법에 대해서 알아보도록 한다.

AT 명령어 모음 https://www.electrodragon.com/w/ESP8266_AT-Command_firmware

ESP8266 WIFI 연결 가이드 https://tttapa.github.io/ESP8266/Chap07%20-%20Wi-Fi%20Connections.html

[엘레파츠] 아두이노 WIFI 킷트 개발보드/프로그래머 > 오픈소스H/W > 아두이노 > 키트 (주)엘레파츠

개발보드/프로그래머 반도체 수동부품 전자기계/통신 커넥터/PCB 센서/디스플레이 개발보드/프로그래머 배터리/전원/전선 자동제어/임베디드/열관리 하드웨어/지원부품/엔클로저 기계/모터/동력/유압,공압 로봇/3D프린터/IOT기기 드론/액션캠/무선모형 공구/수납 테스트/계측기/광학 화학제품/산업안전 컴퓨터/주변기기/네트워크 모바일/가전/차량용품 오피스/서적/소프트웨어 아웃도어/레저/취미

오픈소스H/W 오픈소스H/W 코딩&STEAM교육 개발보드/평가기판 프로그래머/다운로더 영상전송/음성인식 전자실험킷트/DIY킷트 부품샘플킷트 스토어 웨어러블 Digilent

아두이노 라즈베리파이 라즈베리파이 PICO 아두이노 ASUS NUC/에디슨/PHPoC Digilent/비글본/RedPitaya 기타 확장보드 ESP 딥러닝

키트 정품 호환보드 호환쉴드 키트 아두이노 센서모듈 통신/모터제어/기타 디스플레이 아두이노 악세사리 아두이노서적

1. 주문하신 물품의 총 결제금액이 15만원 이상 (환율의 변동에 따라 다를 수 있음) 이면 과부가세가 발생합니다. 관부가세는 고객님께서 부담하시는 금액으로 문자를 통해 입금내역이 발송되며 해당 관세사로 입금하시면 통관처리됩니다.

2. 해외구매 특성상 주문에서 배송까지는 평균 10~15일이 소요됩니다. 간혹 현지 제품 수급에 따라 부득이하게 시일이 더 소요 될 수 있으니 구매시 좀 더 여유있게 주문하시길 권합니다.

3. 해외 내수품인 관계로 A/S에 대해서는 별도의 책임을 지지 않습니다.

4. 해외배송 특성상 주문접수후 배송상태가 배송준비중으로 넘어간 경우 해외에서 국내로의 배송이 이루어지고 있다는 뜻입니다. 따라서 배송준비중으로 배송상태가 넘어간 경우 취소및 반품이 불가하므로 이점 양해 부탁드립니다.

5. 타 해외구매대행 사이트에서 주문하신 물건과 주문날짜가 겹치지않도록 주의해 주십시오. 통관날짜가 같을 경우 합산관세가 부가되게 됩니다.

키워드에 대한 정보 아두 이노 wifi 모듈

다음은 Bing에서 아두 이노 wifi 모듈 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.

이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!

사람들이 주제에 대해 자주 검색하는 키워드 [ESP8266] 드디어!! ESP8266을 인터넷에 접속 시켜보자!

  • ESP8266
  • 아두이노
  • 아두이노 강좌
  • 아두이노 중급
  • 아두이노 고급
  • 아두이노 인터넷
  • 러봇랩
  • 로봇랩
  • lovot lab
  • 미디어아트
  • 코딩
[ESP8266] #드디어!! #ESP8266을 #인터넷에 #접속 #시켜보자!


YouTube에서 아두 이노 wifi 모듈 주제의 다른 동영상 보기

주제에 대한 기사를 시청해 주셔서 감사합니다 [ESP8266] 드디어!! ESP8266을 인터넷에 접속 시켜보자! | 아두 이노 wifi 모듈, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.

See also  밍크 코트 리폼 | \"밍크 조끼로 리폼하기\" 1 66 개의 정답

Leave a Reply

Your email address will not be published. Required fields are marked *