반응형

아두이노를 인터넷에 연결하기 위한 방법으로는 예전에 소개했던 ESP8266 와이파이 모듈을 이용한 방법도 있으나 랜선 연결을 통하여 유선으로 인터넷에 연결하는 방법도 있다. 바로 ENC28J60 이라는 모듈이다. 현재 인터넷에서 만원 이하의 가격으로 구할 수 있는 기존 아두이노 이더넷 쉴드 대비 훨씬 저렴한 인터넷 연결 모듈이다. 

 

연결 단자는 총 10개가 있으며 각각의 용도는 위와 같다.

 

ENC28J60 모듈의 뒷면

 

■ ENC28J60 Data Sheet

ENC28J60.pdf
다운로드

 

 

■ Ethercard Library (ENC28J60)

ethercard-master.zip
다운로드

 

라이브러리는 https://github.com/jcw/ethercard 에서 다운로드 받는다.

라이브러리의 설치는 아두이노 IDE 설치폴더 하위의 libraries 폴더에 위의 ZIP 파일의 압축을 풀어 복사해 넣으면 된다.

 

연결

라이브러리 홈페이지에서 캡처한 아두이노 우노와 메가의 핀연결 방법

 

 

아두이노 우노와의 연결 모습 10개중 6개의 핀을 연결하였다.

 

 

DHCP 테스트

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <EtherCard.h>
 
//MAC주소-아래에서 지정한대로 설정됨
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
 
//이더넷 송수신 데이터 메모리 버퍼 설정
byte Ethernet::buffer[700];
 
void setup () {
  Serial.begin(57600);
  Serial.println(F("\n[testDHCP]"));
 
  //MAC 주소 찍기
  Serial.print("MAC: ");
  for (byte i = 0; i < 6++i) {
    Serial.print(mymac[i], HEX);
    if (i < 5)
      Serial.print(':');
  }
  Serial.println();
 
  //이더넷 연결 실패
  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0
    Serial.println(F("Failed to access Ethernet controller"));
  
  //DHCP 설정
  Serial.println(F("Setting up DHCP"));
  if (!ether.dhcpSetup())
    Serial.println(F("DHCP failed"));
  
  ether.printIp("My IP: ", ether.myip);
  ether.printIp("Netmask: ", ether.netmask);
  ether.printIp("GW IP: ", ether.gwip);
  ether.printIp("DNS IP: ", ether.dnsip);
}
 
void loop () {}
cs

 

공유기에 연결하여 IP, 게이트웨이, DNS, Netmask 등의 값을 설정하고 받아온다.

 

공유기의 DHCP에 의해 IP가 192.168.0.14 로 할당되었고 다른 네트워크 정보도 자동으로 설정되고 MAC 주소를 변경하지 않는다면 공유기에서 계속 이 IP를 사용하게 된다.

 

 

PING 테스트

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// Ping a remote server, also uses DHCP and DNS.
// 2011-06-12 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
 
#include <EtherCard.h>
 
// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
 
byte Ethernet::buffer[700];
static uint32_t timer;
 
// called when a ping comes in (replies to it are automatic)
// PING 을 받으면 보내주는 Call Back
static void gotPinged (byte* ptr) {
  ether.printIp(">>> ping from: ", ptr);
}
 
void setup () {
  Serial.begin(57600);
  Serial.println("\n[pings]");
  
  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
    Serial.println(F("Failed to access Ethernet controller"));
  if (!ether.dhcpSetup())
    Serial.println(F("DHCP failed"));
 
  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);
 
#if 1
  // use DNS to locate the IP address we want to ping
  if (!ether.dnsLookup(PSTR("www.google.com")))
    Serial.println("DNS failed");
#else
  ether.parseIp(ether.hisip, "74.125.77.99");
#endif
  ether.printIp("SRV: ", ether.hisip);
    
  // call this to report others pinging us
  ether.registerPingCallback(gotPinged);
  
  timer = -9999999// start timing out right away
  Serial.println();
}
 
void loop () {
  word len = ether.packetReceive(); // go receive new packets
  word pos = ether.packetLoop(len); // respond to incoming pings
  
  // report whenever a reply to our outgoing ping comes back
  if (len > 0 && ether.packetLoopIcmpCheckReply(ether.hisip)) {
    Serial.print("  ");
    Serial.print((micros() - timer) * 0.0013);
    Serial.println(" ms");
  }
  
  // ping a remote server once every few seconds
  if (micros() - timer >= 5000000) {
    ether.printIp("Pinging: ", ether.hisip);
    timer = micros();
    ether.clientIcmpRequest(ether.hisip);
  }
}
cs
 
<spanstyle="font-family: nanum="" gothic,="" gothic;="" font-size:="" 11pt;">이 소스는 Google 의 IP를 알아와서 Ping 을 해보고 반대로 아두이노에 Ping이 들어왔을때 응답(Call Back) 해 주는 소스이다.
</spanstyle="font-family:>
 

