Arduinoと無線LANで通信する(ESP8266 6)


ESP8266用のライブラリはいくつかありますが、所詮シリアル通信でATコマンドを投げているだけなので、
ライブラリを使わずに通信してみることにしました。
同時に、ESP8266とどのようなやり取りをしているかモニターしてみます。
一連のATコマンドについてはこ ちらを参考にさせていただきました。

最初に、Raspberryがサーバー、Arduino+ESP8266がクライアントの動作を紹介します。
Raspberry側のプログラムはこちらで使ったものです。

Arduino側のスケッチは以下の通りです。
SIDにはアクセスポイントのSSID、PASSにはそのパスワード、SERVERには相手側のIPアドレスを指定してください。

errorDisplay関数は何も実装していませんのでお好みで....
また、sendCommand() waitForString() errorDisplay() clearBuffer() はセットなので
カプセル化してもいいかもしれません。

/*
 * ESP8266 TCP Client with AT Command
 * 
 * ESP8266----------ATmega168/268
 * ESP8266_TX    -> RX(D3)
 * ESP8266_RX    -> TX(D2)
 *
 */

#include <SoftwareSerial.h>

#define rxPin 2    // PD2
#define txPin 3    // PD3
#if defined(__AVR_ATmega328P__)
  #define Model "ATmega328P"
#else
  #define Model "ATmega168P"
#endif

#define SID         "アクセスポイントのSSID"
#define PASS        "アクセスポイントのパスワード"
#define SERVER      "192.168.111.20"
#define PORT        "9876"
#define INTERVAL    5000

//answer strings from ESP
//char str_buffer[64];
//command strings to ESP
char cmd[64];
long next;

SoftwareSerial myESP8266(rxPin, txPin); // RX, TX

void setup(void)
{
  Serial.begin(9600);

  //Make sure ESP8266 is set to 4800
  myESP8266.begin(4800);
  delay(100);

  //Local echo off
  sendCommand("ATE0");
  if (!waitForString("OK", 2, 1000)) {
    errorDisplay("ATE0 Fail");
  }
  clearBuffer();

  //Disconnect from AP
  sendCommand("AT+CWQAP");
  if (!waitForString("OK", 2, 1000)) {
    errorDisplay("AT+CWQAP Fail");
  }
  clearBuffer();

  //Set Wifi softAP + station mode
  sendCommand("AT+CWMODE=3");
  if (!waitForString("OK", 2, 1000)) {
    errorDisplay("AT+CWMODE fail");
  }
  clearBuffer();

  //Enable DHCP
  sendCommand("AT+CWDHCP=2,1");
  if (!waitForString("OK", 2, 1000)) {
    errorDisplay("AT+CWDHCP fail");
  }
  clearBuffer();

  //Connect to AP
  sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"", SID, PASS);
  sendCommand(cmd);
  if (!waitForString("OK", 2, 10000)) {
    errorDisplay("AT+CWJAP Fail");
  }
  clearBuffer();

  //Get local IP address
  sendCommand("AT+CIPSTA?");
  if (!waitForString("OK", 2, 1000)) {
    errorDisplay("AT+CIPSTA? Fail");
  }
  clearBuffer();

  //Delete TCP server
  sendCommand("AT+CIPSERVER=0");
  if (!waitForString("OK", 2, 1000)) {
    errorDisplay("AT+CIPSERVER Fail");
  }
  clearBuffer();

  //Enable single connections
  sendCommand("AT+CIPMUX=0");
  if (!waitForString("OK", 2, 1000)) {
    errorDisplay("AT+CIPMUX Fail");
  }
  clearBuffer();


  next = millis();

}

