フォト
2017年6月
        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  
無料ブログはココログ

ESP-WROOM-02

2016年7月 2日 (土)

ESP-WROOM-02を始めました(4) WiFi経由でLEDを制御

ESP-WROOM-02GPIOまわりの雰囲気が分かったので、
本来の目的のIoTをボチボチとやり始めました。

Dscn5367

まずは、Arduino IDEのサンプルソースのSDWebserverを修正して
簡単なLED制御プログラムを作って見ました。

スマートフォンにてESP-WROOM-02にて稼働するWebサーバーに接続して
LEDを制御しています。

動作の様子

動作としては単純なのですが、ESP-WROOM-02が具体的に何をやっていると言うと
  1)WiFiアクセスポイント 機能の提供
  2)接続したスマートフォンにIPアドレスの配布(DHCP)
  3)Webサーバー
  4)WebコンテンツをSDカードから配信
  5)URL名前解決(DNSサーバー)
  6)LEDの制御

てな感じです。

ESP-WROOM-02がWiFiアクセスポイントになっているので、既存ネットワークが無くても
スマートフォンから接続することが出来ます。

動画見ると分かりますが、表示レスポンス等、Webサーバーとしてはさすがに遅いです。
ですので、ボタン操作によるLED制御は、非同期通信を使ってページ更新が発生しない
ようにしました。

結線

05ピン    LEDのアノードへ接続
13ピン    microSDカードモジュールのMOISに接続
12ピン    microSDカードモジュールのMISOに接続
14ピン    microSDカードモジュールのCLKに接続
15ピン    microSDカードモジュールのCSに接続

microSDカードの接続・使い方はスイッチサイエンスさんの記事
   ESP-WROOM-02を使ったWi-Fi機能付き温度ロガーを作る(1)
が参考になると思います。

スケッチ
ダウンロード SDWebServerEx.zip (64.5K)

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <SPI.h>
#include <SD.h>

#define DBG_OUTPUT_PORT Serial
#define LED_PIN 5

const char* ssid = "esp8266";
const char* password = "xxxxxxx";
const char* host = "sd.local";
const byte DNS_PORT = 53;

IPAddress apIP(192, 168, 0, 1);
DNSServer dnsServer;
ESP8266WebServer server(80);

static bool hasSD = false;

void returnOK() {
  server.send(200, "text/plain", "");
}

void returnFail(String msg) {
  server.send(500, "text/plain", msg + "\r\n");
}

bool loadFromSdCard(String path){
  String dataType = "text/plain";
  if(path.endsWith("/")) path += "index.htm";

  if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
  else if(path.endsWith(".htm")) dataType = "text/html";
  else if(path.endsWith(".css")) dataType = "text/css";
  else if(path.endsWith(".js")) dataType = "application/javascript";
  else if(path.endsWith(".png")) dataType = "image/png";
  else if(path.endsWith(".gif")) dataType = "image/gif";
  else if(path.endsWith(".jpg")) dataType = "image/jpeg";
  else if(path.endsWith(".ico")) dataType = "image/x-icon";
  else if(path.endsWith(".xml")) dataType = "text/xml";
  else if(path.endsWith(".pdf")) dataType = "application/pdf";
  else if(path.endsWith(".zip")) dataType = "application/zip";

  File dataFile = SD.open(path.c_str());
  if(dataFile.isDirectory()){
    path += "/index.htm";
    dataType = "text/html";
    dataFile = SD.open(path.c_str());
  }

  if (!dataFile)
    return false;

  if (server.hasArg("download")) dataType = "application/octet-stream";

  if (server.streamFile(dataFile, dataType) != dataFile.size()) {
    DBG_OUTPUT_PORT.println("Sent less data than expected!");
  }

  dataFile.close();
  return true;
}

void handleNotFound(){
  if(hasSD && loadFromSdCard(server.uri())) return;
  String message = "SDCARD Not Detected\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  DBG_OUTPUT_PORT.print(message);
}

