Arduinoワイヤレスウェザーステーションプロジェクト
このチュートリアルでは、Arduinoベースのワイヤレス気象ステーションを作成する方法を学習します。次のビデオを見るか、以下のチュートリアルを読むことができます。
屋外の温度と湿度はDHT22センサーを使用して測定され、このデータはNRF24L01トランシーバーモジュールを使用して屋内ユニットにワイヤレスで送信されます。室内ユニットには、室内の温度と湿度を測定するための別のDHT22センサーと、Arduinoの電源が切れた場合でも時間を追跡できるDS3231リアルタイムクロックモジュールもあります。これらのデータはすべて、0.96インチのOLEDディスプレイに印刷されています。
回路図とこのプロジェクトがどのように機能するかを見てみましょう。これらの各モジュールがどのように機能するかについての詳細なチュートリアルがすでにあることに注意してください。詳細については、NRF24L01チュートリアル、DHT22チュートリアル、DS3231チュートリアルを確認できます。
このプロジェクトに必要なコンポーネントは、以下のリンクから入手できます。
リアルタイムクロックモジュールとOLEDディスプレイはどちらもArduinoとの通信にI2Cプロトコルを使用するため、ArduinoNanoボードのI2Cピンまたはアナログピン番号4と5に接続されます。 NRF24L01トランシーバモジュールのすぐ隣には、電源をより安定させるためのコンデンサがあります。センサーが正しく機能するように、DHT22データピンにプルアップ抵抗が接続されています。
電源は室内機に12VのDC電源アダプターを使用し、反対側は室外機に電源を供給するために約7.5Vのリチウムイオン電池を2本使用しました。この構成では、データを定期的に送信し、その間に消費電力がわずか約7mAのスリープモードにするため、室外機はバッテリーが放電する前に約10日間稼働する可能性があります。
電子部品を整理しておくために、回路図に従って、EasyEDAの無料オンライン回路設計ソフトウェアを使用してカスタムPCBを設計しました。屋内ユニットと屋外ユニットの両方に同じPCBを使用できることに注意してください。異なる方法でプログラムする必要があるのは、Arduinoボードのみです。
ここで設計が完了したら、PCBの製造に使用されるガーバーファイルをエクスポートするだけです。 Arduinoワイヤレス気象台のEasyEDAプロジェクトファイルはこちらで確認できます。
次に、実際にこのビデオのスポンサーであるJLCPCBにPCBを注文できます。
ここでは、ガーバーファイルをドラッグアンドドロップするだけで、アップロードしたら、ガーバービューアでPCBを確認できます。すべてが順調であれば、先に進み、PCBに必要なプロパティを選択してから、PCBをリーズナブルな価格で注文できます。 JLCPCBからの最初の注文の場合、わずか2ドルで最大10個のPCBを入手できることに注意してください。
それにもかかわらず、数日後、PCBが到着しました。 PCBの品質は素晴らしく、すべてが設計とまったく同じです。
私は、ピンヘッダーをPCBにはんだ付けすることにより、このプロジェクトの電子部品の組み立てを開始しました。このようにして、必要に応じてコンポーネントを簡単に接続および切断できます。
次に、コンデンサとプルアップ抵抗も挿入してはんだ付けしました。この手順が完了すると、コンポーネントをPCBのピンヘッダーに簡単に取り付けることができます。
次に、プロジェクトのケースを作成しました。そのために、8mmティックのMDFボードを使用し、丸鋸を使用して、すべてのピースをサイズに合わせてカットしました。
正確な温度と湿度を測定するには、ケースの側面から空気がケースに入ることができるようにする必要があります。そこで、ドリルとラスプを使用して、屋内ユニットと屋外ユニットの両方のサイドパネルにいくつかのスロットを作成しました。
また、フロントパネルにOLEDディスプレイ用のスロットを作成し、アルミニウムの小片をサイズにカットして、後でフロントパネルに装飾として取り付けます。
ケースの組み立てには、木工用ボンドといくつかのクランプ、およびいくつかのネジを使用しました。
ケースはスプレーペイントで塗装しました。室外機は白、室内機は黒を使用しました。塗料が乾いたら、PCBをケースに挿入するだけです。
室内機の裏側には電源ジャックと電源スイッチを挿入し、室外機では電源スイッチとしてシンプルなジャンパー線を使用しました。
これで、Arduinoワイヤレスウェザーステーションは機能していますが、このビデオに残っているのは、プログラムがどのように機能するかを確認することです。
Arduinoウェザーステーション屋外ユニットコード:
説明: 屋外ユニットは無線通信の送信機であるため、ここではまず、RF24ライブラリ、DHTライブラリ、およびArduinoをスリープモードにするために使用されるLowPowerライブラリを含める必要があります。
インスタンス、モジュールが接続されているピン、およびいくつかの変数を定義した後、セットアップセクションで、ワイヤレス通信アドレスを初期化する必要があります。次に、ループセクションで、最初にDHT22センサーからデータを読み取ります。つまり、温度と湿度です。最初はこれらの値は整数で区切られているので、単一の文字列変数に変換して文字配列に入れ、radio.write()関数を使用してこのデータを室内ユニットに送信しました。 forループを使用して、データを3回送信します。これは、送信時にコントローラーがビジー状態の場合に受信者がデータを確実に取得できるようにするためです。
最後に、消費電力を最小限に抑えるために、Arduinoを特定の期間スリープモードにしました。
Arduinoウェザーステーション屋内ユニットコード:
説明: 一方、室内ユニットまたはレシーバーには、さらに2つのライブラリを含める必要があります。1つはDS3231リアルタイムクロックモジュール用で、もう1つはOLEDディスプレイ用のU8G2ライブラリです。以前と同じように、以下のプログラムに必要なインスタンス、ピン、およびいくつかの変数を定義する必要があります。また、ここでは、温度と湿度のアイコンをビットマップとして定義する必要があります。
温度アイコンビットマップ:
この目的のために、オープンソースの画像エディタであるGIMPを使用できます。このエディタを使用して、何でも描画し、それをビットマップ(.xbm)としてエクスポートできます。
次に、メモ帳を使用してこのファイルを開き、そこからビットマップをArduinoコードにコピーできます。
ここでは、PROGMEM変数修飾子を使用してビットマップを定数として定義できます。これにより、ビットマップはArduinoボードのSRAMではなくフラッシュメモリに保存されます。
セットアップセクションでは、ワイヤレス通信を初期化するだけでなく、OLEDディスプレイとリアルタイムクロックモジュールを初期化する必要があります。
次に、ループセクションで、NRF24L01モジュールを介して読み取ることができる着信データがあるかどうかを常にチェックします。 trueの場合、radio.read()関数を使用してそれを読み取り、最初の2文字を温度文字列変数に格納し、次の2文字を湿度文字列変数に格納します。
次に、millis()関数を使用して、3秒に設定したinterval変数で定義された間隔でさまざまなデータをディスプレイに表示します。このようにして残りのコードを繰り返し実行できるため、millis()関数を使用していますが、delay()関数を使用する場合、プログラムはその期間待機するため、受信データを見逃す可能性があります。室外機から。
次に、U8G2ライブラリのfirstPage()およびnextPage()関数を使用して、カスタム関数で定義された5つの異なる画面を印刷します。
drawDate()カスタム関数は、リアルタイムクロックモジュールから日付と時刻の情報を取得し、それをディスプレイに適切に出力します。 drawInTemperature()関数は、室内の温度を読み取り、それをディスプレイに適切に印刷します。実際、同じ方法がディスプレイ上のすべての画面の印刷に使用されます。
以上で、この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)/*
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)#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)static const unsigned char Temperature_20Icon_bits[] U8X8_PROGMEM // Save in the Flash memory
static unsigned char Temperature_20Icon_bits[] // Save in the SRAM
製造プロセス