Makato-kanのアイコン画像
Makato-kan 2025年01月29日作成 (2025年01月31日更新)
製作品 製作品 閲覧数 85
Makato-kan 2025年01月29日作成 (2025年01月31日更新) 製作品 製作品 閲覧数 85

試作 家庭菜園で使う温湿度ロガー

試作 家庭菜園で使う温湿度ロガー

作った目的

家庭菜園で野菜を栽培しており、温湿度などを測定してトレンドを掴もうと思いましたが通信環境を整えるのに費用かかるため リアルタイムではなくても情報が取れれば良いので、なるべく省電力で測定できてデータを見ればどこで測定したのかわかれば良い(緯度経度があるので)と考えたロガーです。

試作と書いた理由

EEPROMからデータを読み出すのにイチゴジャムPCのLOADとLISTが使えればわざわざ読み出しプログムを作る必要ないと考えプログラムをつくっておりましたがどうしてもLISTコマンドで読み出す事が出来ずコンテストに間に合わなかったのですべてASCIIコードとして保存するバージョンになっております。

使い方

電池を接続するとすぐ起動します。
LED0が点灯している間は緯度経度情報取得中で取得完了すると消灯します
温湿度情報は3分毎に取得しI2CEEPROMに記録します。
外部から動作している事を確認する為30秒LED4点灯後2分30秒消灯を繰り返します。

EEPROMからデータの取り出しとASCIIコード化するプログラムは未作成でした。

保存データフォーマット

1 2 3 4 5 6 7
一行目 行番号 文字数 緯度 経度 偶数調整 行の終了
一行目出力例 10 18 2025 1 22 XX.XX YYY.YY 0 \n
二行目以降繰り返し 行番号 文字数 温度 湿度 気圧 地中温度 行の終了
二行目出力例 11 19 7 34 23.8 67 1004.2 10.5 \n

※すべてASCIIコードデータとして保存して、1行当たりのバイト数が偶数になるよう調整しています。
※行の終了にLFをつけました

出力例

HEXコード

31 30 2C 32 33 2C 32 30 32 35 2C 31 2C 32 34 2C 58 58 2E 58 58 2C 59 59 59 2C 59 59 30 0A 0A 31 31 2C 32 34 3A 38 3A 39 2C 31 39 2E 31 2C 35 36 2C 31 30 31 36 2E 32 2C 31 37 2E 31 0A

ASCII変換後

10,23,2025,1,24,XX.XX,YYY,YY0 11,24:8:9,19.1,56,1016.2,17.1

DS18B20について

arduinoide付属のOneWireではスプレッセンス側の対応が一部無いらしく正常動作しません URL:https://note.com/regnant_saya/n/n2560adf75690 に記述ございました。
この記事にあったライブラリを使わせていただいております。
尚このライブラリはオリジナルのOneire.hと入れ替えて使うようになっていますのでおりますのでオリジナルも必要な場合はあらかじめコピーとるとか別な名前で使えるようにするとかの工夫必要です

使用したプログラムとライブラリ

URL:https://www.arduino.cc/en/software ArduinoIDE
URL:https://github.com/finitespace/BME280 BME280(ボードマネージャーからインストール可能)
URL:https://github.com/saya-mitsuwa/spresense_onewire DS18B20 spresense_onewire(説明文読んで使うイメージです)
URL:https://github.com/RobTillaart/I2C_24LC1025 I2CEEPROM(ボードマネージャーからインストール可能)

プログラム

ヘッダーファイルと本体にわけております.

GNSS_DS18B20_BME280.h

#include <RTC.h> #include <GNSS.h> #define MY_TIMEZONE_IN_SECONDS (9 * 60 * 60) // JST SpGnss Gnss; float latitude1(NAN),longitude1(NAN); int test_lati(0),check_data(0),year_check(0); String time1(""),time2(""); #include <BME280I2C.h> BME280I2C bme; float temp(NAN), hum(NAN), pres(NAN); String temp2(""); //温度・湿度・気圧 #include <OneWire2.h> int DS18S20_Pin(22); //ピンNo変えるときはOneWire2のライブラリも書き換える OneWire ds(DS18S20_Pin); // on digital pin 22 #include <Wire.h>//BME280 and I2CEEPROM #include "I2C_24LC1025.h" I2C_24LC1025 ee(0x50); int offset_w = 0; //EEPROMに書き込むとき用のオフセット int offset1(0),count1(10),wordlength1(0); String data1(""),datatotal1(""); int offset2(0),count2(0),wordlength2(0); String data2(""),datatotal2(""); #define SERIAL_BAUD 9600

