本項目是用arduino開源硬件,來快速制作具有無限數據傳輸功能的氣象站,我之前做過一個帶數據記錄功能的氣象站項目,這次算是升級和改進的版本。
第1步:構想
首先,需要增加從氣象站到室內接收器的無線數據傳輸功能,去掉了SD卡模塊,換成Arduino Uno接口擴展板。
這樣做的主要原因是為了節省空間,接口擴展版完全兼容Arduino Uno,因此無需使用導線進行連接。氣象站支架也進行了重新設計。之前的支架太低,而且不穩,所以我又做了一個新的支架(更高而且更穩)。對於直接安裝到氣象站支架上的外殼而言,我還增加了一個新的托架。此外,還增加了用於供電的太陽能板。
第2步:原材料
硬件清單:
- Weather station kit(氣象站套件,附有風速表/風標/雨斗)
- Arduino Uno開發板
- DFRduino Nano 3.0(兼容Arduino Nano)
- 用於Arduino的RF 433 MHz模塊(接收器和發射器)
- 雙面洞洞板 58mmx78mm
- SD卡
- 太陽能電源管理模塊(5V 1A)
- 半柔性單晶硅太陽能板 (5V 1A) x2
- 接口擴展板 (支持IIC,SPI,TLC,SD卡)
- 一些尼龍扎帶
- 安裝工具
- IIC/TWI LCD2004液晶模塊(Arduino兼容)
- 面包板
- 鋰離子電池(我用的是Sanyo 3.7V 2250mAh電池)
- 防水塑料接線盒
- 一些導線
在制作氣象站支架時需要:
- 大約3.4米長的鋼管(或者鋼板)。
- 鋼絲(大約4米)
- 鋼絲夾(8x)
- 不銹鋼螺絲扣(2x)
- fi10鋼棒(大約50厘米)
- 鋼吊環螺母(4x)
您還將需要以下工具:
- 烙鐵
- 螺絲刀
- 鉗子
- 電鑽
- 焊機
- 角磨機
- 鋼刷
第3步:小結
如前文所述,本篇教程是對上篇氣象站教程的升級。
如果您想了解如何組裝氣象站套件,請看組裝視頻:
第4步:氣象站安裝方案
還有一個問題,那就是如何安裝能夠承受室外條件的氣象站支架。
關於氣象站支架的類型和設計,我做了一些研究。最后我決定使用3米長的鋼管來制作支架。通常建議將風速計安裝到最高點(大約10米(33英尺)),但是由於我使用的是一體化氣象站套件,我選擇了套件建議的高度 - 大約3米(10英尺)。
我考慮的主要問題是,這個支架必須模塊化且易於拆卸,這樣便於轉移到其他位置。
組裝:
1、先從fi18 3.4m(11.15ft)長鋼管開始。在鋼管上塗一層酸性除銹劑,對鋼管進行除銹處理。
2、2到3小時后,除銹完成,接着把鋼管焊接起來。先把吊環螺母焊到鋼管兩端,然后把鋼管放到距地面2米的位置。當然還可以放到更高的位置,但是不能更低,否則靠上的部分就會變得不穩。
3、然后,需要在每一側制作一個“錨”。為此我使用了兩個fi12 50cm(1.64ft)鋼棒。在每個鋼棒的頂端焊上一個吊環螺母和一個小鋼板,這樣就可以把它踩到或用錘子砸到地里面。
如圖所示:
4、然后,使用鋼絲把“錨”上的吊環連到支架兩端。先拿來兩根1.7 m(5.57ft)長的鋼絲,一端用鋼絲夾直接固定到吊環螺母上,另一端固定到不銹鋼螺絲扣上。不銹鋼螺絲扣用於緊固鋼絲。
5、然后,使用一個3D打印托架將塑料接線盒安裝到支架上。更多詳情參見第5步。
6、最后,對每一個鋼制零件都塗上兩層底漆。在此基礎上,您可以塗上任何喜歡的顏色。
第5步:3D打印零件
為使安裝支架易於拆卸,需要制作一些3D打印零件。每一個零件都是我親自設計並使用PLA塑料打印出來的。
塑料接線盒托架
在上一篇教程中,我用鋼板制作了托架,但是不是特別實用。所以我決定使用3D打印零件再做一個。一共有五個3D打印零件,損壞的零件可以快速更換。
有了這個托架,塑料接線盒就能直接安裝到鋼管上。安裝高度也可以靈活調節。
溫濕度傳感器外殼
我需要為溫濕度傳感器設計一個外殼。在參考網上資料之后,我確定了這個外殼的最終形狀。我設計了帶托架的史蒂文森百葉箱,這樣所有部件都可以安裝到鋼管上。
它一共包括10個零件。主體底座由兩部分組成,頂部是一個“蓋子”,這樣就可以實現密封,不會進水。每一個零件都是使用PLA耗材打印而成。
第6步:室內數據接收器
本項目的主要升級就是增加了無線數據傳輸功能。所以還需要增加一個室內數據接收器。
為此,我使用了適合Arduino的430 MHz接收器,然后使用17厘米(6.7英寸)天線對其進行了升級。接着,需要測試一下該模塊的通信距離。第一項測試在室內進行,以確定牆壁對信號范圍的影響,以及會不會造成信號中斷。第二項測試是在室外進行。結果表明,該模塊的通信距離在10米(33英尺)以上,遠遠超出室內接收器的要求。
接收器所需零件:
- Arduino Nano
- Arduino 430 MHz接收器模塊
- RTC模塊
- LCD顯示器
- 一些接頭
如圖所示,這個接收器可以顯示室外溫度和濕度、日期和時間。
第7步:測試
在將各零部件組裝起來之前,必須進行一些測試。
首先要測試Arduino的發送和接收模塊。先得找到合適的代碼,然后進行修改以使其符合項目需求。我從最簡單的例子開始,從發射器向接收器發送一個字,測試成功之后再發送更多的數據。
然后需要對這兩個模塊的范圍進行測試。先把天線去掉,測試發現通信距離非常短,大約4米(13英尺)。然后把天線加上進行測試。通過相關研究和分析,我認為天線長度最好是17厘米(6.7英寸)。之后分別在室內和室外進行了測試,以確定環境對信號的影響。
最后,將發射器置於室外,接收器置於室內,再進行測試,以確定能否實現良好的室內接收效果。最初有一些信號中斷的問題,因為接收到的數據和發射的數據不一致。后來換上從ebay購買的433 Mhz模塊天線,才解決了這個問題。
這個模塊整體不錯,因為非常便宜,而且簡單易用,只不過由於存在信號中斷問題,使用距離會受到一定的限制。
代碼:
#include <SD.h> //SD #include <SPI.h> //SD File myFile; //SD int pinCS = 10; //////////// //LCD #include <Wire.h> #include <LiquidCrystal_I2C.h> #define BACKLIGHT_PIN 3 LiquidCrystal_I2C lcd(0x20, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); /////////// int sensorPin = A0; //battery voltage pin int sensorValue = 0; /////////////////// int sensorPin_solar = A1; //solar panel voltage pin int sensorValue_solar = 0; //////////////// char databuffer[35]; double temp; void getBuffer() //Get weather status data { int index; for (index = 0;index < 35;index ++) { if(Serial.available()) { databuffer[index] = Serial.read(); if (databuffer[0] != 'c') { index = -1; } } else { index --; } } } int transCharToInt(char *_buffer,int _start,int _stop) //char to int) { int _index; int result = 0; int num = _stop - _start + 1; int _temp[num]; for (_index = _start;_index <= _stop;_index ++) { _temp[_index - _start] = _buffer[_index] - '0'; result = 10*result + _temp[_index - _start]; } return result; } int WindDirection() //Wind Direction { return transCharToInt(databuffer,1,3); } float WindSpeedAverage() //air Speed (1 minute) { temp = 0.44704 * transCharToInt(databuffer,5,7); return temp; } float WindSpeedMax() //Max air speed (5 minutes) { temp = 0.44704 * transCharToInt(databuffer,9,11); return temp; } float Temperature() //Temperature ("C") { temp = (transCharToInt(databuffer,13,15) - 32.00) * 5.00 / 9.00; return temp; } float RainfallOneHour() //Rainfall (1 hour) { temp = transCharToInt(databuffer,17,19) * 25.40 * 0.01; return temp; } float RainfallOneDay() //Rainfall (24 hours) { temp = transCharToInt(databuffer,21,23) * 25.40 * 0.01; return temp; } int Humidity() //Humidity { return transCharToInt(databuffer,25,26); } float BarPressure() //Barometric Pressure { temp = transCharToInt(databuffer,28,32); return temp / 10.00; } void setup() { lcd.begin (20,4); lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE); lcd.setBacklight(HIGH); lcd.home (); ////////// Serial.begin(9600); //////// pinMode(pinCS, OUTPUT); // SD Card Initialization if (SD.begin()) { Serial.println("SD card is ready to use."); } else { Serial.println("SD card initialization failed"); return; } ////////// } void loop() { ////////////////// sensorValue = analogRead(sensorPin); //Monitoring battery voltage float voltage = sensorValue*(5.0/1023.0); lcd.setCursor(0,3); //0,3 lcd.print("Voltage bat: "); lcd.print(voltage); lcd.print(" V"); ///////////////// sensorValue_solar = analogRead(sensorPin_solar); float voltage_solar = 2*sensorValue_solar*(5.0/1023.0)-0.07; Serial.println(voltage_solar); // lcd.setCursor(0,2); //This is example how to set your LCD commands // lcd.print("Voltage sol: "); // lcd.print(voltage_solar); // lcd.print(" v"); ///////////////////// getBuffer(); //Begin! /////// if(WindDirection()==0){ Serial.print("Wind Direction: "); Serial.print("SW"); Serial.println(" "); } if(WindDirection()==45){ Serial.print("Wind Direction: "); Serial.print(" W"); Serial.println(" "); } if(WindDirection()==90){ Serial.print("Wind Direction: "); Serial.print("NW"); Serial.println(" "); } if(WindDirection()==135){ Serial.print("Wind Direction: "); Serial.print(" N"); Serial.println(" "); } if(WindDirection()==180){ Serial.print("Wind Direction: "); Serial.print("NE"); Serial.println(" "); } if(WindDirection()==225){ Serial.print("Wind Direction: "); Serial.print(" E"); Serial.println(" "); } if(WindDirection()==270){ Serial.print("Wind Direction: "); Serial.print("SE"); Serial.println(" "); } if(WindDirection()==315){ Serial.print("Wind Direction: "); Serial.print(" S"); Serial.println(" "); } // Serial.print("Wind Direction: "); //Serial.print(WindDirection()); // Serial.println(" "); Serial.print("Average Wind Speed (One Minute): "); Serial.print(WindSpeedAverage()); Serial.println("m/s "); Serial.print("Max Wind Speed (Five Minutes): "); Serial.print(WindSpeedMax()); Serial.println("m/s"); // lcd.setCursor(0,0); // lcd.print("Max Speed"); // lcd.print(" "); //lcd.print(WindSpeedMax()); // lcd.print(" "); // lcd.print("m/s"); Serial.print("Rain Fall (One Hour): "); Serial.print(RainfallOneHour()); Serial.println("mm "); Serial.print("Rain Fall (24 Hour): "); Serial.print(RainfallOneDay()); Serial.println("mm"); Serial.print("Temperature: "); Serial.print(Temperature()); Serial.println("C "); // lcd.setCursor(0,2); // lcd.print("Temperature: "); // lcd.print(Temperature()); // lcd.print("C "); Serial.print("Humidity: "); Serial.print(Humidity()); Serial.println("% "); Serial.print("Barometric Pressure: "); Serial.print(BarPressure()); Serial.println("hPa"); Serial.println(""); Serial.println(""); //// myFile = SD.open("test.txt", FILE_WRITE); if (myFile) { if(WindDirection()==0){ myFile.print("Wind Direction: "); myFile.print("SW"); myFile.println(" "); } if(WindDirection()==45){ myFile.print("Wind Direction: "); myFile.print(" W"); myFile.println(" "); } if(WindDirection()==90){ myFile.print("Wind Direction: "); myFile.print("NW"); myFile.println(" "); } if(WindDirection()==135){ myFile.print("Wind Direction: "); myFile.print(" N"); myFile.println(" "); } if(WindDirection()==180){ myFile.print("Wind Direction: "); myFile.print("NE"); myFile.println(" "); } if(WindDirection()==225){ myFile.print("Wind Direction: "); myFile.print(" E"); myFile.println(" "); } if(WindDirection()==270){ myFile.print("Wind Direction: "); myFile.print("SE"); myFile.println(" "); } if(WindDirection()==315){ myFile.print("Wind Direction: "); myFile.print(" S"); myFile.println(" "); } // myFile.print("Wind Direction: "); // myFile.print(WindDirection()); // myFile.println(" "); myFile.print("Average Wind Speed (One Minute): "); myFile.print(WindSpeedAverage()); myFile.println("m/s "); myFile.print("Max Wind Speed (Five Minutes): "); myFile.print(WindSpeedMax()); myFile.println("m/s"); myFile.print("Rain Fall (One Hour): "); myFile.print(RainfallOneHour()); myFile.println("mm "); myFile.print("Rain Fall (24 Hour): "); myFile.print(RainfallOneDay()); myFile.println("mm"); myFile.print("Temperature: "); myFile.print(Temperature()); myFile.println("C "); myFile.print("Humidity: "); myFile.print(Humidity()); myFile.println("% "); myFile.print("Barometric Pressure: "); myFile.print(BarPressure()); myFile.println("hPa"); myFile.println(""); myFile.println(""); myFile.print("Voltage bat: "); myFile.print(voltage); myFile.println(" V"); myFile.print("Voltage sol: "); myFile.print(voltage_solar); myFile.println(" V"); myFile.close(); // close the file } // if the file didn't open, print an error: else { Serial.println("error opening test.txt"); } delay(100); }
總結
這個項目從最初的想法變成最終的產品,整個過程非常有趣,也很有挑戰性。你需要花時間思考不同的選項。所以,整個項目要順利完成,就需要投入大量時間和精力,才能讓它變成你真正想要的樣子。
但是類似的項目也提供了很好的機會,讓你能夠不斷擴充升級在設計和電路方面的知識。此外,項目還包含了許多其他技術領域,比如3D建模、3D打印、焊接等等。所以,它不僅能讓你了解某一個技術領域,更重要的是讓你了解不同的技術領域如何交互作用,從而實現一個完整的項目。
該項目設計簡單,只要具備電路、焊接、研磨、設計等方面的基本技能,每個人都可以完成。最關鍵的要素還是時間。