// LEDの制御
void handleLED() {
  if (!server.hasArg("LED")) {
    String msg = "Command Error\n";
    returnFail(msg);
    return;
  }

  String cmd = server.arg("LED");
  if (cmd == "on") {
    digitalWrite(LED_PIN, HIGH);
    DBG_OUTPUT_PORT.println("LED ON");
  }    
  if (cmd == "off") {
    digitalWrite(LED_PIN, LOW);
    DBG_OUTPUT_PORT.println("LED OFF");
  }
  returnOK();
}

void setup(void){
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);  
  DBG_OUTPUT_PORT.begin(115200);
  DBG_OUTPUT_PORT.setDebugOutput(true);
  DBG_OUTPUT_PORT.print("\n");

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  WiFi.softAP(ssid, password);

  dnsServer.setTTL(300);
  dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure);
  dnsServer.start(DNS_PORT, host, apIP);

  server.onNotFound(handleNotFound);
  server.on("/do",HTTP_GET, handleLED);
  
  server.begin();
  DBG_OUTPUT_PORT.println("HTTP server started");

  if (SD.begin(SS)){
     DBG_OUTPUT_PORT.println("SD Card initialized.");
     hasSD = true;
  }
}

void loop(void){
  dnsServer.processNextRequest();
  server.handleClient();
}


Webページ
とりあえず、トップ画面のみ掲載します。ファイルはSDカードに入れています。
SDカードライブラリの制約でファイル名は8.3文字となります。

スマートフォンに表示されているページや画像はSDカードに入れています。
ページは2ページ構成です。

簡単な説明
スマートフォンからは、まずssidがesp8266のアクセスポイントに接続します。
このあたりは、ESP-WROOM-02

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  WiFi.softAP(ssid, password);
でやってます。

次にスマートフォンからブラウザにて、URL http://led.local  にアクセスして
LED制御画面を(index.htm)を表示します。

ESP-WROOM-02
でこのアクセスによるコンテンツ画面配信のための、
名前解決は DNSServer dnsServer にて生成したDNSサーバーがやってくれています。

コンテンツの配信は下記のコードでやっています。まずはハンドラの設定は
  server.onNotFound(handleNotFound);
  server.on("/do",HTTP_GET, handleLED);
です。 LEDを制御するためのURL(GET)は、スマートフォンから
   http://led.local/do?LED=on    でLED点灯
   http://led.local/do?LED=off   でLED消灯
のアクセスでやっています。

このled.local/do のURLでアクセスされた場合にLEDの制御を行うため
  server.on("/do",HTTP_GET, handleLED);
と記述して、処理を行う関数 habdleLED() を指定しています。またdo?LED=on 形式で
スマートフォンから変数LEDの値を渡す方式(GET)を指定するためにHTTP_GET
指定しています。

led.local/do 以外のURLでアクセスされた場合は、
  server.onNotFound(handleNotFound);
と記述して、関数 handleNotFound() を呼び出すように指定しています。

handleNotFound()では、loadFromSdCard(String path) を呼び出して
URLで指定したファイルがあればそのファイルをSDカードから
読みだして、配信を行っています("/" の場合は"/index.htm"ファイルを配信)。

今回はサンプルを参照してサクッと作成しましたが、
Webサーバーを操るにあたり、HTTPのプロトコルをちょっと突っ込んで学ばないと
いけないようです。

ただし、ライブラリが充実しており、ちょっとしたプログラムも意外と簡単に作れることが分かりました。

2016年6月28日 (火)

ESP-WROOM-02を始めました(3) SPIFFSの利用

2016/07/02 追記更新

前回はSDカードに漢字フォントとビットマップファイルをを載せていたのですが、
そのデータを標準搭載のフラッシュメモリ上に置けることが分かりました。

ということで、実際にフラッシュメモリ上に漢字フォントをおいて動かしてみました。
取りあえず、動作しました。

03

だだし若干、表示にチラつきが出ます。
フラッシュメモリにアクセスする時にダイナミック駆動に利用しているタイマー割り込みが
中断させられるのかもしれません。

