2016年6月20日 星期一

製作 Arduino Nano + ESP8266 物聯網模組 (三)

上週五晚上在露天尋找蜂鳴器時, 看到一款 3cmx7cm 的 10*24 洞的雙面洞洞板 :

# 【Q小奇】3cm*7cm 雙面噴鍚玻纖洞洞板 厚1.6mm 孔距2.54mm $8

記得好像在禾樺看過, 突發奇想說, 是否用此板會更容易布局與布線呢? 我用 Google 雲端硬碟又畫了一張 10*24 的洞洞板模擬圖來嘗試, 發現還不錯, 雙面佈線似乎更方便哩. 參考上週用 4.5cm*4.5cm 所做的布局 :

# 以 Arduino + ESP8266 物聯網模組重作 NTP 實驗 (二)

週六中午載姊姊去畫室回程特地再去禾樺找此種洞洞板, 結果發現有點不一樣, 禾樺的是 9*24=216 洞, 少了一排. 不確定這樣是否容易佈線, 但還是買回兩塊來試試看 (一片 20 元, 打 8 折還要 16 元, 好貴!).


重新以 9*24 洞佈線發現也 OK, 而且整個板子布局看來更對稱, 因為 Nano 上下排針是跨七格, 加上上下各一排插槽剛好九排, 若買露天賣的 10*24 則會空出一格, 整體看來會較不平均, 但也還是可用啦! 我嘗試幾次後找出最佳佈局方式如下 (只是將元件擺上去而已) :


這塊洞洞板的好處是不用像之前用的那塊必須裁切跟鑽洞, 整塊拿來用剛剛好, 其次是橫排上方有 A~X, 縱排左方有 1~9 的座標, 找焊點核對較方便 (但背面沒有是美中不足之處) :

3cm*7cm 216 洞洞板

經過幾次琢磨修改, 最後定稿的元件布局佈線圖如下 (背面無座標, 下圖之背面是我用 Picpick 直接將正面做水平旋轉而得) :

正面

背面

這裡棕色線為元件 (電阻) 的端線, 藍色線條代表背面 (無座標面) 的焊接線, 而橘色線代表正面 (有座標面) 的跳線. 我在禾樺找到一種更細的包覆線, 九公尺才 30 元, 比較好焊不占空間 :


此次佈線時又為了 ESP8266 的 CH_PD 要越過 RST 接腳接 3.3V 電源而煩惱, 我查了資料, RST 接 LOW 是讓 ESP8266 重置, 正常工作時必須接 HIGH (以前我都讓 RST 懸在那邊沒接, 這樣應該預設為 HIGH). 參考 :

# ESP8266 Wi fi module explain and connection : step 3

這樣就好辦啦! 因為 VCC, RST, 以及 CH_PD 相鄰連成一線, 乾脆用跨焊接在一起, 不需要跳過 RST 連接 VCC 與 CH_PD.

因為把跳線都放在正面, 所以必須先把正面的三個電阻, 模式 Jumper 先固定好 (蜂鳴器要等正面六條跳線完成後焊背面時再焊, 因為它會蓋住部分跳線, 必須驗證跳線連接性 ok 後再處理). 先在正面擺好電阻與 Jumper 並用三秒膠固定, 再到背面焊接固定. 然後焊接跳線, 這裡要注意, 跳線不要太緊, 留一些些餘裕可以稍微把線挑起來即可, 因背面焊錫時, 錫水可能經過洞流到正面, 必要時可把跳線稍微拉起避免包覆的絕緣皮被燙破.


焊好後用電表量看看各跳線接點是否都有確實接通. 接著放上排母與滑動開關, 用三秒膠稍微固定後, 翻到背面也用三秒膠將 AMS1117 稍微固定後進行焊接 (滑動開關不要用三秒膠, 要用膠帶, 因為三秒膠若滲入裡面會使開關變康固力-報廢囉) :



呵呵, 真不錯, 把跳線移到正面後, 背面就乾淨多了! 注意, 蜂鳴器要放到最後跟背面左下方圓圈處的 GND 金屬線一起焊, 蜂鳴器的負極剛好就跟該金屬線在轉折處相接, 若先焊 GND 金屬線, 則蜂鳴器的負極就無法插進洞裡了. 另外 ESP8266 的 3.3V 是從 AMS1117 的上方頭接點接出去, 中間腳因跳線麻煩就用不到了. 


焊好後先量一下 ESP8266 的排母上 TX, RX, CH_PD, VCC, GND 是否與相接的點連通. 然後先裝上 Nano 插電, 量 ESP8266 上 VCC=CH_PD=3.3V 沒問題後就可拔掉電源插上 ESP8266 上傳程式測試了 (程式參考前文), 完成後如下圖 :