void loop(void) {
  static int num = 0;
  char smsg[64];
  char rmsg[64];
  short sz_smsg;

//  if (((signed long)(millis() - next)) > 0) {
  if (num == 0) {
    next = millis() + INTERVAL;
    //Start connection
    //Send AT+CIPSTART="TCP","192.168.XXX.XXX",PORT
    sprintf(cmd, "AT+CIPSTART=\"TCP\",\"%s\",%s", SERVER,PORT);
    sendCommand(cmd);
    if (!waitForString("OK", 2, 10000)) {
      errorDisplay("AT+CIPSTART Fail");
    } else {
      clearBuffer();
      sprintf(smsg,"data from %s %05d",Model,num);
      num++;
      sz_smsg=strlen(smsg);
      //Send AT+CIPSEND=nn
      sprintf(cmd,"AT+CIPSEND=%d",sz_smsg);
      sendCommand(cmd);
      if (!waitForString(">", 1, 1000)) {
        errorDisplay("AT+CIPSEND Fail");
      } else {
        clearBuffer();
        //Send data
        sendCommand(smsg);
        waitForString("OK", 2, 1000);
        clearBuffer();
        //Read data
        readResponse(-1, rmsg, sizeof(rmsg), 5000);
        clearBuffer();
        //Close TCP connection
        sendCommand("AT+CIPCLOSE");
        if (!waitForString("OK", 2, 1000)) {
          errorDisplay("AT+CIPCLOSE Fail");
        }
        clearBuffer();
      }
    }
  }
   

}

//Wait for specific input string until timeout runs out
bool waitForString(char* input, int length, unsigned int timeout) {

  unsigned long end_time = millis() + timeout;
  char current_byte = 0;
  int index = 0;

   while (end_time >= millis()) {
   
      if(myESP8266.available()) {
       
        //Read one byte from serial port
        current_byte = myESP8266.read();
        Serial.print(current_byte);
        if (current_byte != -1) {
          //Search one character at a time
          if (current_byte == input[index]) {
            index++;
           
            //Found the string
            if (index == length) {             
              return true;
            }
          //Restart position of character to look for
          } else {
            index = 0;
          }
        }
      }
  } 
  //Timed out
  return false;
}

//Remove all bytes from the receive buffer
void clearBuffer() {
  while (myESP8266.available())
    myESP8266.read();
  Serial.println("");

}

//Send AT command
void sendCommand(char* buff) {
  Serial.print(buff);
  Serial.println("-->");
  myESP8266.println(buff);
  myESP8266.flush();
}

//Print error
void errorDisplay(char* buff) {

}

//Receive Message
int readResponse(int id, char * buf,int sz_buf, int timeout) {
  int len=0;
  int flag=0;
  int datalen;
  long int time = millis();

  // id < 0  +IPD,nn:ReceiveData
  // id = 0  +IPD,0,nn:ReceiveData
  // id > 0  +IPD,id,nn:ReceiveData
  while( (time+timeout) > millis()) {
    while(myESP8266.available())  {
      char current_byte = myESP8266.read(); // read the next character.
      Serial.print(current_byte);
      if (flag == 0) {
        if (current_byte != 0x2c) continue;
        flag++;
        if (id < 0) flag++;
      } else if (flag == 1) {
        if (current_byte != 0x2c) continue;
        flag++;
      } else if (flag == 2) {
        if (current_byte == 0x3a) { // :
          datalen=atoi(buf);
          flag++;
          len=0;
        } else {
          buf[len++]=current_byte;
          buf[len]=0;
        }
      } else {
        buf[len++]=current_byte;
        if (len == sz_buf) return -len;
        buf[len]=0;
        if (len == datalen) return len;
      }
    } // end while
  } // end while
  return -len;
}

このスケッチを実行すると、シリアルモニターには次のように表示されます。
青字は送信データ、黒字は受信データです。

ATE0-->

OK
AT+CWQAP-->
WIFI DISCONNECT

OK
AT+CWMODE=3-->

OK
AT+CWDHCP=2,1-->

OK
AT+CWJAP="SID","PASS"-->
WIFI CONNECTED
WIFI GOT IP

OK
AT+CIPSTA?-->
+CIPSTA:ip:"192.168.111.109"
+CIPSTA:gateway:"192.168.111.1"
+CIPSTA:netmask:"255.255.255.0"

OK
AT+CIPSERVER=0-->

ERROR

AT+CIPMUX=0-->

OK
AT+CIPSTART="TCP","192.168.111.20",9876-->
CONNECT

OK
AT+CIPSEND=26-->

OK
>
data from ATmega328P 00000-->

busy s...

Recv 26 bytes

SEND OK


+IPD,26:DATA FROM ATMEGA328P 00000
AT+CIPCLOSE-->
CLOSED

OK


こ ちらのページにESP8266を使ってSMTPでメールを送信するサンプルがあります。
頑張れはESP-01やESP-05でも動くようにポーティングできるでしょう。

続く....