今後、WiFi通信等の利用も考えると、1msecの割り込みのダイナミック駆動はちょっと
負担が大きそうです。

フラッシュメモリの具体的な利用方法

ESP-WROOM-02には4MバイトのSPI接続フラッシュメモリが搭載されており、
そのうち、1M or 3Mバイトをデータ用のファイルシステムとして利用出来ます。

この領域は、専用に確保されておりスケッチを書き換えても影響を受けません。

  Flash layout

  ※公式サイトのリファレンスマニュアル ESP8266 Arduino Core /  File System /  より引用
    http://esp8266.github.io/Arduino/versions/2.3.0/doc/filesystem.html

ファイルシステムに利用する領域はArduino IDEにて選択が出来ます。

フラッシュサイズが4MバイトのESP-WROOM-02は1M or 3Mバイトが選択出来ます。

Arduino IDEから任意のファイルを配置出来る

やり方は、公式サイトのリファレンスマニュアル
  ESP8266 Arduino Core /  File System / Uploading files to file system
     http://esp8266.github.io/Arduino/versions/2.3.0/doc/filesystem.html#uploading-files-to-file-system
に記載されています。

ブラグインをダウンロードして、Arduino IDEに組み込み、Arduino IDEを再起動、
これで、ツールメニューに「EPS8266 Sketch data upload」というメニューが追加されます。

現在開いているスケッチが置いてあるフォルダにフォルダ data を作成してその中に
データファイルを置いておきます。

そんでもって、メニュー 「EPS8266 Sketch data upload」 をクリックしてアップロードします。

実際に漢字フォントとビットマップファイルの約1.75Mバイトをアップロードしてみると
数分かかりましたが、エラーなく完了出来ました。

プログラムからのファイルアクセス

ヘッダーファイル fs.h をインクルドします。これにより、File system object (SPIFFS)が
利用出来ます。

ファイルシステムの操作はSPIFFSオブジェクトを使って行います。
SDライブラリのSDオブジェクトとほとんど同じ感覚で利用出来ます。

SDオブジェクトからSPIFFSオブジェクトへの移行は関数がほぼ1対1でかつ、
パラメタも類似しているためすんなりと行えました。

ただ、どうもSDライブラリとの相性が悪いのかSD.hも別途インクルドするFileクラス関連の
コンパイルエラーが発生しました(これは要調査です)。
まあ、今回は、併用しないのでSD.hのインクルドを止めました。

プログラム(スケッチ)

現時点のバージョンを置いておきます。
     ダウンロード sample5v2_esp.zip (14.1K)   

ココログでは、1Mバイト以上のファイルを置けないので、フォントデータは下記より
ダウンロードして下さい。
     https://github.com/Tamakichi/Arduino-KanjiFont-Library-SD/archive/master.zip

フォントの著作権は私ではなくフォント作成者にあります。
解凍し、README.TXTのライセンス等に関する記載内容を確認の上お使い下さい。

解凍したフォルダのfontbin内のFONT.BINが利用するフォントデータとなります。
このフォントデータをスケッチ配置フォルダ下のdataフォルダに入れて、ESP-WROOM-02
にアップロードして利用します。

最後に

最終的にはESP-WROOM-02用の漢字フォントライブラリを整備したいと思います。

2016/07/02 追記

ライブラリ化し、下記にて公開しました。
  ・ESP8266用漢字フォントライブラリ SPIFFS版 ESP8266-KanjiFont-Library-SPIFFS
    https://github.com/Tamakichi/ESP8266-KanjiFont-Library-SPIFFS

2016年6月26日 (日)

ESP-WROOM-02を始めました(2)

前回からの続きです。
ESP8266搭載のESP-WROOM-02の調査中です。

Arduinoとしてどれくらい利用可能かを確認するため、
Arduino UNO(Atmega328)用のaitendo 16x16LEDマトリックス制御プログラムを移植
してみました。

Dscn5336

動作の様子



