Arduino无线气象站项目

在本教程中,我们将学习如何制作一个基于Arduino的无线气象站。你可以观看下面的视频或阅读下面的书面教程。

概述

使用DHT22传感器测量室外温度和湿度,并且使用NRF24L01收发器模块无线地发送到室内单元的数据。在室内单元,还有另一个DHT22传感器,用于测量室内温度和湿度,以及DS3231实时时钟模块,即使Arduino失去电源,也可以跟踪时间。所有这些数据都印在0.96“OLED显示屏上。

Arduino无线气象站电路图

让我们来看看电路图以及该项目的工作原理。请注意,我已经有详细的教程如何了解每个模块的工作,因此您可以查看更多详细信息:nrf24l01教程DHT22教程DS3231教程

Arduino无线气象站电路图

您可以从下面的链接获取此项目所需的组件:

必威外围提钱披露:这些是联盟链接。作为亚马逊助理,我从合格购买中获得。

实时时钟模块和OLED显示屏都使用I2C协议进行与Arduino通信,因此它们连接到Arduino纳米板上的I2C引脚或模拟引脚数和5。在NRF24L01收发器模块旁边有一个电容器,可以使电源保持更稳定。还有一个连接到DHT22数据引脚的上拉电阻,以使传感器正常工作。

至于电源我使用12V直流电源适配器,用于室内机,另一侧,用于为室外单元供电,我使用两个LI-ON电池,产生约7.5V。通过这种配置,室外单元可以在电池放电前10天左右运行,因为我们周期性地传输数据,同时我们将Arduino放到睡眠模式,其中功耗仅为7mA。

定制设计PCB.

为了保持电子组件组织,根据电路图,我设计了必威lol一种使用该定制PCBEasyEDA免费在线电路设计软件。我们可以注意到,相同的PCB可用于室内和室外单元,只有Arduino板应该以不同的方式编程。

Arduino气象站定制PCB设计

一旦我们完成这里的设计,我们可以简单地导出用于制造PCB的Gerber文件。可以查看Arduino无线气象站的EasyEDA项目文件这里

然后我们可以从JLCPCB订购我们的PCB,这实际上是该视频的赞助商。

在这里,我们可以简单地拖放格柏文件,一旦上传,我们可以在Gerber Viewer中查看我们的PCB。如果一切都正确,那么我们可以继续,选择我们为PCB的属性,然后我们可以以合理的价格订购我们的PCB。请注意,如果它是jlcpcb的第一个订单,您只需2美元即可获得10台PCB即可。

尽管如此,在几天后,PCB已经到了。PCB的质量很大,一切都与设计完全相同。

我开始组装这个项目的电子元件,焊接引脚头到PCB上必威lol。通过这种方式,我们可以在需要时轻松地连接和断开组件。

然后我也插入并焊接电容器和上拉电阻。使用此步骤完成,我们现在可以简单地将组件附加到PCB的引脚标题上。

接下来,我继续为项目做案例。为了达到这个目的,我使用了8mm的中密度纤维板,并使用圆锯,我切割所有的碎片大小。

为了具有精确的温度和湿度测量,壳体的侧面必须允许空气进入这种情况。因此,使用钻头和锉刀,我在室内和室外单位的侧面板上制作了几个插槽。

我还为前面板上的OLED显示屏制作了一个插槽,以及将一小块铝制成尺寸,以至于我稍后将作为装饰附着在前面板上。

为了组装我用木材胶水和一些夹子以及一些螺钉。

我用喷漆把箱子涂上了。室外机用白色,室内机用黑色。油漆干后,我简单地把pcb插入到箱子里。

在室内单元的背面,我插入了电源插孔和电源开关,在室外单元上,我使用简单的跳线作为电源开关。

就这样,我们的Arduino无线气象站现在可以工作了,但在这个视频中,我们要看看这个程序是如何工作的。

Arduino无线气象站代码

Arduino气象站户外单位代码:

