2016年6月16日 星期四

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

前天晚上我又製作了第二片 Arduino + ESP8266 物聯網模組, 從第一片的經驗我稍微修改了 Layout, 把模式切換用的滑動開關與 10K 電阻往邊邊平移一格, 主要是讓 10K 電阻靠近 EXP8266 排母 3.3V 附近的焊接點騰出一格來佈線, 同時滑動開關也能跟 Nano 的排母切齊. 佈線方式也為了跳線方便做了些微改變, 參考前文 :

# 製作 Arduino Nano + ESP8266 物聯網模組

新的布局與佈線圖如下所示 :

正面 (元件)

背面 (焊接面)

這裡我將跨焊改用藍色線條表示, 之前用黃色雖然醒目, 但列印出來卻是淡淡的顏色, 上回焊到最後以為可以收工了, 仔細比對實體與佈線圖, 卻發現竟然漏焊了部分跨焊點. 同樣地, 電阻的端線用棕色表示; 包覆跳線用紅色表示. 另外由於空間限制 (騰出一格給 ESP8266 的 3.3V 佈線), 10K 電阻只佔四格, 這對 1/2W 色碼電阻而言還 OK, 對 1/4W 或 1/8W 色碼電阻來說綽綽有餘. 其實用 1/8W 電阻即可, 因為 10K 電阻功耗為 P=V*V/R=5*5/10=2.5mW, 而 1/8W=125mW, 絕對足夠.

首先把排母, 電阻, 蜂鳴器等用三秒膠稍微固定在正面, AMS1117 穩壓 IC 固定在背面後, 就可以開始焊接. 先焊接各元件的接腳, 讓各元件都先固定在板子上, Nano 的排母都用跨焊方式相連, 完成後剪掉電阻的腳, 但這些鐵線要留下來作為輔助連線用 (即上面佈線圖中較長的藍色跨焊部分).  


焊接完成後的正面 :


元件焊接固定後的背面 :


完成跳線的背面 :


焊好滑動開關的正面 :


為了讓板子放在桌上時能四平八穩, 我在四個角角大圓洞位置用三秒膠黏上塑膠螺帽, 暫時當腳用, 等裁好壓克力板再用塑膠螺絲鎖上去 :


最後把 Nano 與 ESP8266 插上去就 OK 啦! 我會先用美工刀一一清理板子背面各接點周邊, 看看是否有跟旁邊接點藕斷絲連, 有時焊錫太大坨就會有這個問題. 然後用舊牙刷把背面刷一下. 


其實我是先插上 Nano 後送電, 以三用電表量看看 ESP8266 排母的 VCC 與 CH_PD 是否為 3.3V, 切換滑動開關, 量看看 Nano 的 D4 腳是否在 0 與 5V 間變化. 確定沒問題後再插上 ESP8266 比較安全. 

然後上傳程式範本 IOT_module_template.ino, 這裡我在 loop() 裡面的應用程式區塊放上對 ESP8266 下 AT 指令的程式, 將此模組切到工作模式即可對 ESP8266 下 AT 指令了 :

#include <SoftwareSerial.h>
#define DEBUG true
//-----application codes listed HERE (header file & macro)-----

//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=configuration, HIGH=working)
//-----application codes listed HERE (global variables)-----

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
    }
  String cifsr=sendData("AT+CIFSR\r\n",1000,DEBUG); //get ip address
  //-----application codes listed HERE (initialization)-----
  }

void loop() {
  if (mode==LOW) {setupWifi();} //system use please do not edit
  else { //-----application codes listed HERE (repeating codes)-----
    //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() {
  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);
            }
          }
        }
      }
    }
  }

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;
  }

我可能還需要再做兩三片模組, 然後接下來打算把上面的佈線圖改為雙層 PCB, 這樣就不用辛苦跳線與跨焊, 板子看起來也比較美觀專業. 不過儘管安裝了 Eagle 等免費 PCB 製作軟體, 但是我發現這需要花一點時間來學習, 所以想先用手繪方式來製作, 反正又不是多複雜的電路啊! 順便叫姊姊幫我在空白處手繪一個卡哇伊圖案.  

參考資料 :

# 自製電路板免費設計環境
電路板的製作
洗電路板初體驗
DIY手作自製PCB電路板蝕刻機
# KiCad EDA KiCad 說明書
# 配線、焊接技巧
# 【技巧】万能洞洞板的手工焊接说明

另外我發現一個不錯的 ESP8266 網站, 裡面有許多意想不到的瘋狂專案 : 

# Dangerous prototype : ESP8266

2016-06-18 補充 :

考慮用一塊壓克力板鎖在背面以保護焊錫面的線路, 因為原先以為可以用洞洞板切下來的另外一片 15*15 那塊來用, 但可惜它四個角的圓孔跟 16*15 這一半不重疊, 只好另尋它法. 我在露天找到台南紅蘋果這家專門做壓克力板切割的廠家, 接受少量訂製, 以 4.5cm*4.5cm 來說, 每片 6 元, 若在四個角落用雷射鑽圓孔加 5 元, 每片 11 元, 價格還 OK, 所以就畫了張規格給廠家訂製 10 片試試看合不合用 :


水平方向兩個孔中心距離固定是 3.5cm, 垂直方向中心距離固定是 3.75cm, 中心距離必須正確才能對準螺絲孔. 每個圓孔直徑 0.4cm.


沒有留言 :