意外とライブラリの互換性レベルが高く、
I/Oピンの割り付け変更とタイマー割り込みの設定の変更程度で動きました。
(直接レジスタをいじっている高速版digitalWrite()、shiftOut()はさすがに動かないので、
正規版に戻しました)。

行儀のよいArduino UNO用スケッチなら少々の修正で利用出来ると思います。
実際に自作のビットマップファイルロードライブラリ、フォントライブラリが利用出来ました。
(この動作確認にて、自作のフォントライブラリの不具合を見つけました)

SPI、SDライブラリは割り付けピンを変えるだけで利用出来ました。

プログラム領域にデータを置いて参照利用するpgm_read_byte()利用出来ました。

タイマー割り込みに使っていたMsTimer2ライブラリは動かないので、ESP8266用に
用意されているTickerを利用しました。利用はとても簡単です。

ヘッダーファイル Ticker.hをインクルードして、グローバル変数を宣言して、
  #include <Ticker.h>
  Ticker ticker ;


タイマー割り込み設定の
  MsTimer2::set(1, fontout);
  MsTimer2::start();
  ticker.attach_ms(1, fontout);
と変更するだけです。

「いろは歌」はSDカード上のフォントを利用して表示しています。
「ねこにこんばんわ」はビットマップファイルを読み込んで表示していま。

タイマ割り込みTickerは、MsTimer2に比べると若干、精度が悪い感じです。
ダイナミック駆動のLED表示に若干ムラが生じます。

ピン割り付けがちょっと悩みましたが、下記のサイトの情報が大変参考になりました。

・Qiita - ESP-WROOM-02 Arduino互換ボードのGPIOはこうやって使う
   http://qiita.com/umi_kappa/items/ac3d37db44a2dcfe71fd

スケッチ  ダウンロード sample5_esp.zip (4.6K)

  ※コンパイルには下記のライブラリが別途必要です。
   sdfonts   : Arduino用漢字フォントライブラリ SDカード版
   sdbitmap : Arduino用Bitmap画像ロードライブラリ

// sample5_esp.ino
// aitendo 16x16LEDドットマトリックスの制御サンプル 漢字フォントライブラリ利用バージョン
// 2016/06/16 ESP-WROOM-02(ESP8266)用に移植 by たま吉さん
// 2016/06/29 コメント追記、定数の定義追加 by たま吉さん
//

#include <sdfonts.h>
#include <string.h>
#include <sdbitmap.h>
#include <Ticker.h>

// ビットマップ操作関数宣言
void scrollBitmap(uint8_t *bmp, uint16_t w, uint16_t h, uint8_t mode);
void clearBitmapAt(uint8_t* bmp, uint16_t w, uint16_t h, int16_t x, int16_t y, uint8_t cw, uint8_t ch);
void setBitmapAt(uint8_t *dstbmp, uint16_t dstw, uint16_t dsth, int16_t dstx, int16_t dsty,uint8_t *srcbmp, uint16_t srcw, uint16_t srch);

//ESP-WROOM-02 接続ピン設定
#define DATAPIN   (5)     // TB62706のSERIAL-INへ接続
#define LATCHPIN  (2)     // TB62706のLATCHへ接続
#define CLOCKPIN  (4)     // TB62706のCLOCKへ接続
#define ENABLEPIN (16)    // TB62706のENABLEへ接続

#define MOSI_SD   (13)    // SDカードのMOISへ接続
#define MISO_SD   (12)    // SDカードのMISOへ接続
#define CLK_SD    (14)    // SDカードのCLKへ接続
#define CS_SD     (15)    // SDカードモジュールCSへ接続

//LEDドットマトリックス用定義
#define FBUFSIZE     32   // ドットマトリックスフレームバッファサイズ
#define MWIDTH       16   // ドットマトリックス幅
#define MHIGTHT      16   // ドットマトリックス高さ

// タイマー割り込み
Ticker ticker;

// 表示用バッファ
uint8_t fbuf[FBUFSIZE];   // 表示パターンバッファデータ
uint8_t buf[MAXFONTLEN];  // フォントデータ格納アドレス(最大24x24/8 = 72バイト)

