1. 程式人生 > >用arduino製作具有無限資料傳輸功能的氣象站

用arduino製作具有無限資料傳輸功能的氣象站

 

本專案是用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列印、焊接等等。所以,它不僅能讓你瞭解某一個技術領域,更重要的是讓你瞭解不同的技術領域如何互動作用,從而實現一個完整的專案。

該專案設計簡單,只要具備電路、焊接、研磨、設計等方面的基本技能,每個人都可以完成。最關鍵的要素還是時間。

&n