##一、 實驗目的和要求
#(1)設計並開發一個網絡應用軟件系統 二、 實驗內容和原理 實驗內容: 本實驗的目的是設計並開發一個物聯網彩燈系統,用於智能化的居家氛圍佈置、照明。系統的操控方式爲手機APP控制,通過MQTT遠程實現。完成的功能有自由控制顏色、亮度,既可以所有的LED燈一起進行操作,也可以對單獨LED等進行操作;一鍵彩燈,按下按鈕,即可按照設定好的氛圍光亮起彩燈,營造獨特的氛圍。本實驗對氛圍光只設定一個模式作爲例子,具體應用時完全可以添加更多的模式。另外,彩燈不僅使用與氛圍佈置,還兼容學習場合,一鍵可以調整至護眼模式。
開發語言:C語言(Arduino平臺)
#三、 架構設計:
1、 硬件部分。硬件包括一塊Nodemcu開發板、一個WS2812燈帶、一臺智能手機。
(1) Nodemcu開發板。NodeMCU,是一個開源的物聯網平臺,使用esp8266作爲核心 它使用Lua腳本語言編程,同時也可以使用Arduino進行編程。硬件配置主要有16個GPIO引腳,可實現1個模擬I/O和11個數字I/O。通訊接口有一個USB口、一個串口和一個Wifi通訊模塊。本實驗主要用到GPIO引腳來驅動WS2812,使用Wifi模塊連接網絡與服務器、手機進行通訊。
(2) WS2812。WS2812B是一個集控制電路與發光電路於一體的智能外控LED光源。其外型與一個5050LED燈珠相同,每個元件即爲一個像素點。像素點內部包含了智能數字接口數據鎖存信號整形放大驅動電路,還包含有高精度的內部振盪器和12V高壓可編程定電流控制部分,有效保證了像素點光的顏色高度一致。數據協議採用單線歸零碼的通訊方式,像素點在上電覆位以後,DIN端接受從控制器傳輸過來的數據,首先送過來的24bit數據被第一個像素點提取後,送到像素點內部的數據鎖存器,剩餘的數據經過內部整形處理電路整形放大後通過DO端口開始轉發輸出給下一個級聯的像素點,每經過一個像素點的傳輸,信號減少24bit。像素點採用自動整形轉發技術,使得該像素點的級聯個數不受信號傳送的限制,僅僅受限信號傳輸速度要求。LED具有低電壓驅動,環保節能,亮度高,散射角度大,一致性好,超低功率,超長壽命等優點。將控制電路集成於LED上面,電路變得更加簡單,體積小,安裝更加簡便。
2、 軟件部分。blinker是一套跨硬件、跨平臺的物聯網解決方案,提供APP端、設備端、服務器端支持,使用公有云服務進行數據傳輸存儲。可用於智能家居、數據監測等領域,可以幫助用戶更好更快地搭建物聯網項目。Blinker由服務器端、app端、設備端組成,可以部署到幾乎所有物聯網平臺,使用WiFi、MQTT等方式接入,服務器端可以部署到阿里雲、騰訊雲、OneNET、百度雲、AWS、google cloud等平臺,通過界面佈局器,DIY用戶可自己拖拽佈局設備控制界面,自由打造專屬的物聯網設備。3、 系統連接。
(1)Nodemcu和WS2812的連接方式如下:
以上紅色箭頭分別是D7、GND和VCC,其中Nodemcu的Vcc和ws2812的Vcc相連,Nodemcu的GND和ws2812的GND相連,Nodemcu的D7和ws2812的S(信號線)相連。
需要注意的是,ws2812所有的燈全亮電流超過500mA,無法通過電腦進行供電,需要外接電源。因此ws2812其實有兩根VCC和兩根GND。這兩根線是短路的,具體連接的時候一根GND連接Nodemcu的GND,另一根GND連接5V直流電源的GND。但是VCC不能兩根都連,一根VCC連接5V直流電源,另外一根VCC懸空。另外,信號線和Nodemcu的D7相連即可。(1)Nodemcu和手機APP的通信。本實驗沒有直接搭建服務器,而是採用了blinker解決方案的服務器。Nodemcu需要處於一個有wifi的局域網環境下,通過wifi接入Internet。通訊使用MQTT方式,即便用戶離開了現場也能夠進行操控。Nodemcu將祕鑰發送到blinker服務器並建立連接,手機APP通過開關按鍵發送祕鑰到服務器同樣建立連接。服務器識別到Nodemcu和客戶端同時發來了祕鑰後,開始在兩者之間傳遞命令協議。每個命令的發出都需要兩步,一是客戶端向Nodemcu發送指令,二是Nodemcu返回一個確認信息,客戶端接收到之後確認操作完成。
三、主要儀器設備
1、一塊Nodemcu開發板
2、一個WS2812燈條
3、Blinker手機app
四、設計要點 (1)下載正確的庫文件。本實驗對ws2812的操作與對單個LED不同,點亮單個基色LED編寫好PWM程序就可以調節亮度,不同亮度的三基色LED疊在一起就能呈現不同的顏色。但是ws2812是成線性排列的,所有的LED公用同一個根信號線,因此不能對LED進行單獨操作。此處需要用到ws2812的庫函數對其進行操作。 在github中搜索blinker library找到資源並下載,將下載好的blinker庫解壓到 我的電腦>文檔>Arduino>libraries 文件夾中
(2)獲得IoT設備祕鑰。祕鑰相當於一個設備的ID,服務器要找到特定的IoT設備,必須依賴該祕鑰。打開blinker app,點擊右上角的‘+’號,選擇Arduino,獲得祕鑰並複製。
(3)代碼中的IoT祕鑰、wifi名稱、wifi祕鑰必須正確輸入,否則設備無法與服務器連接。
(4)組件名稱要和代碼對應。如LEDNum對應Number_1,LED_R對應Number_2.
四、 實驗結果與分析
1、搭建好的硬件如下:
2、APP界面及組件如下:
3、工作時間顯示:工作時間能夠實時更新
2、自由控制(整體)模式:按下自由模式,按鈕高亮,點擊任一顏色,燈顏色改變,手機上顯示對應RGB值。圖中可以看出選中綠色RGB是[0,255,52]
3、七彩模式:按下七彩模式,按鈕高亮,ws2812直接顯示一個絢爛的彩色燈條。
4、逐個調節模式。按下逐個調節模式按鈕,按鈕高亮。這時可以按順序依次調節每一個燈珠的RGB值,當從第一個到最後一個都調整過以後,又重新回到第一個,循環進行。實驗中爲了顯示每個燈珠都可以自由調節,特意相鄰的燈珠選擇了反差明顯的顏色。
5、護眼照明模式。按下護眼照明模式按鈕,按鈕高亮。一鍵調整至護眼模式,此時是柔和的黃光。
以上結果達到預期要求。另外需要說明的是,本實驗對燈光效果只設定一個模式作爲例子,具體應用時完全可以添加更多的模式。
五、實驗注意1、本實驗主要的代碼內容是硬件設備Nodemcu上的,編寫硬件代碼比較麻煩的是參數的選取(關係到硬件是否能正產工作)。實驗時一開始時將ws2812的144個燈珠全部點亮,帶來了嚴重的問題,電腦突然掉電。重啓後Windows系統提示USB口電流過大,無法繼續使用。幸好內部電路沒有破壞性損壞,冷卻下來之後仍然能繼續工作,否則我的電腦就會損失一個USB口。2、明確電腦無法直接給ws2812供電之後,又找了一個220V轉5V的電源適配器來給ws2812供電(先接在麪包板上再借ws2812)。這樣一來144個LED燈珠都能正常工作。然而偶然觸摸麪包板溫度非常高,迅速拔掉電源後發現麪包板已經嚴重融化。可見144個燈珠同時亮起電流過大。3、最終才確定只點亮20個LED燈珠,防止再次出現意外。
六、附實驗代碼(C語言)
六、附實驗代碼(C語言)#define BLINKER_WIFI#include
<Blinker.h>#include<math.h>
char auth[] = "692310ffgrt";//IoT祕鑰
char ssid[] = "ONEPLUS";//wifi名稱
char pswd[] = "55555555"; //wifi祕鑰
bool tab[5] = { false };
bool modestate[4] = { false }; //工作模式選項卡
bool AutoBit= false; //判斷手動模式是否有效
bool SingleAdjust= false;//判斷逐個調節是否有效
int LEDserial=0;//
int Offset=20; //燈珠整體移動若干單位
#include <Adafruit_NeoPixel.h>#ifdef __AVR__ #include <avr/power.h>#endif #if defined (__AVR_ATtiny85__) if (F_CPU == 16000000) clock_prescale_set(clock_div_1);#endif #define PIN 13#define NUMPIXELS 20#define RGB_1 "RGBKey"#define Tab_1 "tab-mode"#define Number_1 "LEDNum"#define Number_2 "LED_R"#define Number_3 "LED_G"#define Number_4 "LED_B" BlinkerRGB WS2812(RGB_1);BlinkerTab Tab1(Tab_1);//定義數據結構
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
BlinkerNumber Number1 (Number_1);
BlinkerNumber Number2 (Number_2);
BlinkerNumber Number3 (Number_3);
BlinkerNumber Number4 (Number_4); //*************************************************************//選項卡觸發函數
void tab1_callback(uint8_t tab_set){ //BLINKER_LOG("get tab set: ", tab_set);
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
switch (tab_set) {
case BLINKER_CMD_TAB_0 :
tab[0] = true; //BLINKER_LOG("tab 0 set");
AutoBit=!AutoBit;//手動位取反
break;
case BLINKER_CMD_TAB_1 :
tab[1] = true; //BLINKER_LOG("tab 1 set");
Mode1();//開啓Mode1,燈光模式1
break;
case BLINKER_CMD_TAB_2 :
tab[2] = true; //BLINKER_LOG("tab 2 set");
SingleAdjust=!SingleAdjust;//開啓Mode2,燈光模式2 break;
case BLINKER_CMD_TAB_3 :
tab[3] = true; //BLINKER_LOG("tab 3 set");
Mode3();//開啓Mode3,流水燈模式
break;
case BLINKER_CMD_TAB_4 :
tab[4] = true; //BLINKER_LOG("tab 4 set");
break;
default:
break; }}
void tab1_feedback(){
for(uint8_t num = 0; num < 5; num++) {
if (tab[num]) {
Tab1.tab(num);
tab[num] = false; } }
Tab1.print();} //*******************************************************************//自由模式整體調節/逐個調節服務函數
void ws2812_callback(uint8_t r_value, uint8_t g_value, uint8_t b_value, uint8_t bright_value){
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
if (AutoBit==true){ digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
Mode0(r_value,g_value,b_value,bright_value); return NULL; }
else if(SingleAdjust==true){ digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
Mode2(r_value,g_value,b_value,bright_value); }}
//********************************************************************//自由控制(整體調節)Mode0
void Mode0(uint8_t r_value, uint8_t g_value, uint8_t b_value, uint8_t bright_value){
pixels.setBrightness(bright_value);
for(int i = 0; i < NUMPIXELS; i++){
pixels.setPixelColor(i, r_value, g_value, b_value); }
pixels.show();
Number2.print(r_value);
Number3.print(g_value);
Number4.print(b_value);}
//********************************************************************//七色模式Mode1
void Mode1(){
int r=0; int g=0; int b=0; int i=0; int full=NUMPIXELS;
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
for(int i=0;i<NUMPIXELS;i++){ if(i<full/3){ r=255; g=ceil(255*3*i/full); b=0; }else if(i<full/2){ r=ceil(750-i*(250*6/full)); g=255; b=0; }else if(i<full*2/3){ r=0; g=255; b=ceil(i*(250*6/full)-750); }else if(i<full*5/6){ r=0; g=ceil(1250-i*(250*6/full)); b=255; }else{ r=ceil(150*i*(6/full)-750); g=0; b=255; } pixels.setPixelColor(i, pixels.Color(r,g,b)); } pixels.show(); }//********************************************************************//逐個調節Mode2
void Mode2(uint8_t r_value, uint8_t g_value, uint8_t b_value, uint8_t bright_value){ pixels.setBrightness(bright_value); pixels.setPixelColor(LEDserial, r_value, g_value, b_value); pixels.show(); LEDserial=LEDserial+1; LEDserial= LEDserial % NUMPIXELS; Number2.print(r_value); Number3.print(g_value); Number4.print(b_value); }//*******************************************************************//護眼照明模式 黃光Mode3
void Mode3(){ int bright_value=200; int r_value=255; int g_value=215; int b_value=0; pixels.setBrightness(bright_value); for(int i = 0; i < NUMPIXELS; i++){ pixels.setPixelColor(i, r_value, g_value, b_value); } pixels.show(); Number2.print(r_value); Number3.print(g_value); Number4.print(b_value);}//*******************************************************************//顯示數值
void dataRead(const String & data){ uint32_t BlinkerTime = millis(); Number1.print(BlinkerTime/1000);} //*********************************************************************
void setup(){ Serial.begin(115200); BLINKER_DEBUG.stream(Serial); Blinker.attachData(dataRead); pinMode(LED_BUILTIN, OUTPUT);//引腳設置爲輸出模式
digitalWrite(LED_BUILTIN, LOW); Blinker.begin(auth, ssid, pswd); pixels.begin();//開啓pixel對ws2812輸出
WS2812.attach(ws2812_callback);
Tab1.attach(tab1_callback,
tab1_feedback);
}
void loop(){ Blinker.run();}