![ed3c03f68141b0c282ba62cc45833c38.png](https://i-blog.csdnimg.cn/blog_migrate/59e9d40747c7eda6449cfbf47a13d689.png)
今天我们来介绍如何利用DHT22传感器测量室外温度和湿度,并使用NRF24L01收发器模块将该数据无线发送到室内单元。在室内单元中,还有一个用于测量室内温度和湿度的DHT22传感器,以及一个DS3231实时时钟模块,即使Arduino断电,该模块也可以跟踪时间。所有这些数据都打印在0.96英寸OLED显示器上。
Arduino无线气象站电路图
让我们看一下电路图以及该项目的工作方式。
实时时钟模块和OLED显示屏均使用I2C协议与Arduino通信,因此它们都连接到Arduino Nano板上的I2C引脚或4和5的模拟引脚。NRF24L01收发器模块旁边有一个电容器,以保持其电源稳定。DHT22数据引脚上还连接了一个上拉电阻,以使传感器正常工作。
至于电源,我们为室内机配置了12V直流电源适配器,另一方面,为室外机供电时,使用了两节可产生约7.5V电压的锂电池。通过这种配置,室外机可以在电池放电之前运行约10天,因为我们会定期传输数据,与此同时,我们将Arduino置于睡眠模式,此时功耗仅为7mA左右。
接着我们设计好PCB 并印出来
好了,我们现在开始通过将引脚头焊接到PCB上来组装该项目的电子组件。这样,可以在需要时轻松地连接和断开组件。
然后,我们还插入并焊接了电容器和上拉电阻。完成此步骤后,现在我们可以简单地将组件连接到PCB的排针上。
接下来,我们选用8mm刻度MDF板,利用圆锯将所有部件切成事先定好的尺寸。
为了进行准确的温度和湿度测量,箱子的侧面必须允许空气进入箱子。因此,需要用钻子和粗锉刀在室内机和室外机的侧板上都开几个槽。
我们还在前面板上为OLED显示屏制作了一个插槽,并切成一小块铝,将其尺寸固定,然后将其作为装饰贴在前面板上。
为了组装箱子,使用了木胶和一些夹子,以及一些螺丝。自己动手时能组个木箱出来就好了,材料倒没什么特别的限制。
为了更加的美观,我们用喷漆为箱子涂了油漆我在室外机上使用了白色涂料,在室内机上使用黑色涂料。油漆变干后,我们只需将PCB插入外壳即可。
我们在室内机的背面插入了电源插孔和电源开关,在室外机上,使用了一根简单的跳线作为电源开关
这下我们的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
#include
#include
#include
#include
#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);
}
}
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
#include
#include
#include
#include
#include
#include
#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);
}
关注风火轮,技术之路常相伴,我们下期见!