ESP8266で電子工作練習、「Milkcocoa Hardware」を作ってみた

[Milkcocoa](https://mlkcca.com/)のサイトとかを作っている者です。

電子工作の練習がてら、Milkcocoaの基本のAPI（`push()`、`send()`、`on()`）が使えるハードウェアを試作しました。

<blockquote class="twitter-tweet" lang="ja"><p lang="in" dir="ltr">milkcocoa.datastore().send() <a href="https://t.co/c0iJN6VaQW">https://t.co/c0iJN6VaQW</a></p>&mdash; kiyopikko (@kiyopikko) <a href="https://twitter.com/kiyopikko/status/674987944546013184">2015, 12月 10</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" lang="ja"><p lang="in" dir="ltr">milkcocoa.datastore().on() <a href="https://t.co/o5Dsmjxz2Y">https://t.co/o5Dsmjxz2Y</a></p>&mdash; kiyopikko (@kiyopikko) <a href="https://twitter.com/kiyopikko/status/674987086404038656">2015, 12月 10</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>


※参考：APIの説明は省きますが、ざっくり以下みたいな感じです。

![](https://mlkcca.com/img/tutorial/method.png)

# 機能

見た目の割に出来ることは相当しょぼいです。

- `push`か`send`を選択できる
- 0〜3の範囲でカウントした数字をPublishする
- Subscribeして、来た数字を表示する

![esp8266-qiita.png](https://qiita-image-store.s3.amazonaws.com/0/94526/0cbdf664-0fcb-0ba0-fcbc-809e1b54f427.png)




# GPIO割り当て

(MODE切り替え兼用のものを除いて)6本あるGPIOを以下のように割り当てました。（ピン配置参考：https://tech-blog.cerevo.com/archives/859/ ）


## INPUT

- **IO4, IO5**：2bitで0〜3の値読み取り
- **IO14**：`LOW`になったらPublishする
- **IO12**：`LOW`の間だけSubscribeのコールバックを呼ぶ
- **IO16**：`push`(`LOW`), `send`(`HIGH`)の切り替え

## OUTPUT

- **IO13**：カウンタの入力につないで、来た値の回数だけカウンタをカウント(`LOW`&`HIGH`のセットを送る)する


# プログラム

```cpp
#include <ESP8266WiFi.h>
#include <Milkcocoa.h>

/************************* WiFi Access Point *********************************/

#define WLAN_SSID       "...SSID..."
#define WLAN_PASS       "...PASS..."


/************************* Your Milkcocoa Setup *********************************/

#define MILKCOCOA_APP_ID             "...Your_Milkcocoa_app_id..."
#define MILKCOCOA_DATASTORE_PUSH     "esp8266/push"
#define MILKCOCOA_DATASTORE_ONPUSH   "esp8266/onpush"
#define MILKCOCOA_DATASTORE_SEND     "esp8266/send"
#define MILKCOCOA_DATASTORE_ONSEND   "esp8266/onsend"


/************* Milkcocoa Setup (you don't need to change this!) ******************/

#define MILKCOCOA_SERVERPORT  1883

/************ Global State (you don't need to change this!) ******************/

// Create an ESP8266 WiFiClient class to connect to the MQTT server.
WiFiClient client;

const char MQTT_SERVER[] PROGMEM    = MILKCOCOA_APP_ID ".mlkcca.com";
const char MQTT_CLIENTID[] PROGMEM  = __TIME__ MILKCOCOA_APP_ID;

Milkcocoa milkcocoa = Milkcocoa(&client, MQTT_SERVER, MILKCOCOA_SERVERPORT, MILKCOCOA_APP_ID, MQTT_CLIENTID);


/************************* PIN Number *********************************/

#define PUBLISH_PIN        14
#define SUBSCRIBE_PIN      12

#define ON_VALUE_PIN       13

#define PUBLISH_VALUE_PIN1  4
#define PUBLISH_VALUE_PIN2  5

#define CHANGE_MODE_PIN    16


void setup() {
  Serial.begin(115200);
  delay(10);

  Serial.println(F("Milkcocoa SDK demo"));

  // Connect to WiFi access point.
  Serial.println(); Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WLAN_SSID);

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  pinMode(PUBLISH_PIN, INPUT);
  pinMode(SUBSCRIBE_PIN, INPUT);
  pinMode(PUBLISH_VALUE_PIN1, INPUT);
  pinMode(PUBLISH_VALUE_PIN2, INPUT);
  pinMode(CHANGE_MODE_PIN, INPUT);

  pinMode(ON_VALUE_PIN, OUTPUT);

  Serial.println( milkcocoa.on(MILKCOCOA_DATASTORE_ONPUSH, "push", onCallback) );
  Serial.println( milkcocoa.on(MILKCOCOA_DATASTORE_ONSEND, "send", onCallback) );
};

void loop() {
  milkcocoa.loop();

  /* set publish value */
  DataElement elem = DataElement();

  int val = digitalRead(PUBLISH_VALUE_PIN1) + digitalRead(PUBLISH_VALUE_PIN2)*2;
  elem.setValue("v", val);
  Serial.println(String(val));

  /* change mode */
  int apimode; 
  apimode = digitalRead(CHANGE_MODE_PIN);
  
  /* publish */
  if(digitalRead(PUBLISH_PIN) == LOW)
    triggerAPI(apimode, elem);
      
  delay(20);
};

void triggerAPI(int apimode, DataElement elem) {
  
  Serial.println("publish");
  
  if(apimode == LOW)
    milkcocoa.push(MILKCOCOA_DATASTORE_PUSH, elem);
  else
    milkcocoa.send(MILKCOCOA_DATASTORE_SEND, elem);

  delay(3000);
  
  Serial.println("publish finish");
};

void onCallback(DataElement elem) {
  Serial.println("onCallback");
  if(digitalRead(SUBSCRIBE_PIN) == LOW){
    int val = elem.getInt("v");

    // データが来たことを知らせるLEDを光らせるためのHIGH
    digitalWrite(ON_VALUE_PIN, HIGH);
    delay(200);

    // 0だったら1週させる
    if(val==0) val = 4;

    // 値の回数だけHIGHとLOWを送る
    for (int i = 0; i < val; i ++)
    {
      if(i!=0)
        digitalWrite(ON_VALUE_PIN, HIGH);
        
      delay(1);
      digitalWrite(ON_VALUE_PIN, LOW);
      delay(1);
    };
  }
};
```

# 使った部品

## **通信モジュール**

- [ESP-WROOM-02 USB付きBreakout基板 REESPUSB](http://www.runele.com/ca1/40/p-r-s/)：1個

![esp8266-qiita2.jpg](https://qiita-image-store.s3.amazonaws.com/0/94526/9dd25e5d-b973-03fa-c592-81d33016723e.jpeg)



## **`push`／`send`のモード切り替え部分**

- [トグルスイッチ](http://akizukidenshi.com/catalog/g/gP-00300/)：1個
- 10kΩ抵抗（プルアップ用）：1個

![esp8266-qiita3.jpg](https://qiita-image-store.s3.amazonaws.com/0/94526/2e730a78-e483-bfd4-4044-58058631fac5.jpeg)


※[何故プルアップ抵抗が必要かについてはこちら。](http://www.geocities.jp/zattouka/GarageHouse/micon/circuit/pullup.htm)

## **Publish、Subscribe部分**

- [タクトスイッチ](http://akizukidenshi.com/catalog/goods/search.aspx?search=x&keyword=%83%5E%83N%83g%83X%83C%83b%83%60&image=%8C%9F%8D%F5)：2個
- 10kΩ抵抗（プルアップ用）：2個
- LED＆100Ω抵抗（写真載せ忘れました）：各1個

![esp8266-qiita4-mod.jpg](https://qiita-image-store.s3.amazonaws.com/0/94526/64667b2e-966b-90d2-4b6a-ed5e665e21f7.jpeg)


## **数字カウント部分**

### 7セグ周り
  - [7セグメントLED（カソードコモンタイプのC-551）](http://akizukidenshi.com/catalog/g/gI-00640/)：1個
  - [7セグデコーダ（カソードコモン用の74HC4511）](http://akizukidenshi.com/catalog/g/gI-08878/)：1個
  - 47Ω抵抗（7セグLEDの電流制御用、実際には220Ωを使いました）：7個

![esp8266-qiita5-mod.jpg](https://qiita-image-store.s3.amazonaws.com/0/94526/5567621c-fd17-8c2e-63a1-6e2cb0a364b1.jpeg)


### カウンタ
- [バイナリカウンタ（74HC393）](http://akizukidenshi.com/catalog/g/gI-08603/)：1個
- [タクトスイッチ](http://akizukidenshi.com/catalog/goods/search.aspx?search=x&keyword=%83%5E%83N%83g%83X%83C%83b%83%60&image=%8C%9F%8D%F5)（リセット用）：1個
- 10kΩ抵抗（プルダウン用）：1個（写真載せ忘れました）

![esp8266-qiita6.jpg](https://qiita-image-store.s3.amazonaws.com/0/94526/f3139abe-b892-b045-4cd8-3d2c6d0e4ccd.jpeg)


### カウンタの入力部分
  - [OR回路（74HC32）](https://bispa.co.jp/1053)（ESP側の出力とシュミットトリガの出力をショートさせない用）：1個 

![esp8266-qiita7.jpg](https://qiita-image-store.s3.amazonaws.com/0/94526/47357ae8-c921-b3cd-f341-05ed8c203c66.jpeg)


※[何故ロジックICの出力をショートさせたらだめかについてはこちら](http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1021963980)

### カウンタ入力のチャタリング対策部分
- [0.1μF](http://akizukidenshi.com/catalog/g/gP-02211/)、[0.47μF](http://akizukidenshi.com/catalog/g/gP-05266/)積層セラミックコンデンサ（チャタリング平滑用、1つでも良いですが私の場合1つじゃ安定しなかったので2つ使ってます）：各1個
- 2.2kΩ、22kΩ抵抗（プルアップ用、コンデンサの電流制御用）：各1個
- [タクトスイッチ](http://akizukidenshi.com/catalog/goods/search.aspx?search=x&keyword=%83%5E%83N%83g%83X%83C%83b%83%60&image=%8C%9F%8D%F5)（カウント用）：1個
- [シュミットトリガ（74HC14）](http://akizukidenshi.com/catalog/g/gI-08879/)（中間値取らない用）：1個

![esp8266-qiita8.jpg](https://qiita-image-store.s3.amazonaws.com/0/94526/859ba2e4-c0fa-13d0-65ce-70cd73ac4a2f.jpeg)


※[チャタリングについてはこちら](http://www.marutsu.co.jp/pc/static/large_order/1405_311_ph)


# 回路図

厳密な回路図じゃなくて、ざっくりイメージ伝える系の回路図です。

![esp8266-qiita9-01-01.png](https://qiita-image-store.s3.amazonaws.com/0/94526/9607c1d1-deee-da8d-44b1-5c1aba1c1fa0.png)

![esp8266-qiita9-01-02.png](https://qiita-image-store.s3.amazonaws.com/0/94526/51006d18-ebe0-dfb3-74c3-00624436f9e8.png)



# 感想

思い描いたものが実際に動くと大変面白かったです。[2日目の方もおっしゃっていましたが](http://qiita.com/ie4/items/ae850cdb2c617f3fd6af)、ボタンをカチカチするのは楽しいです。無駄に押してしまいます。

あと、テスターが最高に頼もしかったです。電子工作は「何が起こってるのがわからない」っていう怖さがあるので、そこが明らかになるのはとても安心できます。

次はユニバーサル基板で出来るだけコンパクトにしたいと作れたらとか思っています。

用途としては4択のアンケート回答とかでしょうか。Milkcocoaに保存もできるので集計も楽です。
また4択ということで、実際にやっちゃうとアウトですが、見せ方を時計っぽく作ったらマークシート式の緩いテストならインターネット越しのカンニングマシンとして使えるかもとか妄想しました。


# 電子工作の勉強で参考になったものとか

## [Make: Electronics ―作ってわかる電気と電子回路の基礎 ((Make:PROJECTS))](http://www.amazon.co.jp/Make-Electronics-%E2%80%95%E4%BD%9C%E3%81%A3%E3%81%A6%E3%82%8F%E3%81%8B%E3%82%8B%E9%9B%BB%E6%B0%97%E3%81%A8%E9%9B%BB%E5%AD%90%E5%9B%9E%E8%B7%AF%E3%81%AE%E5%9F%BA%E7%A4%8E-PROJECTS/dp/4873114772)

これに尽きました（[2日前にはてなの人もおすすめしてましたね](http://hakobe932.hatenablog.com/entry/learning-electronics)）。これを1章から順番に必要なものを買って工作していくのが一番勉強になると思います。

少し前に話題になった[クックパッドのCTOさんの記事](http://techlife.cookpad.com/entry/2015/10/28/080000)を見ると必要な道具の多さに面食らう＆一気に全部買ったとしても何のこっちゃわからないと思うので、段階的に買って学び進めていくとわかりやすいと思います（と言いつつ、送料で結構損した気がしますが）。

頭だけで理解するより手を動かした方が10倍理解しやすいです。


## [剣菱P](https://twitter.com/kenbishi_p)の[零からの電子工作（ニコ動）](http://www.nicovideo.jp/mylist/21945950)

Make: Electronicsと並行して見ていくとすごく理解できます。この動画があったからこの試作品が作れたと言っても過言ではないです。

説明不要の必修科目です。


## [始める電子回路](http://startelc.com/index.html)

古い感じのサイトですが、とても丁寧でわかりやすいサイトです。私の謎だった部分に答えてくれていました。


## データシート

参考になるとかじゃなくて、読めないと始まらない類いのものなんですが。

LEDだってデータシートを読まないと何mAまで流して良いとか何V電圧が落ちるのかがわからないので、読める（どこを見れば良いかわかっている）ようになっておく必要があります。