亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

Arduino无线气象站项目

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

概览

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

Arduino无线气象站电路图

让我们看一下电路图以及该项目的工作原理。请注意,我已经有关于这些模块如何工作的详细教程,因此有关更多详细信息,您可以查看它们:NRF24L01 教程、DHT22 教程、DS3231 教程。

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

  • NRF24L01 收发模块…………
  • DHT22传感器…………………………………………
  • DS3231 实时时钟…………………….. Amazon / Banggood / AliExpress
  • Arduino Nano………………………….……..

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

至于电源,我为室内机使用了 12V DC 电源适配器,另一方面,为室外机供电,我使用了两节锂电池,产生约 7.5V 的电压。使用这种配置,室外机可以在电池放电前运行大约 10 天,因为我们会定期传输数据,同时我们将 Arduino 置于睡眠模式,此时功耗仅为 7mA 左右。

定制设计PCB

为了保持电子元件井井有条,根据电路图,我使用 EasyEDA 免费在线电路设计软件设计了一个定制的 PCB。我们可以注意到,室内机和室外机都可以使用相同的 PCB,只是 Arduino 板的编程方式不同。

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

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

在这里,我们可以简单地拖放 Gerber 文件,上传后我们可以在 Gerber 查看器中查看我们的 PCB。如果一切正常,那么我们可以继续,为我们的 PCB 选择我们想要的属性,然后我们可以以合理的价格订购我们的 PCB。请注意,如果这是您从 JLCPCB 订购的第一个订单,您只需 2 美元即可获得多达 10 个 PCB。

然而,几天后,多氯联苯已经到货了。 PCB的质量很好,一切都与设计中的完全一样。

我开始通过将排针焊接到 PCB 上来组装这个项目的电子元件。通过这种方式,我们可以在需要时轻松连接和断开组件。

然后我还插入并焊接了电容器和上拉电阻。完成这一步后,现在我们可以简单地将组件连接到 PCB 的排针上。

接下来,我继续为该项目制作案例。为此,我使用了 8 毫米刻度 MDF 板并使用圆锯将所有部件切割成合适的尺寸。

为了获得准确的温度和湿度测量值,外壳的侧面必须允许空气进入外壳。所以,我用钻头和锉刀在室内和室外机的侧板上开了几个槽。

我还在前面板上为 OLED 显示屏制作了一个插槽,并将一小块铝切割成一定尺寸,稍后我将把它贴在前面板上作为装饰。

为了组装外壳,我使用了木胶和一些夹子,以及一些螺丝。

我用喷漆给箱子上漆。我为室外机使用白色油漆,为室内机使用黑色油漆。油漆干了之后,我就简单地将多氯联苯插入外壳中。

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

就是这样,我们的 Arduino 无线气象站现在正在运行,但本视频剩下的就是看看程序是如何工作的。

Arduino 无线气象站代码

Arduino气象站室外机代码:

/*
  Arduino Wireless Communication Tutorial
      Outdoor unit - Transmitter 
      
  by Dejan Nedelkovski, www.HowToMechatronics.com

Libraries:
NRF24L01 - TMRh20/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 <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <dht.h>
#include <LowPower.h>

#define dataPin 8 // DHT22 data pin
dht DHT; // Creates a DHT object

RF24 radio(10, 9); // CE, CSN
const byte address[6] = "00001";

char thChar[32] = "";
String thString = "";

void setup() {
  radio.begin();
  radio.openWritingPipe(address);
  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);
  }
}Code language: Arduino (arduino)

说明: 室外机是无线通信的发射器,所以这里首先需要包含RF24库,DHT库,以及用于让Arduino进入睡眠模式的LowPower库。

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

最后,我们将 Arduino 置于睡眠模式一段时间,以最大限度地降低功耗。

Arduino气象站室内机代码:

/*
  Arduino Wireless Communication Tutorial
        Indoor unit  - Receiver

  by Dejan Nedelkovski, www.HowToMechatronics.com
 Libraries:
 DS3231 - http://www.rinkydinkelectronics.com/library.php?id=73
 U8G2 - https://github.com/olikraus/u8g2
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <dht.h>
#include <DS3231.h>
#include <U8g2lib.h>
#include <Wire.h>

#define dataPin 8 // DHT22 sensor
dht DHT; // Creats a DHT object
DS3231  rtc(SDA, SCL);
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

RF24 radio(10, 9); // CE, CSN
const byte address[6] = "00001";

char text[6] = "";
int readDHT22, t, h;
String 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);
}Code language: Arduino (arduino)

说明: 另一方面,在室内机或接收器处,我们需要多包含两个库,一个用于 DS3231 实时时钟模块,一个用于 OLED 显示器,即 U8G2 库。和之前一样,我们需要为下面的程序定义实例、引脚和一些变量。同样在这里我们需要将温度和湿度图标定义为位图。

温度图标位图:

#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
};Code language: Arduino (arduino)

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

然后我们可以使用记事本打开这个文件,然后我们可以将位图复制到 Arduino 代码中。

注意,这里我们可以使用PROGMEM变量修饰符将位图定义为常量,这样位图将存储在闪存中而不是Arduino板的SRAM中。

static const unsigned char Temperature_20Icon_bits[] U8X8_PROGMEM // Save in the Flash memory 
static unsigned char Temperature_20Icon_bits[] // Save in the SRAM

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

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

然后我们使用 millis() 函数,以便以间隔变量定义的间隔在显示器上显示各种数据,我将其设置为 3 秒。我们使用millis() 函数是因为这样可以重复执行其余代码,而如果我们使用delay() 函数,程序会等待该时间段,因此我们可能会错过传入的数据从室外机。

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

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

这就是全部,我希望你喜欢这个 Arduino 项目并学到新的东西。欢迎在下方评论区提出任何问题。


制造工艺

  1. 基于树莓派的气象站
  2. Raspberry Pi 2 气象站
  3. Raspberry Pi 气象站
  4. Weather Station V 2.0
  5. 音频检测器
  6. 无线灯开关操纵器
  7. Tech-TicTacToe
  8. Arduino 倒数计时器
  9. $10 便携式 Arduino 气象站 (AWS)
  10. eDOT - 基于 Arduino 的精密时钟和气象站
  11. ThingSpeak Arduino 气象站
  12. 遥控保时捷汽车(Arduino 项目)