// バッファ内データを表示する(1ライン分割表示)
void fontout() {
  static uint8_t _line = 0;      // 表示対象行
  // 点灯LEDが移動するパターン
  digitalWrite(ENABLEPIN,LOW);   // OUTを有効にする
  digitalWrite(LATCHPIN, LOW);   //送信開始        
 
  // 表示対象行選択
  uint16_t val = _BV(15-_line);
  shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, val);
  shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, val>>8);       
     
  // 表示対象行のフォントパターン送信
  shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, fbuf[(_line<<1)+1]);
  shiftOut(DATAPIN, CLOCKPIN, LSBFIRST, fbuf[_line<<1]);

  digitalWrite(LATCHPIN, HIGH);  //送信終了

  // 表示対象行を次行に設定
  _line++;
  if (_line == MHIGTHT )
    _line = 0;
}

// バッファクリア
void clearBuf() {
   memset(fbuf, 0, FBUFSIZE);
}

// いろは歌デモ
void test_iroha() {
  char* str="色はにほへど散りぬるを我が世たれぞ常ならむ有為の奥山今日越えて浅き夢見じ酔ひもせず";
  uint8_t fn;
  uint8_t tmpbuf[FBUFSIZE];        // 表示パターン2次バッファデータ
  memset(tmpbuf,0,FBUFSIZE);       // 2次バッファクリア
  SDfonts.open();                 // フォントのオープン

  // 表示文字数分ループ処理
  while(1) {
    fn = rand() % (EXFONT24+1);            // 表示フォントサイズランダム決定
    SDfonts.setFontSizeAsIndex(fn);       // フォントサイズの指定
    str = SDfonts.getFontData(buf, str);  // フォントデータの取得
    if (!str)
      break;                               // 文末なら抜ける

    // 1文字分スクロール表示
    for (int8_t t = 0; t < SDfonts.getWidth(); t++) {
      scrollBitmap(tmpbuf, MWIDTH, MHIGTHT, B0001); // 左スクロール
      clearBitmapAt(tmpbuf, MWIDTH, MHIGTHT, MWIDTH-t-1, MHIGTHT-t-1, SDfonts.getWidth(), SDfonts.getHeight());
      setBitmapAt(tmpbuf, MWIDTH, MHIGTHT, MWIDTH-t-1, MHIGTHT-t-1, buf, SDfonts.getWidth(), SDfonts.getHeight());
      memcpy(fbuf,tmpbuf,FBUFSIZE);
      delay(30);
    }
  }
  SDfonts.close(); // フォントのクローズ
}

// ビットマップパターン表示
void test_bitmap() {
  uint8_t tmpbuf[FBUFSIZE]; // 表示パターンバッファデータ
  uint8_t rc;
  uint8_t w,h;

  memset(tmpbuf,0,FBUFSIZE);
  sdbitmap bitmap;
  bitmap.setFilename("IMG2.BMP");

  // ビットマップデータオープン
  rc = bitmap.open();
  w  = bitmap.getWidth();
  h  = bitmap.getHeight();
  
  for (uint8_t i=0; i <= w-MWIDTH; i++) {  
    // データの取得
    bitmap.getBitmapEx(tmpbuf, i, 0, MWIDTH, MHIGTHT, 1);
    memcpy(fbuf,tmpbuf,FBUFSIZE);
    delay(30);
  }
  delay(2000);
  bitmap.close();
}

// セットアップ
void setup() {
  // LEDマトリックス用制御ピンのモード設定
  pinMode(ENABLEPIN,OUTPUT);
  pinMode(DATAPIN, OUTPUT);
  pinMode(LATCHPIN, OUTPUT);
  pinMode(CLOCKPIN, OUTPUT);

  // 制御ピンの初期化
  digitalWrite(ENABLEPIN,HIGH);
  digitalWrite(CLOCKPIN, LOW);
  digitalWrite(LATCHPIN, HIGH);

  // SDカード利用フォントライブラリの初期化
  SDfonts.init(CS_SD);         // フォント管理の初期化

  // 1msec間隔タイマー割り込み設定
  ticker.attach_ms(1, fontout); 
}