program_main.ino

#include "GNSS_DS18B20_BME280.h" //GNSS void printClock(RtcTime &rtc){ time1 = String(rtc.year())+","+String(rtc.month())+","+String(rtc.day()); time2 = String(rtc.hour())+":"+String(rtc.minute()); year_check = rtc.year(); } void updateClock(){ static RtcTime old; RtcTime now = RTC.getTime(); if (now != old){ printClock(now); old = now; } } void printBME280Data(Stream* client){ BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); BME280::PresUnit presUnit(BME280::PresUnit_Pa); bme.read(pres, temp, hum, tempUnit, presUnit); temp2 = String(temp,1)+","+String(hum,0)+","+String(pres/100,1); delay(10); } float getTemp(){ delay(50); //returns the temperature from one DS18S20 in DEG Celsius byte data[12]; byte addr[8]; if ( !ds.search(addr)){ //no more sensors on chain, reset search ds.reset_search(); return -1000; } if ( OneWire::crc8( addr, 7) != addr[7]){ Serial.println("CRC is not valid!"); return -1000; } if ( addr[0] != 0x10 && addr[0] != 0x28){ Serial.print("Device is not recognized"); return -1000; } delay(50); ds.reset(); ds.select(addr); ds.write(0x44,1); // start conversion, with parasite power on at the end byte present = ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad for (int i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read(); } ds.reset_search(); byte MSB = data[1]; byte LSB = data[0]; float tempRead = ((MSB << 8) | LSB); //using two's compliment float TemperatureSum = tempRead / 16; return TemperatureSum; } void setup(){ pinMode(LED0, OUTPUT); pinMode(LED1, OUTPUT); pinMode(LED2, OUTPUT); pinMode(LED3, OUTPUT); Serial.begin(SERIAL_BAUD); while (!Serial); Wire.begin(); if (! ee.begin()) { Serial.println("EEPROM not found..."); while (1); } RTC.begin(); int ret; ret = Gnss.begin(); assert(ret == 0); ret = Gnss.start(); assert(ret == 0); while(!bme.begin()) { Serial.println("Could not find BME280 sensor!"); delay(1000); } if (Gnss.waitUpdate()){ SpNavData NavData; // Get the UTC time Gnss.getNavData(&NavData); SpGnssTime *time = &NavData.time; // Check if the acquired UTC time is accurate if (time->year >= 2000) { RtcTime now = RTC.getTime(); // Convert SpGnssTime to RtcTime RtcTime gps(time->year, time->month, time->day, time->hour, time->minute, time->sec, time->usec * 1000); #ifdef MY_TIMEZONE_IN_SECONDS // Set the time difference gps += MY_TIMEZONE_IN_SECONDS; #endif int diff = now - gps; if (abs(diff) >= 1) { RTC.setTime(gps); } } } SpNavData NavData; while(check_data == 0){ if (Gnss.waitUpdate()) { SpNavData NavData; Gnss.getNavData(&NavData); SpGnssTime *time = &NavData.time; if (time->year >= 2000) { RtcTime now = RTC.getTime(); RtcTime gps(time->year, time->month, time->day, time->hour, time->minute, time->sec, time->usec * 1000); #ifdef MY_TIMEZONE_IN_SECONDS gps += MY_TIMEZONE_IN_SECONDS; #endif int diff = now - gps; if (abs(diff) >= 1) { RTC.setTime(gps); } } } updateClock(); Gnss.waitUpdate(); delay(10); Gnss.getNavData(&NavData); digitalWrite(LED0,HIGH); delay(10); latitude1 = (NavData.latitude); longitude1 = (NavData.longitude); delay(10); test_lati = (NavData.latitude); if(test_lati >0){ check_data = 1; } } updateClock(); data1 = String(time1)+","+String(latitude1)+","+String(longitude1); wordlength1 = data1.length(); if(wordlength1 %2 == 0){ datatotal1 = String(count1)+","+String(wordlength1)+","+String(data1)+String(0)+String("\n"); Serial.println(String(datatotal1)+" EVEN "+String(datatotal1.length())); byte buffer_1[datatotal1.length() + 1]; datatotal1.getBytes(buffer_1, datatotal1.length() + 1); offset_w = offset1 ; delay(10); ee.writeBlock(offset_w, (uint8_t*) buffer_1, datatotal1.length()); delay(10); }else{ datatotal1 = String(count1)+","+String(wordlength1)+","+String(data1)+String("\n"); Serial.println(String(datatotal1)+" ODD "+String(datatotal1.length())); byte buffer_1[datatotal1.length() + 1]; datatotal1.getBytes(buffer_1, datatotal1.length() + 1); offset_w = offset1 ; delay(10); ee.writeBlock(offset_w, (uint8_t*) buffer_1, datatotal1.length()); delay(10); } digitalWrite(LED0,LOW); getTemp(); } void loop(){ float temperature = getTemp(); printBME280Data(&Serial); delay(10); if(offset2 == 0){offset2 = datatotal1.length();}else{offset2 = offset2;} delay(5); if(count2 == 0){count2 = count1+1;}else{ count2 = count2;} delay(5); updateClock(); data2 = String(time2)+","+String(temp2)+","+String(temperature,1); wordlength2 = data2.length(); if(wordlength2 %2 == 0){ datatotal2 = String(count2)+","+String(wordlength2)+","+String(data2)+String(0)+String("\n"); byte buffer_2[datatotal2.length() + 1]; datatotal2.getBytes(buffer_2, datatotal2.length()+1); offset_w = offset2 ; ee.writeBlock(offset_w, (uint8_t*) buffer_2, datatotal2.length()); delay(10); Serial.println(String(datatotal2)+" EVEN "+datatotal2.length()); count2++; offset2 = offset2 + datatotal2.length(); }else{ datatotal2 = String(count2)+","+String(wordlength2)+","+String(data2)+String("\n"); byte buffer_2[datatotal2.length() + 1]; datatotal2.getBytes(buffer_2, datatotal2.length()+1); offset_w = offset2 ; ee.writeBlock(offset_w, (uint8_t*) buffer_2, datatotal2.length()); delay(10); Serial.println(String(datatotal2)+" ODD "+datatotal2.length()); count2++; offset2 = offset2 + datatotal2.length(); } delay(10); digitalWrite(LED3,HIGH); delay(30000); digitalWrite(LED3,LOW); delay(150000); }

