用arduino製作具有無線資料傳輸功能的氣象站
本專案是用arduino開源硬體,來快速製作具有無限資料傳輸功能的氣象站,我之前做過一個帶資料記錄功能的氣象站專案,這次算是升級和改進的版本。
第1步:構想
首先,需要增加從氣象站到室內接收器的無線資料傳輸功能,去掉了SD卡模組,換成Arduino Uno介面擴充套件板。
這樣做的主要原因是為了節省空間,介面擴充套件版完全相容Arduino Uno,因此無需使用導線進行連線。氣象站支架也進行了重新設計。之前的支架太低,而且不穩,所以我又做了一個新的支架(更高而且更穩)。對於直接安裝到氣象站支架上的外殼而言,我還增加了一個新的托架。此外,還增加了用於供電的太陽能板。
第2步:原材料
硬體清單:
在製作氣象站支架時需要:
您還將需要以下工具:
第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英尺)以上,遠遠超出室內接收器的要求。
接收器所需零件:
如圖所示,這個接收器可以顯示室外溫度和溼度、日期和時間。
第7步:測試
在將各零部件組裝起來之前,必須進行一些測試。
首先要測試Arduino的傳送和接收模組。先得找到合適的程式碼,然後進行修改以使其符合專案需求。我從最簡單的例子開始,從發射器向接收器傳送一個字,測試成功之後再發送更多的資料。
然後需要對這兩個模組的範圍進行測試。先把天線去掉,測試發現通訊距離非常短,大約4米(13英尺)。然後把天線加上進行測試。通過相關研究和分析,我認為天線長度最好是17釐米(6.7英寸)。之後分別在室內和室外進行了測試,以確定環境對訊號的影響。
最後,將發射器置於室外,接收器置於室內,再進行測試,以確定能否實現良好的室內接收效果。最初有一些訊號中斷的問題,因為接收到的資料和發射的資料不一致。後來換上從ebay購買的433 Mhz模組天線,才解決了這個問題。
這個模組整體不錯,因為非常便宜,而且簡單易用,只不過由於存在訊號中斷問題,使用距離會受到一定的限制。
程式碼:
#include
#include
File myFile; //SD
int pinCS = 10;
////////////
//LCD
#include
#include
#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列印、焊接等等。所以,它不僅能讓你瞭解某一個技術領域,更重要的是讓你瞭解不同的技術領域如何互動作用,從而實現一個完整的專案。
該專案設計簡單,只要具備電路、焊接、研磨、設計等方面的基本技能,每個人都可以完成。最關鍵的要素還是時間。