用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打印、焊接等等。所以,它不仅能让你了解某一个技术领域,更重要的是让你了解不同的技术领域如何交互作用,从而实现一个完整的项目。
该项目设计简单,只要具备电路、焊接、研磨、设计等方面的基本技能,每个人都可以完成。最关键的要素还是时间。
用arduino制作具有无限数据传输功能的气象站的更多相关文章
- AndroidStudio制作登录和注册功能的实现,界面的布局介绍
前言 大家好,给大家带来AndroidStudio制作登录和注册功能的实现,界面的布局介绍的概述,希望你们喜欢 每日一句: Success is connecting with the world a ...
- 如何用HMS Nearby Service给自己的App添加近距离数据传输功能
当你给朋友发送手机资料时,过了很久进度条却动也不动:当你想发送大文件给同事时,仅一个文件就用光了你所有流量:当你跟朋友乘坐飞机时想一起玩游戏时,却因没有网络无奈放弃. 们生活中似乎经常能遇到这 ...
- 【原创】Arduino制作Badusb实践
1.U盘构造 U盘由芯片控制器和闪存两部分组成. 芯片控制器负责与PC的通讯和识别,闪存用来做数据存储: 闪存中有一部分区域用来存放U盘的固件,它的作用类似于操作系统,控制软硬件交互:固件无 ...
- ASCIITable: 演示 Arduino 串口输出的进阶功能
原文地址 - https://www.arduino.cc/en/Tutorial/ASCIITable ASCII字符表 本例展示了高级的串口打印功能,通过本功能可以在Arduino软件(IDE)的 ...
- excel具有制作甘特图的功能
1.Excel最大功能:数据处理.统计分析. 2.数据有效性验证: 长数字输入方法,文本前面加英文"'"(单引号)或使用文本转换. 身份证号:数据.数据有效性.文本长度. 性别:数 ...
- 极客DIY:使用Arduino制作一块开源手表
1 – 引言 首先让我们看下这个项目要考虑到的问题: .)使用100%Arduino兼容性硬件 .)保证存储器足够大可以装下大量的稍后会扩展的新内容 .)电量最少够1天用 .)BLE既是中枢设备又是外 ...
- WPF制作的一个小功能,智能提示(IntelliSense)
原文http://www.cnblogs.com/scheshan/archive/2012/06/30/2570867.html 最近WPF项目中遇到一个需求,需要给一个RichTextBox添加智 ...
- 用Arduino制作一个二维码显示器
先上图 场景是这样的, 这几天给CS系统做一个微信支付的功能, 但是生成的二维码是在前台的电脑上..不可能让用户跑到前台的电脑上去扫描...然后拿出了N年前买的Arduino 做了一个二维码显示器. ...
- 创建一个C++制作的包含Opencv功能的dll,供C#程序使用
目的:获取某图片指定位置的颜色. 实现该目的的方法有很多,但为了有助于扩充自己技术广度,所以决定采用标题中的方法来完成. 没有C++编程经验,也没有制作C++版Opencv语法经验,也没有制作dll的 ...
随机推荐
- Android 事件分发机制具体解释
很多其它内容请參照我的个人网站: http://stackvoid.com/ 网上非常多关于Android事件分发机制的解释,大多数描写叙述的都不够清晰,没有吧来龙去脉搞清晰,本文将带你从Touch事 ...
- 【转】opencart 源码解析
前台控制程序列表-catalog/controller Catalog|controller|account 会员功能 |—— account.php 会员功能主頁|—— address.php 会员 ...
- 关于QSocket的释放的一个需要注意的情况(必须先断开连接)
最近在用QtNetwork编写服务器程序进行TCP/IP通信,大体过程如下: 1. 创建一个QTcpServer实例,监听目标IP和端口: 2. 一旦监听到有连接,获取和客户端之间的socket: 3 ...
- 最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保留一块内存
申请效率的比较 栈:由系统自动分配,速度较快.但程序员是无法控制的. 堆:是由new分配的内存,最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保 ...
- UNITY VR 视频/图片 开发心得(二)
上回说到了普通的全景图片,这回讲真正的VR. 由于这种图片分为两部分,所以我们需要两个Camera对象以及两个球体.首先新建一个Camera对象,并将其命名为RightEye(其它名字也无妨,只要你自 ...
- ubuntu 16.04 android studio 开发环境搭建
安装步骤: 1. 安装 Java developer kit 2.安装 Android developer kit 3.安装 Android studio 4.真机调试 第一次用Linux,命令基本不 ...
- iostat命令浅析
报告中央处理器(CPU)统计信息.整个系统.适配器.TTY 设备.磁盘 CD-ROM.磁带和文件系统的异步输入/输出(AIO)与输入/输出统计信息,iostat也有一个弱点,就是它不能对某个进程进行深 ...
- js判断图片是否存在
var imageData = Array(); for(var i = 0; i < imageTemp.length; i++){ ajaxSizeRequest = $.ajax({ ty ...
- 毕设(三)NotifyIcon
NotifyIcon是一个比较特殊的组件,其特殊之处是既可以把它归类到控件中,也可以把它归类到组件中.这是因为将其拖放到设计窗体后,我们并不能马上看到它的界面(像组件),而是在运行时才能看到它(像控件 ...
- 修改用户名后TSF出现"需要本地工作区。工作区 xxx 并未驻留在本计算机上"
解决方法就是:1,打开vs下的"开发人员命令提示"2,按下面格式输入命令:tf workspaces /collection:http://192.168.0.110:8080/t ...