部品表

品名 概要
1 BME280 3.3V用を購入したが1.8Vで動作しました
2 DS18B20 3V動作の為レベルコンバータ使いました
3 いちごジャムPC用EEPROM お値段手ごろの為
4 ピンヘッダーや配線材料 ぁユニバーサル基板も使いました
5 レベルコンバータ DS18B20用です

※レベルコンバーターは4回路用のうち一回路を使っています。

回路図

スプレセンスメインボードから 1.8V,3.3V,DS18B20用D22,SDL,SCR,GNDを使い、配線しています。
センサーやEEPROMはプルアップ抵抗付きの部品を使ったため特に考慮しておりません。
エクセルで書いた配線図です
メイン基板と接続用基板

ケース

温度湿度は容器に入れると温室効果で実際よりかなり高い値を示しますがグラフ化してトレンドを掴むには丁度よかったのです。
100均のタッパーを使い開けた穴はボンドで塞いであります。
接続した状態

Makato-kanのアイコン画像
屋外で温度湿度を測定し記録するので、壊れやすいと思い大量にDHT11とESP-WROOM-02を購入したのですが思いのほか壊れなかったので、何にでもDHT11をくっつけています。
  • Makato-kan さんが 2025/01/29 に 編集 をしました。 (メッセージ: 初版)
  • Makato-kan さんが 2025/01/31 に 編集 をしました。 (メッセージ: 1バイト書き込み忘れを直しました)
  • Makato-kan さんが 2025/01/31 に 編集 をしました。 (メッセージ: 行末をLFにするよう変更しました)
  • Makato-kan さんが 2025/01/31 に 編集 をしました。 (メッセージ: これで多分大丈夫かと思う)
  • Makato-kan さんが 2025/01/31 に 編集 をしました。 (メッセージ: ダメ直し)
ログインしてコメントを投稿する