這次製作新模組經過縝密的規劃與注意焊接程序, 一次就 OK, 修長的外型比前一版要好看, 而且綠色電路板看起來較有質感. 事實上兩個面積差不多, 舊版是 4.5*4.5=20.25 平方公分, 此次新版是 3*7=21 平方公分, 新版雖然大了 0.75 平方, 但因為各元件模組緊密相鄰, 感覺比較精巧 :


這片新模組只花了兩天就規劃與製作完成, 速度比上回快. 舊版的目前有三片不會再製作了, 新版的還會再做 1 片即夠用矣. 這片背面的保護用壓克力板規格如下圖 :


台南紅蘋果訂的壓克力板打算改為舊版的 5 片, 新版的 8 片, 總共 13*11=143+運費55=198 元. 今天下班後又順路跑去禾樺買要鎖壓克力底板的螺絲 (平頭細牙 2*8) 螺帽 (六角細牙 2*4), 牙寬都是 2mm, 長度 8mm 的螺絲剛剛好 (塑膠的沒這麼小, 而且比較貴), 而 4mm 的螺帽直徑則剛好與洞洞板四角的圓孔大小吻合.


上週四做完三片物聯網模組後, 本以為就此打住, 沒想到又製做了新版的, 我覺得已經很滿意了, 似乎也沒必要花時間去洗 PCB, 因為那還要去鑽洞, 也還是要焊接, 只是省下布線的時間而已.

製作程序爰記如上, 以備來日重製時參考. 這個禮拜都在瘋造板子, 真是夠了.

此模組的程式架構更新如下 :

#include <SoftwareSerial.h>
#define DEBUG true
//-----application include & def listed HERE-----

//system use please do not edit
SoftwareSerial esp8266(7,8); //(RX,TX)
const int SW_PIN=4; //Pin to switch configuration or working mode
const int MAX_PAGE_NAME_LEN=48;  //buffer size
char buffer[MAX_PAGE_NAME_LEN + 1]; //store page_name/ssid/pwd
int mode; //store current mode(LOW=wifi setup, HIGH=working)

//-----application global variables listed HERE-----

void setup() {
  //system use please do not edit
  Serial.begin(9600);
  esp8266.begin(9600);
  sendData("AT+RST\r\n",2000,DEBUG); // reset ESP8266
  pinMode(SW_PIN, INPUT);
  mode=digitalRead(SW_PIN);
  sendData("AT+GMR\r\n",1000,DEBUG);
  if (mode==LOW) { //setup mode : for wifi configuration
    sendData("AT+CWMODE=3\r\n",1000,DEBUG); //configure as access point
    sendData("AT+CIPMUX=1\r\n",1000,DEBUG); //enable multiple connections
    sendData("AT+CIPSERVER=1,80\r\n",2000,DEBUG); //turn on server 80 port    
    }
  else {  //working mode : for running application
    sendData("AT+CWMODE=1\r\n",1000,DEBUG); //configure as a station
    delay(3000); //wait for wifi connection to get local ip
    }
  sendData("AT+CIFSR\r\n",1000,DEBUG); //get ip address
  //-----application setup codes listed HERE-----
  }

void loop() {
  if (mode==LOW) {setupWifi();} //system use please do not edit
  else { //-----application loop codes listed HERE-----
    //show ESP8266 response char to serial monitor window
    if (esp8266.available()) {Serial.write(esp8266.read());}
    //send char to ESP8266 if got char from serial monitor window
    if (Serial.available()) {esp8266.write(Serial.read());}    
    }
  }

