在本教程中,我们将学习如何制作基于Arduino的无线气象站。您可以观看以下视频或阅读下面的书面教程。
使用DHT22传感器测量室外温度和湿度,并且使用NRF24L01收发器模块无线地发送到室内单元的数据。在室内单元,还有另一个DHT22传感器,用于测量室内温度和湿度,以及DS3231实时时钟模块,即使Arduino失去电源,也可以跟踪时间。所有这些数据都印在0.96“OLED显示屏上。
Arduino无线气象站电路图
让我们来看看电路图以及该项目的工作原理。请注意,我已经有详细的教程如何了解每个模块的工作,因此您可以查看更多详细信息:nrf24l01教程那DHT22教程那DS3231教程。
您可以从下面的链接获取此项目所需的组件:
- NRF24L01收发器模块.........。亚马逊/伯格多德/aliexpress.
- DHT22传感器................ ........................亚马逊/伯格多德/aliexpress.
- DS3231实时时钟.......................亚马逊/伯格多德/aliexpress.
- Arduino纳米 .......................................亚马逊/伯格多德/aliexpress.
必威外围提钱披露:这些是附属链接。作为一名亚马逊助理,我的收入来自符合条件的购买。
实时时钟模块和OLED显示屏都使用I2C协议进行与Arduino通信,因此它们连接到Arduino纳米板上的I2C引脚或模拟引脚数和5。在NRF24L01收发器模块旁边有一个电容器,可以使电源保持更稳定。还有一个连接到DHT22数据引脚的上拉电阻,以使传感器正常工作。
至于电源我使用12V直流电源适配器,用于室内机,另一侧,用于为室外单元供电,我使用两个LI-ON电池,产生约7.5V。通过这种配置,室外单元可以在电池放电前10天左右运行,因为我们周期性地传输数据,同时我们将Arduino放到睡眠模式,其中功耗仅为7mA。
定制设计PCB.
为了保持电子元件的组织,根据电路图我设计了必威lol一个定制的PCB使用Easyeda.免费在线电路设计软件。我们可以注意到室内机和室外机都可以使用同一个PCB,只是Arduino板的编程不同。
完成此处的设计后,我们只需导出用于制造PCB的格柏文件。您可以查看Arduino无线气象站的Easyeda项目文件这里。
然后我们可以从JLCPCB订购我们的PCB,这实际上是该视频的赞助商。
在这里,我们可以简单地拖放Gerber文件,上传之后,我们可以在Gerber查看器中查看我们的PCB。如果一切正常,我们就可以继续,为我们的PCB选择我们想要的属性,然后我们就可以以合理的价格订购我们的PCB。请注意,如果这是你从JLCPCB的第一个订单,你可以得到最多10个pcb只花2美元。
然而,几天后,多氯联苯就来了。pcb的质量是伟大的,一切都是完全相同的设计。
我开始通过焊接针头上的PCB来组装该项目的电子部件必威lol。通过这种方式,我们可以在需要时轻松连接和断开组件。
然后我也插入并焊接电容器和上拉电阻。使用此步骤完成,我们现在可以简单地将组件附加到PCB的引脚标题上。
接下来,我继续为项目进行案例进行。为此目的,我使用了8毫米蜱MDF板并使用圆锯,我将所有碎片缩小到大小。
为了精确测量温度和湿度,箱子的侧面必须允许空气进入箱子。所以,使用一个钻和锉刀,我做了几个插槽的侧板上的室内外单位。
我还在前面板上做了一个OLED显示屏的槽,并切了一小块铝片按尺寸贴在前面板上做装饰。
为了组装我用木材胶水和一些夹子以及一些螺钉。
我使用喷漆涂上案例。我用白色单位和室内单位的黑色涂料用白色涂料。涂料干燥后,我只是将PCB插入案件。
在室内机的背面我插了一个电源插孔和一个电源开关,在室外机上我用了一根简单的跳线作为电源开关。
就是这样,我们的Arduino无线气象站现在正在工作,但是在这个视频中留下的是看看程序的工作原理。
Arduino无线气象站代码
Arduino气象站户外单位代码:
/ * Arduino无线通信辅导户外单位 - 发射器由Dejan Nedelkovski,www.www.mfxpo.com图书馆:nrf24l01 - tmrh20 /bet188官方网站 rf24,https://github.com/tmrh20/rf24/ dht22 - dhtlib,https://github.com/ robtillaart / arduino / tree / master / libraries / dhtlib lowpower - https://github.com/rocketscream/low-power * / #include#include #include #include #include #define datapin 8 // dht22 data pin 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);电台.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传感器或那种温度和湿度读取数据。最初这些值是整数并分开的,因此我将它们转换为单个字符串变量,将它们放在字符数组中,并使用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,Inhum,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};
为此,我们可以使用g,一个开源图像编辑器,我们可以绘制任何东西,然后将其导出为位图(.xbm)。
然后我们可以用记事本打开这个文件,从那里我们可以复制位图到Arduino代码。
请注意,这里我们可以使用progmem变量修改器将位图定义为常量,这使得位图将存储在闪存中而不是Arduino板的SRAM。
静态const unsigned char温度_20iCon_bits [] u8x8_progmem //保存在闪存静态无符号char温度_20iCon_bits [] //保存在SRAM中
在setup部分,我们需要初始化无线通信,以及初始化OLED显示器和实时时钟模块。
然后在循环部分中,我们不断检查是否有可通过NRF24L01模块读取的传入数据。如果为true,则使用radio.read()函数我们读取它,并将前两个字符存储到温度字符串变量中,并将下两个字符变为湿度串变量。
然后,我们使用Millis()函数以以与我将其设置为3秒的间隔变量的间隔显示显示的各种数据。我们正在使用Millis()函数,因为通过这种方式,可以重复执行代码的其余部分,而在我们使用延迟()函数时,程序会等待该期间,以便我们可能会错过传入数据从室外单位。
接下来,使用U8G2库的第一个()和NextPage()函数,我们打印五个不同的屏幕,这些屏幕定义为自定义功能。
绘制()自定义函数从实时时钟模块获取日期和时间信息,并适当地打印显示屏上。TraxIntemperature()功能读取室内温度并在显示器上适当地打印。实际上,相同的方法用于打印显示器上的所有屏幕。
所以这就是全部,我希望你喜欢这个Arduino项目并且学到了一些新的东西。请在下面的评论部分提出任何问题。
我以为这将是一个伟大的主意,因为我一直想要自己的气象站并决定给它试一试。
我跟随你关于东西的电子方面的指示,并在我去的时候测试了每个部分。
但是,在尝试将脚本上传到纳米或我的UNO时,它拒绝识别“DHT.H”即使我找到它,也可以将其放在与脚本相同的文件夹中。有没有其他人有这个问题,或者有没有办法解决它
嘿,图书馆确实有问题。请确保下载并正确安装到Arduino库目录中。我可以注意到,我为GitHub上的库提供的链接现在没有下载按钮。你需要倒退两步,Arduino/libraries/DHTlib/。因此,在Arduino页面会出现下载按钮,因此下载所有库并将DHT库文件夹复制到Arduino库目录中。我希望这能行得通。
你好,如何设置RTC的日期和时间?
取消注释代码设置部分中的集合函数。
你好,伟大的教程!一个小问题,如果没有i2c,我将如何使用16×2 lcd而不是Oled?谢谢
谢谢并确定您可以使用该液晶显示器,但您需要适当地调整代码。
你能给我一个例子吗?我之前使用了16×2液晶,但不是NRF24L01,并且我非常困惑。它在Arduino项目列表上说,您可以使用此屏bet188me幕,以便我假设将提供适当的调整?
如何调整代码以使用16×2液晶屏?任何帮助,将不胜感激
好日子先生
我用的是dht11,这个设置可以吗?这么说,它拥有同样的图书馆?
由于多
是的,DHT11应该与DHT22相同。
你好,
谢谢你的代码。除了室外温度和湿度不会改变之外,一切都很好。DHT22传感器正常工作。发送/接收数据是否正确存在问题?你知道代码中可能是什么吗?
嗯,是的,我猜无线电通信是问题。尝试更简单的代码来测试通信是否正常工作,例如,尝试代码形成我的基本NRF24L01模块教程。
你好,
这是它显示出外部温度和湿度,但它只是显示一次,如果外部单元的温度或湿度发生变化,它不会在显示器上显示变化。
你知道我怎样才能解决这个问题吗?
你好,我目前正在研究这个项目,因为这将是我的小型工作台的完美补充,但我一直得到相同的错误代码。
“Arduino:1.8.7(Windows 10),董事会:”Arduino Nano,Atmega328P“
arduino_wireless_weather_station_indoor_reciever:15:21:错误:u8g2lib.h:没有这样的文件或目录
汇编终止。
退出状态1.
U8g2lib。h:没有这样的文件或目录
在C:\ Users \ Jim \ Documents \ Arduino \ Libraries \ U8G2中找到的无效库:在C:\ Users \ Jim \ Documents \ Arduino \ Libraries \ U8G2中找不到标题文件(.h)
此报告将有更多信息
“在编译期间显示详细输出”
选项在文件中启用 - >首选项。
我已经下载并加载了您在本教程中指定的U8G2库,但正如您所看到的,程序拒绝识别它,即使它已经正确安装在Libraries文件夹中。你有什么建议吗?我真的希望这能成功。谢谢你!
必须说,这个项目教会了我很多关于这些东西的新东西,我是一个退休的木工,所以建造盒子等对我来说很容易。下一步我了解了这个网站的多氯联苯很容易订购我的第一个多氯联苯了解了Gerber文件
编程的最大问题,对于你newies如果你买像我一样廉价克隆arduino nano看线或youtube上设置这些,这是一个星期的头发拉喊着屏幕和很多粗口发现一个视频在youtube上5个最常见的arduino nano克隆问题及其解决方案,这是一个重要视频木制头喜欢我。所以,如果你像我一样,在这类事情上是全新的,坚持下去,你会在最后到达那里,非常感谢