編集履歴一覧に戻る
Makato-kanのアイコン画像

Makato-kan が 2025年01月31日19時49分12秒 に編集

これで多分大丈夫かと思う

本文の変更

> #### 作った目的 家庭菜園で野菜を栽培しており、温湿度などを測定してトレンドを掴もうと思いましたが通信環境を整えるのに費用かかるため リアルタイムではなくても情報が取れれば良いのでなるべく省電力で測定できてデータを見ればどこで測定したのかわかれば良い(緯度経度があるので)と考えたロガーです。 > #### 試作と書いた理由 EEPROMからデータを読み出すのにイチゴジャムPCのLOADとLISTが使えればわざわざ読み出しプログムを作る必要ないと考えプログラムをつくっておりましたがどうしてもLISTコマンドで読み出す事が出来ずコンテストに間に合わなかったのですべてASCIIコードとして保存するバージョンになっております。 > #### 使い方 電池を接続するとすぐ起動します。 LED0が点灯している間は緯度経度情報取得中で取得完了すると消灯します 温湿度情報は3分毎に取得しI2CEEPROMに記録します。 外部から動作している事を確認する為30秒LED4点灯後2分30秒消灯を繰り返します。 EEPROMからデータの取り出しとASCIIコード化するプログラムは未作成でした。 > #### 保存データフォーマット

-

||||1|2|3|4|5|6|7|8| |---|---|---|---|---|---|---|---|---|---|---| |一行目|行番号|文字数|年|月|日|緯度|経度||行の終了|奇数調整 |一行目出力例|10|22|2025|1|22|XX.XX|YYY.YY||\n|

+

||||1|2|3|4|5|6|7| |---|---|---|---|---|---|---|---|---|---| |一行目|行番号|文字数|年|月|日|緯度|経度|偶数調整|行の終了| |一行目出力例|10|18|2025|1|22|XX.XX|YYY.YY|0|\n|

|二行目以降繰り返し|行番号|文字数|時|分|温度|湿度|気圧|地中温度|行の終了|

-

|二行目出力例|11|23|7|34|23.8|67|1004.2|10.5|0|\n|

+

|二行目出力例|11|19|7|34|23.8|67|1004.2|10.5|\n|

※すべてASCIIコードデータとして保存して、1行当たりのバイト数が偶数になるよう調整しています。 ※行の終了にLFをつけました >#### 出力例 ```arduino: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 ``` ```arduino: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(ボードマネージャーからインストール可能) >#### プログラム ヘッダーファイルと本体にわけております. ```arduino: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 ``` ```arduino: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はプルアップ抵抗付きの部品を使ったため特に考慮しておりません。 ![エクセルで書いた配線図です](https://camo.elchika.com/835b24e85c295d206940028fbc2d9fb21b366071/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f66373831653764372d303336352d343131662d613663362d3663623238333931346464342f63613763643830382d323131372d343161382d396330632d646637336438313065343966/) ![メイン基板と接続用基板](https://camo.elchika.com/4f86e976cc64205e741deb4ed6caf135c2d5c935/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f66373831653764372d303336352d343131662d613663362d3663623238333931346464342f62343336663564332d666136642d346361362d393161652d356230623731303261316131/) >#### ケース 温度湿度は容器に入れると温室効果で実際よりかなり高い値を示しますがグラフ化してトレンドを掴むには丁度よかったのです。 100均のタッパーを使い開けた穴はボンドで塞いであります。 ![接続した状態](https://camo.elchika.com/c8675c7eb3e1e9077589e6b340d17faabafd5d49/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f66373831653764372d303336352d343131662d613663362d3663623238333931346464342f30383938396530622d646438652d346561642d623662612d366162613835636230336531/)