void setupWifi() { //system use please do not edit
  if (esp8266.available()) { // check if the esp is sending a message
    if (esp8266.find("+IPD,")) {
      delay(1000);
      //esp8266 link response : +IPD,0,498:GET / HTTP/1.1
      //retrieve connection ID from response (0~4, after "+IPD,")
      int connectionId=esp8266.read()-48;  //from ASCII to number
      //subtract 48 because read() returns ASCII decimal value
      //and in ASCII, "0" (the first decimal number) starts at 48
      if (esp8266.find("GET /")) { //retrieve page name (router)
        memset(buffer, 0, sizeof(buffer));  //clear buffer (all set to 0)
        if (esp8266.readBytesUntil('/', buffer, sizeof(buffer))) {
          if (strcmp(buffer, "update") == 0) { //update wifi
            //"?ssid=aaa&pwd=bbb HTTP/1.1"        
            esp8266.find("?ssid="); //skip ssid token
            memset(buffer, 0, sizeof(buffer));  //clear buffer (all set to 0)
            esp8266.readBytesUntil('&', buffer, sizeof(buffer)); //retrieve ssid
            String ssid=buffer;
            esp8266.find("pwd="); //skip pwd token
            memset(buffer, 0, sizeof(buffer));  //clear buffer (all set to 0)
            esp8266.readBytesUntil(' ', buffer, sizeof(buffer)); //retrieve pwd
            String pwd=buffer;
            //configure as a station
            String res=sendData("AT+CWJAP=\"" + ssid + "\",\"" + pwd + "\"\r\n",6000,DEBUG);
                 
            //show setup result
            String webpage="<html>Wifi setup ";
            if (res.indexOf("OK") != -1) {webpage += "OK!</html>";}
            else {webpage += "Failed!</html>";}
            String cipSend="AT+CIPSEND=";
            cipSend += connectionId;
            cipSend += ",";
            cipSend +=webpage.length();
            cipSend +="\r\n";
            sendData(cipSend,1000,DEBUG);
            sendData(webpage,2000,DEBUG);
       
            String closeCommand = "AT+CIPCLOSE=";
            closeCommand+=connectionId; // append connection id
            closeCommand+="\r\n";
            sendData(closeCommand,3000,DEBUG);            
            }
          else { //show setup page
            String webpage="<html><form method=get action='/update/'>SSID ";
            webpage += "<input name=ssid type=text><br>";
            String cipSend = "AT+CIPSEND=";
            cipSend += connectionId;
            cipSend += ",";
            cipSend +=webpage.length();
            cipSend +="\r\n";
            sendData(cipSend,1000,DEBUG);
            sendData(webpage,2000,DEBUG);

            webpage="PWD <input name=pwd type=text> ";
            cipSend = "AT+CIPSEND=";
            cipSend += connectionId;
            cipSend += ",";
            cipSend +=webpage.length();
            cipSend +="\r\n";
            sendData(cipSend,1000,DEBUG);
            sendData(webpage,2000,DEBUG);

            webpage="<input type=submit value=Connect></form></html>";
            cipSend = "AT+CIPSEND=";
            cipSend += connectionId;
            cipSend += ",";
            cipSend +=webpage.length();
            cipSend +="\r\n";
            sendData(cipSend,1000,DEBUG);
            sendData(webpage,2000,DEBUG);

            String closeCommand = "AT+CIPCLOSE=";
            closeCommand+=connectionId; // append connection id
            closeCommand+="\r\n";
            sendData(closeCommand,3000,DEBUG);
            }
          }
        }
      }
    }
  }

//system use please do not edit
String sendData(String command, const int timeout, boolean debug) {
  String response="";
  esp8266.print(command); // send the read character to the esp8266
  long int time=millis();
  while ((time+timeout) > millis()) {
    while(esp8266.available()) {
      // The esp has data so display its output to the serial window
      char c=esp8266.read(); // read the next character.
      response += c;
      }
    }
  if (debug) {Serial.print(response);}
  return response;
  }

編譯後記憶體耗用情形 :

草稿碼使用了 9,078 bytes (29%) 的程式存儲空間。最大值為 30,720 bytes。
全域變數使用了 730 bytes (35%) 的動態記憶體,剩餘 1,318 bytes 供局部變數。最大值為 2,048 bytes 。

最後整理一下我這塊模組的保留腳位,  開發應用時不要使用這四個數位腳, 若用不到蜂鳴器, 可用尖嘴鉗拔掉被 Nano 蓋住的 Jumper (位於 USB 插槽正下方), 這樣 D9 就與蜂鳴器斷開可自由使用了.

 Nano 腳位 保留用途
 D4 模式選擇, LOW(上)=Wifi 設定, HIGH(下)=工作
 D7 軟體序列埠 Rx (接 ESP8266 Tx)
 D8 軟體序列埠 Tx (接 ESP8266 Rx)
 D9 蜂鳴器輸出 (可拔掉 Jumper 斷開)

2016-07-08 補充 :

跟 Q 小奇買的 3*7 cm 洞洞板到貨了, 跟禾樺買的大小一樣, 但洞多一排, 是 10*24 :


其實我買這一塊只是要比較看看哪裡不同而已, 我還是會用禾樺的 9*24 這塊, 因為布局與布線起來剛剛好.

另外訂製的壓克力保護板收到了, 雷射切割非常平整, 只是四個角的孔有些誤差, 螺絲鎖上去時不是很對稱, 所以改用塑膠螺母當墊片, 以三秒膠黏緊就好了 :


這樣其實四個角根本就不需要鑽洞啦!


沒有留言:

張貼留言