// デモループ
void loop(){
  test_bitmap();  // ビットマップデータロードテスト
  test_iroha();   // いろは歌デモ表示
  //clearBuf();   // 表示用バッファ初期化
  delay(1000);
}

今回の動作確認でデジタル出力、SPI通信普通に使えることが分かりました。
次はI2Cを調べてみます。

2016年6月22日 (水)

ESP-WROOM-02を始めました

そろそろ、IoT関連をやりたいなぁと思い、
スイッチサイエンスさんのESPr Developer(ESP-WROOM-02開発ボード)を購入しました。

Dscn5328

スイッチサイエンスさんの下記の記事を参考にしてArduino IDE 1.6.9上に環境を構築しました。
ESP-WROOM-02開発ボードをArduino IDEで開発する方法

01

特に問題なく、チカチカ出来ました。

Dscn5331

ブレッドボードに差し込むよう、オスピンヘッドを取り付けました。

後で知ったのですが、スイッチサイエンスさんではピンソケット付きも販売しているようです。

ESPr Developer(ピンソケット実装済)
02

この形態が正式なのかも...

ざっと調べた感じはで、I/O、SPI、I2C関連はArduinoと同等、タイマ割り込みは
全く異なった実装方法っぽいです。

取りあえず、I2C接続デバイス、SPI接続を色々とつなげてArduinoとの互換レベルを
調べてみたいと思います。

I2Cはスレーブでの利用はまだ対応出来ていないようです。

関連情報
  ・ESP-WROOM-02(公式サイト)
    http://espressif.com/en/products/hardware/esp-wroom-02/overview
    Resourceにドキュメント、SDK、ツールが公開されています。

  ・ESP8266 Arduino Core documentation for version 2.3.0
    http://esp8266.github.io/Arduino/versions/2.3.0/doc/reference.html   
    コア部および標準ライブラリに関するドキュメント。目を通しておく必要ありです。

  ・ESP8266
   http://links2004.github.io/Arduino/index.html
   クラスライブラリ等がリスト、インデックスにて整理されているマニュアルです。
   だだし、説明分等が無いのが残念。ソースから自動生成したっぽい。

  ・ESP8266 Community Wiki
   http://www.esp8266.com/wiki/doku.php
   ESP8266の情報が集まっているWikiサイトのようです。ここをチェックすれば、
   ESP8266に関するよりディープな情報を取得出来そうです。

  ・スイッチサイエンス ESPr Developer(ESP-WROOM-02開発ボード)
     https://www.switch-science.com/catalog/2500/

  ・スイッチサイエンス マガジン ESP-WROOM-02関連記事
     http://mag.switch-science.com/tag/esp-wroom-02/

  ・電子工作と介護と生活と・・・
    https://www.mgo-tec.com/category/arduino/esp8266-wroom
    スイッチサイエンスさんが、リンクを貼っているブログです。情報満載です。

  ・BRILLIANTSERVICE TECHNICAL BLOG - 技適OKな中華IoTモジュールを使いこなす
    http://bril-tech.blogspot.jp/2015/07/okiot.html
    内部構造的な解説が大変参考になりました。

  ・息子と一緒に Makers - ESP-WROOM-02 のWiFiを止めるには?
   http://makers-with-myson.blog.so-net.ne.jp/2016-05-15
   WiFi止めるとかなり、消費電力を抑えられるようです。

  ・息子と一緒に Makers - ESP-WROOM-02 でタイマー割り込みを使ってみた
   http://makers-with-myson.blog.so-net.ne.jp/2016-05-13
   ESPではTickerという機能でタイマー割り込み するのが定番のようですが、別の
   方法もあるようです(要調査)。

  ・Qiita - ESP-WROOM-02 Arduino互換ボードのGPIOはこうやって使う
   http://qiita.com/umi_kappa/items/ac3d37db44a2dcfe71fd
   GPIOピンの割り付けが参考なまりました。