아두이노에 Ping 호출

 

Google 의 Ping 과 아두이노로 Ping을 보낸 컴퓨터의 정보 표시

 

Ping 호출에 대한 응답이 정상적으로 이루어지니 미니 웹서버로의 활용도 가능해 보인다.

 

 

 

미니 웹서버

웹브라우저의 요청에 준비된 HTML을 뿌려주는 기능이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// Present a "Will be back soon web page", as stand-in webserver.
// 2011-01-30 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
 
#include <EtherCard.h>
 
//0은 DHCP, 1은 Static으로 설정
#define STATIC 0  // set to 1 to disable DHCP (adjust myip/gwip values below)
 
//Static IP 일 경우 설정
#if STATIC
// ethernet interface ip address
static byte myip[] = { 192,168,1,200 };
// gateway ip address
static byte gwip[] = { 192,168,1,1 };
#endif
 
// ethernet mac address - must be unique on your network
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
 
byte Ethernet::buffer[500]; // tcp/ip send and receive buffer
 
//요청이 왔을 경우 뿌려줄 HTML 소스
const char page[] PROGMEM =
"HTTP/1.0 503 Service Unavailable\r\n"
"Content-Type: text/html\r\n"
"Retry-After: 600\r\n"
"\r\n"
"<html>"
  "<head><title>"
    "아두이노 웹서버 입니다."
  "</title></head>"
  "<body>"
    "<h3>아두이노 웹서버</h3>"
    "<p><em>"
      "아두이노 웹서버 입니다.<br />"
      "공사중 입니다."
    "</em></p>"
  "</body>"
"</html>"
;
 
void setup(){
  Serial.begin(57600);
  Serial.println("\n[backSoon]");
  
  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0
    Serial.println( "Failed to access Ethernet controller");
#if STATIC
  ether.staticSetup(myip, gwip);
#else
  if (!ether.dhcpSetup())
    Serial.println("DHCP failed");
#endif
 
  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);  
  ether.printIp("DNS: ", ether.dnsip);  
}
 
void loop(){
  //웹브라우저의 요청이 들어왔을 경우 page 의 내용을 보내줌
  // wait for an incoming TCP packet, but ignore its contents
  if (ether.packetLoop(ether.packetReceive())) {
    memcpy_P(ether.tcpOffset(), page, sizeof page);
    ether.httpServerReply(sizeof page - 1);
  }
}
cs

브라우저에 아두이노의 IP를 입력하면 ENC28J60은 TCP 패킷을 받게 된다. 이 요청에 아두이노에 저장된 HTML 소스(page 변수) 를 웹브라우저로 보내주는 소스이다. 공유기 환경의 경우 포트포워딩을 이용하면 외부 인터넷에서도 접근이 가능하게 만들 수 있다.

 

웹브라우저에서 아두이노에 할당된 IP를 입력하면 위와 같이 나오게 된다.

 

 

트위터에 글 보내기

트위터에 글을 보내기 위해서는 우선 트위터 계정이 있어야 하며 트위터에 아두이노가 로그인하기 위한 인증키(보안토큰)를 발급 받아야 한다.

 

http://arduino-tweet.appspot.com/oauth/twitter/login 사이트에 들어가서 트위터 아이디와 패스워드를 입력하고 Authorize App 을 클릭한다.

 

잠시 후 인증이 완료되고 보안토큰의 값이 나온다. 이를 복사하여 아래의 소스 17행에 붙여 넣기 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Twitter client sketch for ENC28J60 based Ethernet Shield. Uses 
// arduino-tweet.appspot.com as a OAuth gateway.
// Step by step instructions:
// 
//  1. Get a oauth token:
//     http://arduino-tweet.appspot.com/oauth/twitter/login
//  2. Put the token value in the TOKEN define below
//  3. Run the sketch!
//
//  WARNING: Don't send more than 1 tweet per minute! (1분에 1개 이상의 트위터를 보내지 마시오)
//  NOTE: Twitter rejects tweets with identical content as dupes (returns 403)
 
#include <EtherCard.h>
 
// 트위터 API 이용을 위해 OAUTH 토큰값을 넣는다. (트위터 ID/패스워드 필요)
// http://arduino-tweet.appspot.com/oauth/twitter/login 여기에서 트위터 로그인하고 토큰발급 받는다.
#define TOKEN   "발급받은 토큰값을 여기에 입력"
 
// ethernet interface mac address, must be unique on the LAN
byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x63 };
 
const char website[] PROGMEM = "arduino-tweet.appspot.com";
 
static byte session;
 
byte Ethernet::buffer[700];
Stash stash;
 