/* Arduino Wireless Communication Tutorial Outdoor unit - Transmitter by Dejan Nedelkovski, www.bet188官方网站HowToMechatronics.comNRF24L01 - TMRh20 / RF24 https://github.com/tmrh20/RF24/ DHT22 DHTlib, https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib低电力——https://github.com/rocketscream/Low-Power * / # include < SPI.h > # include < nRF24L01.h > # include < RF24.h > # include < dht.h > # include < LowPower.h > # define dataPin 8 / / DHT22销dht dht的数据;//创建一个DHT对象RF24 radio(10,9);// CE, CSN const字节地址[6]= "00001";char thChar[32] = "";String thString = "";Void setup() {radio.begin();radio.openWritingPipe(地址);radio.setPALevel (RF24_PA_MIN);radio.stopListening (); } void loop() { int readData = DHT.read22(dataPin); // Reads the data from the sensor int t = DHT.temperature; // Gets the values of the temperature int h = DHT.humidity; // Gets the values of the humidity thString = String(t) + String(h); thString.toCharArray(thChar, 12); // Sent the data wirelessly to the indoor unit for (int i = 0; i <= 3; i++) { // Send the data 3 times radio.write(&thChar, sizeof(thChar)); delay(50); } // Sleep for 2 minutes, 15*8 = 120s for (int sleepCounter = 15; sleepCounter > 0; sleepCounter--) { LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); } }

描述:室外机是无线通信的发射机,所以首先我们需要包括RF24库,DHT图书馆以及低功耗库用来让Arduino进入睡眠模式。

在定义了它们的实例、模块连接到的引脚和一些变量之后,在设置部分我们需要初始化无线通信地址。然后在回路部分,首先我们从DHT22传感器读取数据,这是温度和湿度。最初,这些值是整数并且是分开的,因此我将它们转换为单个String变量,将它们放入字符数组中,并使用radio.write()函数将这些数据发送到室内单元。使用for循环,我们发送数据3次,以确保在控制器在发送时忙碌时,接收方将获得数据。

最后,我们将Arduino设置为睡眠模式一段时间,以最小化功耗。

Arduino气象站室内单元代码:

/ * Arduino无线通信辅导室内单位 - 接收器由Dejan Nedelkovski,www.www.mfxpo.com图书馆:DS3231  -  http:/bet188官方网站/www.rinkydinkelectronics.com/library.php?id=73 U8G2必威lol  -  https://github.com/Olikraus / U8G2 * / #include  #include  #include  #include  #include  #include  #define Datapin 8 // DHT22传感器DHT DHT;//创建DHT对象DS3231 RTC(SDA,SCL);U8G2_SSD1306_128X64_NONAME_1_HW_I2C U8G2(U8G2_R0,/ * RESET = * / U8X8_PIN_NONE);RF24收音机(10,9);// CE, CSN const字节地址[6]= "00001";char text [6] =“”;int readdht22,t,h;字符串Intemp,Inh​​um,OutTemp,Outhum;String RTCTIME,RTCDATE;int draw_state = 0; unsigned long previousMillis = 0; long interval = 3000; #define Temperature_20Icon_width 27 #define Temperature_20Icon_height 47 static const unsigned char Temperature_20Icon_bits[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0xe1, 0x00, 0x00, 0xe0, 0xc0, 0x01, 0x00, 0x60, 0x80, 0xf9, 0x03, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x79, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0xf9, 0x03, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x8c, 0x79, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0xf9, 0x03, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x79, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0xf9, 0x03, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x70, 0x9e, 0x03, 0x00, 0x38, 0x1e, 0x07, 0x00, 0x18, 0x3e, 0x0e, 0x00, 0x1c, 0x3f, 0x0c, 0x00, 0x0c, 0x7f, 0x18, 0x00, 0x8c, 0xff, 0x18, 0x00, 0x8e, 0xff, 0x38, 0x00, 0xc6, 0xff, 0x31, 0x00, 0xc6, 0xff, 0x31, 0x00, 0xc6, 0xff, 0x31, 0x00, 0x8e, 0xff, 0x38, 0x00, 0x8c, 0xff, 0x18, 0x00, 0x0c, 0x7f, 0x1c, 0x00, 0x3c, 0x1c, 0x0e, 0x00, 0x78, 0x00, 0x06, 0x00, 0xe0, 0x80, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #define Humidity_20Icon_width 27 #define Humidity_20Icon_height 47 static const unsigned char Humidity_20Icon_bits[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, 0x86, 0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x03, 0x07, 0x00, 0x80, 0x03, 0x06, 0x00, 0x80, 0x01, 0x0c, 0x00, 0xc0, 0x01, 0x1c, 0x00, 0xc0, 0x00, 0x18, 0x00, 0xe0, 0x00, 0x38, 0x00, 0x60, 0x00, 0x30, 0x00, 0x70, 0x00, 0x70, 0x00, 0x30, 0x00, 0xe0, 0x00, 0x38, 0x00, 0xc0, 0x00, 0x18, 0x00, 0xc0, 0x01, 0x1c, 0x00, 0x80, 0x01, 0x0c, 0x00, 0x80, 0x03, 0x0e, 0x00, 0x80, 0x03, 0x06, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x06, 0x63, 0x00, 0x00, 0x06, 0x63, 0x00, 0x00, 0x06, 0x63, 0x00, 0x00, 0x06, 0xe3, 0x00, 0x00, 0x06, 0xc7, 0x00, 0x00, 0x06, 0xc6, 0x01, 0x00, 0x07, 0x86, 0x03, 0x00, 0x03, 0x0e, 0x1f, 0x00, 0x03, 0x0e, 0x1e, 0x80, 0x01, 0x1c, 0x00, 0xc0, 0x01, 0x38, 0x00, 0xe0, 0x00, 0x78, 0x00, 0x70, 0x00, 0xf0, 0x00, 0x38, 0x00, 0xe0, 0x07, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }; void setup() { radio.begin(); radio.openReadingPipe(0, address); radio.setPALevel(RF24_PA_MIN); radio.startListening(); u8g2.begin(); rtc.begin(); } void loop() { if (radio.available()) { radio.read(&text, sizeof(text)); // Read incoming data outTemp = String(text[0]) + String(text[1]) + char(176) + "C"; // Outdoor Temperature outHum = String(text[2]) + String(text[3]) + "%"; // Outdoor Humidity } unsigned long currentMillis = millis(); if (currentMillis - previousMillis > interval) { previousMillis = currentMillis; u8g2.firstPage(); do { switch (draw_state ) { case 0: drawDate(); break; case 1: drawInTemperature(); break; case 2: drawInHumidity(); break; case 3: drawOutTemperature(); break; case 4: drawOutHumidity(); break; } } while ( u8g2.nextPage() ); draw_state++; if (draw_state > 4) { draw_state = 0; } } } void drawDate() { String dowa = rtc.getDOWStr(); dowa.remove(3); rtcDate = dowa + " " + rtc.getDateStr(); u8g2.setFont(u8g2_font_timB14_tr); u8g2.setCursor(0, 15); rtcTime = rtc.getTimeStr(); // DS3231 RTC time rtcTime.remove(5); u8g2.print(rtcDate); u8g2.setFont(u8g2_font_fub30_tf); u8g2.setCursor(8, 58); u8g2.print(rtcTime); } void drawInTemperature() { readDHT22 = DHT.read22(dataPin); // Reads the data from the sensor t = DHT.temperature; // Gets the values of the temperature inTemp = String(t) + char(176) + "C"; u8g2.setFont(u8g2_font_helvR14_tr); u8g2.setCursor(24, 15); u8g2.print("INDOOR"); u8g2.setFont(u8g2_font_fub30_tf); u8g2.setCursor(36, 58); u8g2.print(inTemp); u8g2.drawXBMP( 0, 17, Temperature_20Icon_width, Temperature_20Icon_height, Temperature_20Icon_bits); } void drawInHumidity() { h = DHT.humidity; // Gets the values of the humidity inHum = String(h) + "%"; u8g2.setFont(u8g2_font_helvR14_tr); u8g2.setCursor(24, 15); u8g2.print("INDOOR"); u8g2.setFont(u8g2_font_fub30_tf); u8g2.setCursor(36, 58); u8g2.print(inHum); u8g2.drawXBMP( 0, 17, Humidity_20Icon_width, Humidity_20Icon_height, Humidity_20Icon_bits); } void drawOutTemperature() { u8g2.setFont(u8g2_font_helvR14_tr); u8g2.setCursor(12, 15); u8g2.print("OUTDOOR"); u8g2.setFont(u8g2_font_fub30_tf); u8g2.setCursor(36, 58); u8g2.print(outTemp); u8g2.drawXBMP( 0, 17, Temperature_20Icon_width, Temperature_20Icon_height, Temperature_20Icon_bits); } void drawOutHumidity() { u8g2.setFont(u8g2_font_helvR14_tr); u8g2.setCursor(12, 15); u8g2.print("OUTDOOR"); u8g2.setFont(u8g2_font_fub30_tf); u8g2.setCursor(36, 58); u8g2.print(outHum); u8g2.drawXBMP( 0, 17, Humidity_20Icon_width, Humidity_20Icon_height, Humidity_20Icon_bits); }

描述:在另一边,在室内单位或接收器,我们需要包括两个图书馆,一个是一个DS3231实时时钟模块一个用于OLED显示屏,U8G2库.与前面一样,我们需要定义下面程序所需的实例、引脚和一些变量。这里我们还需要将温度和湿度图标定义为位图。

温度图标位图:

#define温度_20iCon_width 27 #define温度_20iCon_height 47静态const unsigned char温度_20iCon_bits [] u8x8_progmem = {0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x80,0x7f,0x00,0x00,0xc0,0xe1,0x00,0x00,0x00,0xe0,0xc0,0x01,0x00,0x60,0x80,0xf9,0x03,0x60,0x80,0x01,0x00,0x60,0x0,0x01,0x00,0x60,0x01,0x00,0x60,0x80,0x79,0x00,0x60,0x79,0x00,0x60,0x80,0x01,0x60,0x80,0x01,0x00,0x80,0x01,0x00,0x0,0x01,0x00,0x60,0x80,0x01,0x00,0x03,0x60,0x0,0x01,0x00,0x60,0x0,0x01,0x0,0x0,0x01,0x00,0x60,0x01,0x79,0x0,0x0,0x79,0x0,0x60,0x9e,0x01,0x60,0x9e,0x01,0x00,0x0,0x01,0x00,0x60,0x01,0x00,0x60,0x01,0x00,0x60,0x01,0x00,0x0,0x0,0x01,0x00,0x60,0x0,0xF9,0x03,0x60,0x9e,0x01,0x0,0x60,0x9e,0x01,0x00,0x60,0x0,0x79,0x0,0x0,0x79,0x01,0x60,0x9e,0x01,0x00,0x60,0x01,0x00,0x60,0x01,0x01,0x60,0x01,0x01,0x00,0x60,0x9e,0xf9,0x03,0x60,0x9e,0x01,0x00,0x60,0x0,0x01,0x00,0x60,0x0,0x01,0x00,0x70,0x01,0x00,0x70,0x9e,0x03,0x00,0x38,0x1e,0x07,0x00,0x18,0x3e,0x0e,0x00,0x1c,0x3f,0x0c,0x00,0x0c,0x7f,0x18,0x00,0x8c,0xff,0x18,0x00,0x0,0xff,0x38,0x00,0xC6,0xF,0x31,0x00,0xC6,0xff,0x31,0x00,0xc6,0xff,0x31,0x00,0x8e,0xff,0x38,0x00,0x8c,0xff,0x18,0x00,0x0c,0x7f,0x1c,0x00,0x3c,0x1c,0x0,0x3c,0x1c,0x0e,0x00,0x78,0x00,0x06,0x00,0x00,0xe0,0x80,0x07,0x00,0xe0,0xff,0x03,0x00,0x80,0xFF,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00};

为此,我们可以使用GIMP,一个开源图像编辑器,通过它我们可以绘制任何东西,然后将其导出为位图(.xbm)。

然后我们可以使用记事本和从那里打开此文件,我们可以将位图复制到Arduino代码中。

请注意,这里我们可以使用progmem变量修改器将位图定义为常量,这使得位图将存储在闪存中而不是Arduino板的SRAM。

static const unsigned char Temperature_20Icon_bits[] U8X8_PROGMEM //保存在Flash内存中static unsigned char Temperature_20Icon_bits[] //保存在SRAM中

在设置部分中,我们需要初始化无线通信,以及初始化OLED显示和实时时钟模块。

然后在循环部分,我们不断检查是否有一个传入的数据可以通过NRF24L01模块读取。如果为真,使用radio.read()函数读取它,并将前两个字符存储到temperature String变量中,将后两个字符存储到humidity String变量中。

然后,我们使用Millis()函数以以与我将其设置为3秒的间隔变量的间隔显示显示的各种数据。我们正在使用Millis()函数,因为通过这种方式,可以重复执行代码的其余部分,而在我们使用延迟()函数时,程序会等待该期间,以便我们可能会错过传入数据从室外单位。

接下来,使用U8G2库的firstPage()和nextPage()函数,我们打印用自定义函数定义的五个不同的屏幕。

drawDate()自定义函数从实时时钟模块获取日期和时间信息,并将其打印在适当的显示器上。drawwintemperature()函数读取室内温度,并将其适当地打印在显示器上。事实上,同样的方法用于打印显示屏上的所有屏幕。

所以这就是全部,我希望你喜欢这个Arduino项目并学会了新的东西。随意询问以下意见部分中的任何问题。

15回应

  1. 彼得年轻人

    我以为这将是一个伟大的主意,因为我一直想要自己的气象站并决定给它试一试。
    我跟随你关于东西的电子方面的指示,并在我去的时候测试了每个部分。
    然而,当试图将脚本上传到Nano或我的Uno时,它拒绝识别“dht.h”。文件,尽管我找到了它,并把它放在了脚本的同一个文件夹。还有其他人遇到过这个问题吗?有没有解决的办法

    回复
    • 德扬

      嘿,这是肯定的图书馆的问题。确保您下载并将其正确安装到您的Arduino库目录中。我可以注意到GitHub上包含用于图书馆的链接我现在没有下载按钮。你需要走两步,“arduino / libraries / dhtlib /”。所以在Arduino页面上,将出现“下载”按钮,因此下载所有库并将DHT库文件夹复制到Arduino库目录中。我希望这将思考。

      回复
  2. Desie V- Zyl

    你好,伟大的教程!快速质疑我将如何在没有I2C而不是OLED中使用16×2 LCD?谢谢

    回复
      • Desie V- Zyl

        你能给我一个例子吗?我之前使用了16×2液晶,但不是NRF24L01,并且我非常困惑。它在Arduino项目列表上说,您可以使用此屏bet188me幕,以便我假设将提供适当的调整?

  3. Desie V- Zyl

    如何调整代码来使用16×2液晶屏?任何帮助都将不胜感激

    回复
  4. ernel

    好日子先生
    我正在使用DHT11,它是否与这些设置合作?因此它有同一个图书馆吗?
    谢谢

    回复
  5. Felix.

    你好,

    谢谢你的代码。除了室外温度和湿度不会改变之外,一切都很好。DHT22传感器正常工作。发送/接收数据是否正确存在问题?你知道代码中可能是什么吗?

    回复
    • 德扬

      嗯,是的,我猜无线电通信是问题。尝试更简单的代码来测试通信是否正常工作,例如,尝试代码形成我的基本NRF24L01模块教程。

      回复
      • Felix.

        你好,

        问题是它显示了外部的温度和湿度但它只显示一次如果外部设备的温度或湿度发生变化它不会在显示器上显示变化。

        你知道我如何解决这个问题?

  6. 吉姆

    你好,我目前正在这个项目上工作,因为这将是一个完美的添加到我的小工作台,但我一直得到相同的错误代码。

    Arduino: 1.8.7 (Windows 10), Board:“Arduino Nano, ATmega328P”
    Arduino_Wireless_Weather_Station_Indoor_Reciever:15:21:错误:U8g2lib.h:没有这样的文件或目录
    汇编终止。
    退出状态1.
    U8G2Lib.h:没有这样的文件或目录
    在c:\ users \吉姆\文档\ arduinoj \库\u8g2中发现的无效库:在c:\ users \吉姆\文档\ arduinoj \库\u8g2中发现的不头文件(.h)
    此报告将有更多信息
    “在编译期间显示详细输出”
    选项在文件中启用 - >首选项。

    我已下载并加载了您在此操作中指定的确切U8G2库,但尽管您可以看到该程序拒绝识别它,即使它已在Libraries文件夹中正确安装。你有任何建议吗?我真的很想工作。谢谢

    回复
  7. 伊恩史密斯

    必须说这个项目告诉我一个全部关于这些东西的新的东西,我是一个退休的木匠木匠,所以盒子的建设很容易。下一步,我了解了这个网站的PCB,很容易订购我的第一个PCB关于Gerber文件
    然后是最大的问题编程,如果你在那里出来的话,如果你买的那样,因为我做了便宜的克隆arduino nano看线或youtube关于设置这些,这是一周的拉头发在屏幕上喊叫,很多咒骂发现了一个视频YouTube 5最常见的Arduino纳米克隆问题及其解决方案这是一个像我这样的木头的伟大的视频。所以,如果像我一样,你是全新的东西,在这种事情上,继续挂钩,你将在最后到达那里非常感谢

    回复

发表评论

您的电子邮件地址不会被公开。

推荐

2019年最佳入门级示波器初学者和爱好者

为初学者和爱好者最好的示波器

推荐

2019年初学者的8个最佳Arduino Starter Kits

初学者的8个最佳Arduino Starter Kits

推荐

最佳3D打印机为初学者和爱好者- 3D打印

最好的3d打印机为初学者和爱好者