網頁最後修改時間:2017/09/13
我們最終的目的:就是要利用 nRF24L01+ 構建無線溫溼度節點群組 (sensor nodes),群組中的主節點負責接收其他節點的溫溼度數據,利用有線或無線網路 (ESP8266, WiFi Shield ... etc ) 的方式向伺服器 (例如 Blynk Server 、ThingSpeak ... etc ) 傳送並儲存數據,能夠在手機隨時監控與查詢各節點的溫溼度。
在這篇,將完成單點溫溼度無線傳輸與數據上傳 Blynk Server 的部分。與之前討論不同的是:發射端加入休眠功能,不傳送的時後,nRF24L01+ 與 Arduino Nano 進入 Power Down 休眠模式節省電力;接收端的整合型 LCD 增加一個可處理儲存於 Flash 字串的顯示函式,並且修改程式以解決 Blynk Arduino 函式庫記憶體需求的問題。
網頁裡面的程式碼以及使用的接線圖,會稍微不同此系列前面網頁所用的,但都是以其為基礎做增加和修改,建議先閱讀前面幾篇再來讀這篇。
Blynk 函式庫使用在 Arduino IDE 開發環境時,若使用 Arduino UNO / Nano (以 ATmega328P 晶片為核心) 的開發板配合 ESP8266,當不特別注意程式裡記憶體 (SRAM) 使用的情況時,就會遇到記憶體不足造成無法連線 Blynk Server 的問題 ( login timeout );即便已經連線上路由器取得 IP
Blynk server login timeout |
所以,為了解決這個問題,以凸顯出 Arduino 開發板配合 ESP8266,Blynk 函式庫比想像中需要更多的記憶體 (SRAM),所以多了一組接收端接線圖用來解釋與盡量解決這問題。
因此程式撰寫時需要特別去處理變數字串的問題,一但處理不當,耗費太多資源,Blynk Server 就會怎麼連也連不上,很搞人!但這也是官網為什麼建議直接使用 ESP8266 來做的原因。不過相比於 Arduino,ESP8266 IO 和 ADC 數目少,這也是為什麼還是有人執著用 Arduino 開發板配合 ESP8266 來做;只是更換為有更多記憶體晶片型式的 ( 例如,Mega2560...etc)。
反正不管如何,解決了 SRAM 記憶體佔用的問題,就能大致解決 Blynk Server login timeout 的困境,所以就讓我們開始吧!
參考接線圖:
這裡的接線圖跟此系列前幾篇網頁有些微不同,所以要注意接下來的各小節的說明,若之前已經接過線了,就把缺少的部分再補上去!
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
[ !!! 重要接線須知 !!! ]
- 接線圖裡面所使用的 ESP8266 無線網路模組,採用的是 ESP-01;但 ESP-01S 也可直接照著接 (其中,<EN> 可選擇接或不接 3V3 皆可 )。
- 請注意到,下面接線圖中所使用的 nRF24L0+ 無線模組,都是有加裝轉接板的!如果不接轉接板跟著接線會燒掉無線模組。
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 發射端:
發射端沿用*2*nRF24L01+*2* SHT31 單點無線溫溼度傳輸的接線圖,並在 <A0> 新增加了一顆狀態 LED。當這顆 LED 燈會亮起,表示數據傳送失敗,或是 (當使用電池時) 沒電了。
接線圖代號:sch-transmitter-00
參考接線圖 - 無線溫溼度發射端 |
* 發射端接線材料:
- Arduino Nano / Uno
- 一些杜邦線
- LED 燈
- R2 電阻 ( 假設 LED Vf = 2VDC, R 值取 150Ω 以上即可)
- 麵包板或Arduino Nano 擴充底板
- SHT31-D 溫溼度感測器
- NRF24L01+ (功率加強版本) 無線模組 (含轉接板)
- NRF24L01+ + PA+LNA 遠距離無線模組(含轉接板與 SMA 天線)
發射端實際接線完成參考圖 |
* 接收端:
接收端則有兩組接線圖 (可點擊看原圖),在圖左上角有接線圖的代號。
一組是沿用初遇 Blynk - {*2_1*nRF24L01+*2_1*}裡的接線圖。<A1> 增加了一個開關 (選擇是否輸出計算之後的 SHT31 溫溼度值)、 <D4> 增加一顆 LED 燈 (不能再使用板載的 <D13> LED 燈,會跟電路衝突) 和加入 nRF24L01+ 無線模組的線路。
另一組則是上面的線路再加上*2*nRF24L01+*2* SHT31 單點無線溫溼度傳輸的接線圖,但移除了不需要的開關,直接在程式裡面選擇輸出的方式,以節省記憶體。
接線圖代號:sch-receiver-01
參考接線圖 - 無線溫溼度接收端 (無外接 RTC 和 LCD 版本) |
接線圖代號:sch-receiver-02
參考接線圖 - 無線溫溼度接收端 (外接 RTC 與 LCD 版本) |
* 接收端接線材料:
- Arduino Nano / Uno
- 一些杜邦線
- LED 燈
- R2 (和 R6) 電阻 ( 假設 LED Vf = 2VDC, R 值取 150Ω 以上即可)
- R4 和 R5 (R7 和 R8) 可採用 四通道雙向邏輯電壓準位轉換模組 或使用分壓電路 ( 1K 和 2 K 電阻 )
- 麵包板或Arduino Nano 擴充底板
- V2.1 版 { 萬物皆聯網-ESP8266 IoT(Internet of Things)入門學習套件 }
- 裡面有 USB 轉 TTL模組、麵包板電源、杜邦線和 ESP8266, ESP-01S ( Ai-Mod, AT v1.2.0.0 based on SDK v1.5.4.1 )
- 高精度即時時鐘 DS3231 + 32KByte EEPROM二合一模組
- {5V}整合型 {4/8BIT, IIC, 4SPI}1602英文字型藍底白字 LCD 螢幕
- NRF24L01+ (功率加強版本) 無線模組 (含轉接板)
- NRF24L01+ + PA+LNA 遠距離無線模組(含轉接板與 SMA 天線)
Blynk 的安裝分為 Arduino IDE 和手機 APP 兩個部分,並且需要在 Blynk App 中載入此篇網頁要用的 Blynk Project。怎麼做,請上初遇 Blynk - {*2_1*nRF24L01+*2_1*}網頁照步驟安裝,這裡不再贅述!
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* Blynk Porject 按鈕修改:
手機裡面的 Blynk Project 載入之後,修改最下面的那顆按鈕所連結的 PIN "D13" 改為 "D4",因為 Arduino Nano 的 <D13> 是 SPI 介面的 SCK 腳位,已經被 nRF24L01+ 所用,所以不可以去控制它,否則無線通訊會失靈!
Arduino 程式碼:
在接下來網頁裡面所使用的 Arduino 程式碼,會大肆修改來自*2*nRF24L01+*2* SHT31 單點無線溫溼度傳輸網頁中的 nRF24one2oneSHT31Transmitter.ino 和 nRF24one2oneSHT31Receiver.ino 這兩個程式,使用者可先至該網頁裡面下載。
由於 Blynk Server 的條件限制,對於要儲存的數據,每分鐘只會儲存一筆,但是依然可接收每分鐘多筆數據的輸入,而這些數據將會平均之後更新為此分鐘所代表的數值,所以對於發射端與接收端的程式會進行如下的修改與設計:
* 發射端:
- 限制發射端每 15 秒傳送一次溫溼度數據 (raw data),其餘的時間 Arduino Nano 和 nRF24L01+ 進入睡眠狀態 (POWER DOWN MODE) 節省電量,非常適合用於電池供電的場合。
- 在通電的同時,可利用 <A1> 接腳選擇是否要進一步將數據計算,將數據計算成實際的溫溼度值。一般在經過測試階段之後,這功能就可以不再需要。
- 接腳 <A0> 接了一顆 LED 指示燈。只有當數據成功傳送出去時這一顆 LED 燈才會是熄滅的;亮起,表示通訊參數匹配出問題,無法正常傳送數據,或是接收端不存在。
- 限制接收端每秒執行四次數據接收與上傳
- 取消外部接腳輸出選擇功能
- 如果開啟整合型 LCD 顯示,日期與時間每秒鐘更新一次,溫度數據一經接收後計算就馬上顯示
- 如果開啟 DEBUG 模式,只輸出計算之後的溫溼度值
- 減少 Arduino Nano SRAM 的使用量
- 移除 BLYNK_LOG 字串輸出方式
- 整合型 LCD 支援處理儲存於 Flash 字串的顯示函式
- 重新整理程式碼
- 三種輸出模式選擇
- Blynk debug 與自訂訊息輸出
- DS3231 RTC 模組與整合型 LCD 訊息輸出
- 取消上面兩個輸出,只留下預設上傳到 Blynk Server 的溫溼度值
* 發射端程式碼:
在不要求電量限制的環境下,(使用原網頁的接線圖) nRF24one2oneSHT31Transmitter.ino 程式碼只需要修改 loop() 裡用到的 interval 就可以
/** time */ unsigned long previousMills = 0; const unsigned long interval = 16000L; // milliseconds //----------------------------------------- end of time
但!發射端與接收端不同的是,它通常都是放置在遙遠的另一端,而另一端剛好有插頭的情況也都不多,所以當在使用電池供應的場合中,只要微控制器不工作的時候,就要考慮讓微控制器進入休眠的狀態以延長電池使用的壽命。
所以原來的 nRF24one2oneSHT31Transmitter.ino 的程式配合 sch-transmitter-00 接線方式的程式碼,加入了狀態 LED 和休眠的功能之後,修改之後的程式碼如下
發射端程式碼下載
其中就新增休眠的函式部分做大概說明,因為這需要對照 ATMega328 的資料手冊來看,否則看不懂,所以我只針對其中比較重要的變數做說明。只要掌握這幾個變數的設定方式,休眠時間就可以自行修改;但其他的,就請自行消化了。
prescalar:位於 setSleepInterval() 函式中,用來設定使用的基本休眠時間間隔
0:16ms、 1:32ms、2:64ms、3:0.125 ssleep_cycles_remaining:位於 gotoSleep() 函式裡,用來設定總休眠時間
4:0.25 s、5:0.5 s、 6:1.0 s
7:2.0 s、 8:4.0 s、 9:8.0 s
以下面的程式碼做例子,基本休眠時間為 8 秒,循環兩次 (16秒) 後叫醒 Arduino Nano 工作。利用這個方式,要讓微控制器睡多久再工作一次,都只是這兩個變數設定的問題了。
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 31 32 | /******************************************* * sleep *******************************************/ ISR(WDT_vect) { --sleep_cycles_remaining; } void setSleepInterval() { uint8_t prescalar = 9; uint8_t wdtcsr = prescalar & 7; if ( prescalar & 8 ) wdtcsr |= _BV(WDP3); MCUSR &= ~_BV(WDRF); WDTCSR = _BV(WDCE) | _BV(WDE); WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE); } void gotoSleep() { sleep_cycles_remaining = 2; set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); WDTCSR |= _BV(WDIE); while( sleep_cycles_remaining ) { sleep_mode(); } sleep_disable(); WDTCSR &= ~_BV(WDIE); } |
另外,千萬別忘了!nRF24L01+ 也可以 powerDown() 節省電力,在休眠之前可以關掉。
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 接收端程式碼:
接收端的程式可以是初遇 Blynk - {*2_1*nRF24L01+*2_1*}網頁裡修改後的那個程式再加入 nRF24L01+ 硬體的程式修改而成,這是最簡單可完成的部分!但是除非與電腦連接,否則得不到任何除錯訊息或相關輸出。
另一個則是使用*2*nRF24L01+*2* SHT31 單點無線溫溼度傳輸網頁的 nRF24one2oneSHT31Receiver.ino 程式來做修改;也就是加入 ESP8266 與 Blynk 函式庫的支援。這部分會因為 Arduino Nano SRAM 記憶體限制的關係,必須重新考慮程式碼的撰寫方式,以增加 SRAM 的容量;這部分會在後面特別討論我所使用的方法。
** sch-receiver-01 接線搭配 初遇 Blynk - {*2_1*nRF24L01+*2_1*} 程式碼修改 **
----------------------------------------------------------------------------------------------------------
原網頁的程式,模擬 SHT31 的溫溼度值並傳送給 Blynk Server,所以少了 nRF24L01+ 接收和 SHT31 溫溼度模組的程式碼。接下來,讓我們把這些缺少的東西補進去
接收端程式碼下載
上面的程式碼,加入了 nRF24L01+ 無線模組接收的部分,以及 SHT31-D 溫濕度模組取值的函式,更名 insertTRH() 這個 Callback 函式的名稱為 updateTRH() 與裡面的程式碼。
由於我們使用了 Blynk 函式庫,因此程式撰寫上有一些限制。也就是說,setup() 函式處理了所有硬體零件初始化與設定的動作,任何需要週期性確認的東西,必須使用 BlynkTimer 來處理,不要直接寫進到 loop() 函式裡面。所以在裡面,我們設定一個每 100 ms 執行一次的函式 updateTRH(),負責檢查 nRF24L01+ 接收的狀態和計算出溫溼度值,溫溼度值可以經由外部接腳選擇是否要由 debugSerial 輸出。一但開機的同時,接腳 <A1> 接地就會進入 Blynk 除錯模式,執行時後就會將 Blynk 訊息輸出到 debugSerial 定義的通訊埠。
最後,需要注意一點的就是:Blynk.begin() 這一個函式在執行的時候,沒有連上線的時候是絕不會返回的!也就是說,這一行之後的程式碼都不會先執行,整個程式會在這裡停下來,一直等待 ESP8266 連上 Blynk Server,所以不要以為接下來的程式碼會先執行;因為在撰寫其他 ESP8266 standalone 程式時,連線指令發出之後下面的程式碼會繼續下去不會阻斷 (除非程式裡面自己阻斷),所以這點要注意,避免程式執行時,不曉得是停在無線連線是還是硬體初始化上。
講得有點多了,現在編譯與上傳這個程式到你的 Arduino Nano 去試試吧!
這個程式在執行上沒有任何的問題,但不知道眼尖的你(妳),有沒特別注意到編譯成功之後所輸出的記憶體使用的情況?
有沒看到,這個簡單的程式,Sketch 使用了 76% 的儲存空間 (Flash) 和 65% 的 SRAM 記憶體 。這個兩個數值請先記在心中,當接下來加入整合型 LCD 和 DS3231 RTC 模組的程式之後,可以想像會增加多少,而這又會對程式執行時造成什麼影響?
simpleBlynknRF24one2oneSHT31Receiver.ino 編譯輸出 |
simpleBlynknRF24one2oneSHT31Receiver.ino DEBUG 模式下 debugSerial 的輸出 |
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
[ 編譯大小 ]
由於程式裡面 auth, ssid, pass 這三個變數大家都不一樣,因此編譯出來的大小也會不同 (但是不會差太多),特此說明!
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
** sch-receiver-02 接線搭配*2*nRF24L01+*2* SHT31 單點無線溫溼度傳輸程式碼修改 **
-------------------------------------------------------------------------------------------------------------------
接下來的程式也可以由 simpleBlynknRF24one2oneSHT31Receiver.ino 來改,但反正我都給完整程式,所以其實也沒差!但如果真的想學習的話,這部分應該要想一下,如果是你(妳),你(妳)會怎麼改 ?
下面給出第一個版本的程式,直接用 *2*nRF24L01+*2* 的 nRF24one2oneSHT31Receiver.ino 加入 Blynk 使用 ESP8266 的程式碼,未作任何其他的處理
接收端程式碼下載
編譯程式與上傳後,接著看一下編譯之後的結果
BlynkSingleNodeWirelessReceiver00.ino 編譯結果 |
BlynkSingleNodeWirelessReceiver00.ino DEBUG 模式下 debugSerial 的輸出 |
讀者可以看到,ESP8266 確實是連上指定的 SSID 並且取得 IP,但是就是一直連不上 Blynk Server,很奇怪吧!
對,我也是這樣覺得!
不過,上了 Blynk 找了一些討論後發現,最有可能的是記憶體不足造成的
我的直覺認為,應該是與 Blynk 函式庫在連線時會需要大量的 SRAM 導致,剩餘 25% 的空間還是不足夠的,還要更多!
其實沒錯,嘗試過幾種方式的修改,即便 SRAM 已經降低到 68% 做測試,依然無法成功連線
BlynkSingleNodeWirelessReceiver02.ino 編譯結果 |
修改到這個地步,接下來就是修改輸出選擇的方式;不再使用接腳選擇輸出方式,而改用前置處理器讓程式編譯時選擇需要的部分,以這樣的方式減少 Flash 和 SRAM 記憶體的使用量。即使這樣只能二選一,但是當所有需要的訊息都可以在整合型 LCD 或是 debugSerial 各別輸出顯示時,為什麼還需要兩個一起做同樣的動作呢 ?
接收端程式碼下載
切換上面程式碼註解 line 9 或 line 10 (只能二選一) 其中一行,然後進行編譯可得到下面結果
BlynkSingleNodeWirelessReceiver03.ino 選擇開啟 DEBUG 模式選項 |
BlynkSingleNodeWirelessReceiver03.ino 選擇開啟 USEIICLCD 模式選項 |
Blynk 單點無線溫溼度測試:
接下來的測試需要發射端與接收端兩組裝置,依照接收端選擇的模式分別來做
* 發射端
- 接線圖:sch-transmitter-00
- 程式碼:nRF24one2oneSHT31TransmitterWithSleep.ino
* 接收端
- 接線圖:sch-receiver-01 (DEBUG 模式), sch-receiver-02 (USEIICLCD 模式)
- 程式碼:BlynkSingleNodeWirelessReceiver03.ino
Blynk 手機專案檔的效果跟 初遇 Blynk - {*2_1*nRF24L01+*2_1*} 網頁中展示的沒什麼不同,所以就沒有特別放在影片中了;一但接收端連線成功到 Blynk Server,Blynk 手機端就可以開始接收到資料。
兩個影片我都加上了簡單的字幕來做說明,因此就不再下面贅述相同的東西。測試時要注意的事項我列在下面:
- 發射端可以使用 PC 的 USB 供電
- 接收端若是使用 PC 端的 USB 供電,當發射端通電開始通訊的時候,有可能會造成接收端重置;因此影片中才在上傳程式之後使用外接電源供電。
- ESP8266 與 Arduino Nano 在影片中是使用兩個電源,因此供電有時間差。若是兩個裝置都使用同一個外接電源時,由於同時供電的關係,有可能會造成 Arduino Nano 太快傳送 AT 指令給 ESP8266,而 ESP8266 還沒準備好接收指令 ... 等類的連線失敗的問題;這時就要考慮在程式中適當的地方加入 delay(),讓裝置完全 ready 後再作後續控制的動作。
* 接收端 (DEBUG 模式):
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 接收端 (USEIICLCD 模式):
影片中整合型 LCD 的可變電阻接線不是太牢固,為了讓影片清楚一點,需要不時做調整,不好意思!
結論:
經過幾天的網頁的撰寫與程式測試下來,發現 Blynk 雖然好用,但是以 ATMega328 晶片作為核心的 Arduino 開發板,配合 ESP8266 來做開發會面臨 SRAM 短缺的問題;因為 ATMega328 只有 2KBytes 的 SRAM。
經過多次的測試之後發現,類似的 Arduino 開發板在編譯之後,至少還需要 SRAM 有 34% 的空間,否則就容易遇到 Login timeout 的問題;因此,以網頁中的開發方式,在撰寫程式時,應該盡量將字串儲存到 Flash,並且減少變數的宣告與使用,才能節省 SRAM 記憶體的使用。
Blynk 函式庫裡面有提供一個字串輸出函式:BLYNK_LOG#(),但是在上面的程式裡面都沒有看到,WHY ??? 原因是,測試過的結果顯示,將 debugSerial.print() 或是 debugSerial.println() 全部改成 BLYNK_LOG#() 函式來做輸出,上面其中一個程式的 SRAM 記憶體增加了 3% 的使用量。這也就是上面的程式完全看不到 BLYNK_LOG#() 的原因!
雖然這樣測試下來,可以知道官網為什麼建議要使用 ESP8266 standalone 來開發 Blynk 程式,而不是網頁中所使用的方式。但是,上面有提到過,個人需求和應用層面不同,有利就有弊,不是這樣做就不好,而是需要考量的東西會比較多,反而會比較複雜,考驗能力與功力!
單節點無線溫溼度傳輸的部分已經完成,多節點的部分就不會再使用 Arduino Nano 配合 ESP8266 來做了,因為程式空間與記憶體都已明顯不夠用了。接續的,應該會考慮 ESP8266 standalone 的方式,像是相容於 NodeMCU 開發板類型的 ESP8266 開發板來做,這種比較小巧,類似 Arduino Nano 開發板,接腳是排針不是插孔,做實驗比較方便。不過,因為電壓變成 3.3V,而且又是多點通訊,所以要去買料與準備料件了,就先到這!
<< 部落格相關網頁 >>
- Google Spreadsheet(試算表)之 ESP8266 溫濕度紀錄與趨勢圖
- 當 ESP8266 遇上中華電信 IoT 智慧聯網大平台 { 入門 - 07 } - 結合 Arduino + ESP8266 實現 MQTT 主題訂閱與接收
- 當 ESP8266 遇上中華電信 IoT 智慧聯網大平台 { 入門 - 06 } - 了解 MQTT 協議,學習如何訂閱 MQTT 主題與接收 MQTT 發佈消息
- 當 ESP8266 遇上中華電信 IoT 智慧聯網大平台 { 入門 - 05 } - 結合 ESP8266 發佈 MQTT 消息
- 當 ESP8266 遇上中華電信 IoT 智慧聯網大平台 { 入門 - 04 } - 了解 MQTT 協議,學習如何發佈 MQTT 消息
- 當 ESP8266 遇上中華電信 IoT 智慧聯網大平台 { 入門 - 03 } - 使用 Arduino + ESP8266 上傳 SHT31 溫溼度數據
- *0*nRF24L01+*0* Arduino 二點四GHz 訊號掃描器
- *1*RF24L01+*1* 如何提高 nRF24L01+ 板載天線無線模組的傳輸距離與穿牆效果 ? 加碼:不同天線形式的穿牆測試
- *2*nRF24L01+*2* SHT31 單點無線溫溼度傳輸
- 初遇 Blynk ( 物聯網手機 APP ) - 如何使用 Arduino 和 AT 韌體 ( Ai-Mod, AT v1.2.0.0 based on SDK v1.5.4.1 ) 的 ESP8266 (ESP-01, ESP-01S) 連上 Blynk 伺服器和儲存數據 {*2_1*nRF24L01+*2_1*}
- *3*nRF24L01+*3* 初遇 Blynk - 建立從 nRF24L01+ 到 ESP8266 再到 Blynk 的 SHT31 單點無線溫溼度傳輸物聯網
沒有留言:
張貼留言
留言屬名為"Unknown"或"不明"的用戶,大多這樣的留言都會直接被刪除掉,不會得到任何回覆!
發問問題,請描述清楚你(妳)的問題,別人回答前不會想去 "猜" 問題是什麼?
不知道怎麼發問,請看 [公告] 部落格提問須知 - 如何問問題 !