static void sendToTwitter () {
  Serial.println("Sending tweet...");
  byte sd = stash.create();
 
  const char tweet[] = "hello world!!!!!!"//트위터에 올릴 글 내용
  stash.print("token=");
  stash.print(TOKEN);
  stash.print("&status=");
  stash.println(tweet);
  stash.save();
  int stash_size = stash.size();
 
  // Compose the http POST request, taking the headers below and appending
  // previously created stash in the sd holder.
  Stash::prepare(PSTR("POST http://$F/update HTTP/1.0" "\r\n"
    "Host: $F" "\r\n"
    "Content-Length: $D" "\r\n"
    "\r\n"
    "$H"),
  website, website, stash_size, sd);
 
  // send the packet - this also releases all stash buffers once done
  // Save the session ID so we can watch for it in the main loop.
  session = ether.tcpSend();
}
 
void setup () {
  Serial.begin(57600);
  Serial.println("\n[Twitter Client]");
 
  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0
    Serial.println(F("Failed to access Ethernet controller"));
  if (!ether.dhcpSetup())
    Serial.println(F("DHCP failed"));
 
  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);  
  ether.printIp("DNS: ", ether.dnsip);  
 
  if (!ether.dnsLookup(website))
    Serial.println(F("DNS failed"));
 
  ether.printIp("SRV: ", ether.hisip);
 
  sendToTwitter();
}
 
void loop () {
 
  //트위터 서버로 부터 받은 결과를 출력
  ether.packetLoop(ether.packetReceive());
  
  const char* reply = ether.tcpReply(session);
  if (reply != 0) {
    Serial.println("Got a response!");
    Serial.println(reply);
  }
 
}
 
cs

 

소스를 업로드 하고 트위터를 들어가서 보면 다음과 같이 소스에서 설정한 글이 올라가 있다.

 

 

트위터 보내기에서 중요한 점은 적어도 글을 올리고 1분 뒤에 글을 올려야 한다는 것이다. 그리고 같은 글을 계속 보내도 차단 될 수 있다고 한다. 만약 에러가 나는 사람은 1분 이상 기다렸다가 다시 시도해 보거나 트위터 내용을 다른 글로 수정하고 보내면 될 것이다.

 

 

웹서버로 데이터 보내기 (GET 방식)

아두이노가 웹클라이언트로 웹서버에 데이터를 보낼 수도 있다. 이를 위해서는 데이터를 받을 별도의 웹서버가 필요하며 받을 데이터를 처리할 웹프로그래밍이 필요하다. 예를 들면 아두이노에서 온도 데이터를 웹서버로 보냈다면 이를 받아서 DB에 저장하는 등의 처리과정이 필요한 것이다. 아무튼 웹서버에서 데이터를 받아서 어떻게 처리하는지는 각자의 목적이 다를 것이므로 여기서는 ENC28J60 과 아두이노를 이용해서 GET 방식으로 웹서버에 데이터를 보내는 방법을 알아보겠다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 
// Demo using DHCP and DNS to perform a web client request.
// 2011-06-08 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
 
#include <EtherCard.h>
 
// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
 
byte Ethernet::buffer[700];
static uint32_t timer;
 
//GET 방식으로 데이터를 보낼 주소
const char website[] PROGMEM = "192.168.0.7";
 
// called when the client request is complete
static void my_callback (byte status, word off, word len) {
  Serial.println(">>>");
  Ethernet::buffer[off+300= 0;
  Serial.print((const char*) Ethernet::buffer + off);
  Serial.println("...");
}
 
void setup () {
  Serial.begin(57600);
  Serial.println("\n[webClient]");
 
  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0
    Serial.println( "Failed to access Ethernet controller");
  if (!ether.dhcpSetup())
    Serial.println("DHCP failed");
 
  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);  
  ether.printIp("DNS: ", ether.dnsip);  
 
  if (!ether.dnsLookup(website))
    Serial.println("DNS failed");
    
  ether.printIp("SRV: ", ether.hisip);
}
 
void loop () {
  ether.packetLoop(ether.packetReceive());
  
  if (millis() > timer) {
    timer = millis() + 5000;    //5초마다 보냄
    Serial.println();
    Serial.print("<<< REQ ");
    
    //웹서버 포트 입력
    ether.hisport = 80;
 
    //GET 방식으로 데이터를 받을 URL 과 보낼 데이터
    ether.browseUrl(PSTR("/receive/receive.php?"), "get=Hello", website, my_callback);
  }
}
cs

 

위의 소스는 'http://192.168.0.7/receive/receive.php' 주소에 get의 ID 값으로 Hello 라는 데이터를 보내는 예제이다. 8행 MAC 주소, 14행 사이트 주소, 52행 포트번호, 55행 데이터 받을 웹주소 및 보낼 데이터 등은 자신의 상황에 맞게 수정이 필요하다.

 

ENC28J60을 잘 활용한다면 원격지에서 특정지역의 날씨데이터를 측정하여 웹서버로 보내 데이터베이스를 구축한다거나 요즘 뜨고 있는 IoT 기술 등에도 쓰일 수 있을 것 같다.

반응형

+ Recent posts