水温計ソース

// 文字列変換用バッファー
#define STR_HENKAN_BUFF 50
// I2Cライブラリ
#include <Wire.h>
//時間処理用
// DS3231タイムモジュール使用時 true 不使用時 false
#define DS_3231 true
#define DS_3231_ONDO true
//************************* DS_3231温度取得時
#include <DS3231.h>
DS3231 clock;
RTCDateTime tm;
#define TMPTYOUSEI2 0 // 温度微調整
//*******************
// 時間設定時 true 通常使用は false に戻してコンパイルし直す
// パソコンに同期できないときtrueのままだと
// 同期出来た時の以前の時間に初期化される
#define TIMESETTEI false
//***********************
#define TIMETYOUSEI 0 // 時間微調整
//********************
// SDカード設定
#include <SD.h>
#include <SPI.h>
#define SD_SS 3 // SD使用ソケット番号
//*************
File myFile;
//filename
#define FILENAME "ondo" // 保存ファイル名 ondo1.csv の様になる
//***********************
#define FILENAME_SUU 6 //filename の長さ設定
#define FILEMAX 131072 //1024*128 100Kバイト以下で保存
//********************
//ディスプレイ用
//LIQUIDCRYSTAL_I2C 使用時 true LIQUIDCRYSTAL 使用時 false
#define LIQUIDCRYSTALI2C true
//****************************
// ディスプレイ アドレス・表示幅・桁
#define LCD_ADDRESS 0x3f
#define LCDSIZE_YOKO 16 // 16 or 20
#define LCDSIZE_TATE 2 // 2 or 4
//*******************
#if LIQUIDCRYSTALI2C==true // I2C シリアルボード使用
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(LCD_ADDRESS,LCDSIZE_YOKO,LCDSIZE_TATE);
#define printIIC(args) Wire.write(args)
inline size_t LiquidCrystal_I2C::write(uint8_t value) {
send(value, Rs);
return 1;
}
#else // LiquidCrystal使用
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
//***********************************
#endif
//温度・湿度用
#include <OneWire.h>
#include <DallasTemperature.h>
//温度モジュル接続ピン
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
#define ONDOKEI_SUU 1 // DS18B20 温度計の数
//******************************
float ondo1[ONDOKEI_SUU+1]={-126.90}; //温度記録用変数 DS18B20用
float tmp_tyousei[ONDOKEI_SUU+1]={0,0}; // 温度微調整
//*********************************
// DS18B20センサーモジュール 分解能セット
//0.5℃、0.25℃、0.125℃、0.0625℃に対応して、9、10、11、12ビットを選択す
#define SENSER_BIT 12 //9~12 数字が大きいほど高精度 但し 時間がかかる
//********************
DeviceAddress ondokei1[ONDOKEI_SUU]; // 温度計アドレス DS18B20用
//***************************************
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
void setup() {
// Serial.begin(115200); //ディバッグ時 コメントアウトを外す
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
clock.begin();
//時間設定ONの時のみ パソコンと同期 時間初期設定
time_settei(TIMESETTEI);
//LCD初期設定
#if LIQUIDCRYSTALI2C==true // I2C シリアルボード使用
lcd.init();
lcd.backlight();
#else // LiquidCrystal使用
lcd.begin(LCDSIZE);
#endif
// SDセットアップ
sdsetup();
// DS18B20センサーモジュール温度計 アドレスセット
int i;
for(i=0;i<ONDOKEI_SUU;++i){
sensors.getAddress(ondokei1[i],i);
}
// DS18B20センサーモジュール 分解能セット
sensors.setResolution(SENSER_BIT);
}
void loop() {
//ディスプレイ表示
//日付・時間
time_dsp_hyouji();
//温度
ondo_syutoku();
// データの保存
data_hozon();
}
// ディスプレイへの日・時の表示
void time_dsp_hyouji(){
//時間の取得
tm = clock.getDateTime();
int yoko=1;
int haba=9;
String hyouji1;
// 日時の表示開始
if(LCDSIZE_YOKO >= 20 || ONDOKEI_SUU<=1){
hyouji(0, 0,1, "x27");
hyouji1 = String(tm.year - 2000) + "/";
}else{
hyouji1 = "";
haba=5;
yoko=0;
}
hyouji1 += String(tm.month) + "/" + String(tm.day);
string_hyouji(yoko, 0, haba, hyouji1);
if (tm.hour < 10) {
hyouji(0, 1, 1, " ");
ketahyouji(1, 1, 1, tm.hour);
} else {
ketahyouji(0,1, 2, tm.hour);
}
hyouji(2, 1, 1, ":");
ketahyouji(3, 1, 2, tm.minute);
if(LCDSIZE_YOKO >= 20 || ONDOKEI_SUU<=1){
hyouji(5, 1, 1, ":");
ketahyouji(6, 1, 2, tm.second);
}
}
// 温度取得 → 表示
void ondo_syutoku(){
int ondohyouji_suu = ONDOKEI_SUU; //温度表示の総数 DS_3231を含む
// DS3231内蔵温度計
clock.forceConversion();
if(DS_3231_ONDO){
ondo1[0] =clock.readTemperature() + TMPTYOUSEI2 ; // call sensors.requestTemperatures() to issue a global temperature
//温度微調整
tmp_tyousei[0] = TMPTYOUSEI2 ;
ondohyouji_suu +=1;
}
// DS18B20センサーモジュール温度計
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
sensors.requestTemperatures(); // Send the command to get temperatures
int i;
for(i=0;i<ondohyouji_suu;++i){
if(DS_3231_ONDO){
ondo1[i+1] =sensors.getTempCByIndex(i) + tmp_tyousei[i+1] ; // call sensors.requestTemperatures() to issue a global temperature
//温度微調整
}else{
ondo1[i] =sensors.getTempCByIndex(i) + tmp_tyousei[i] ; // call sensors.requestTemperatures() to issue a global temperature
//温度微調整
}
}
ondo_dsp_hyouji(ondohyouji_suu);
}
// ディスプレイへの温度表示
void ondo_dsp_hyouji(int ondohyouji_suu){
int yoko=10;
if(LCDSIZE_YOKO < 20 && ondohyouji_suu>LCDSIZE_TATE){
yoko=6;
}
int i;
char *no;
int len;
int tate;
for(i=LCDSIZE_TATE;i<ondohyouji_suu;++i){ // 2ページ目以降から表示
no=str_to_char(String(i+1)+String(":"));
len=strlen(no);
tate= i % LCDSIZE_TATE;
hyouji(yoko,tate ,len,no);
if( ondo1[i]>-125+ tmp_tyousei[i]){
ondo1[i]=ondo_hyouji(yoko+len, tate , ondo1[i]);
}else{
hyouji(yoko+len,tate ,LCDSIZE_YOKO-yoko-len,"");
}
if( tate==LCDSIZE_TATE-1){
delay(2500);
}
}
if( tate!=LCDSIZE_TATE-1 && LCDSIZE_TATE < ondohyouji_suu){ // ページ余白の消去
for(tate=tate+1;tate<LCDSIZE_TATE;++tate){
hyouji(yoko,tate ,LCDSIZE_YOKO-yoko,"");
}
delay(2500);
}
for(i=0;i<LCDSIZE_TATE && i< ondohyouji_suu ;++i){ // 1ページ目
if(LCDSIZE_YOKO < 20 && ondohyouji_suu<=2){
len=0;
}else{
no=str_to_char(String(i+1)+String(":"));
len=strlen(no);
hyouji(yoko,i ,len,no);
}
if( ondo1[i]>-125+ tmp_tyousei[i]){
ondo1[i]=ondo_hyouji(yoko+len, i , ondo1[i]);
}else{
hyouji(yoko+len,i ,LCDSIZE_YOKO-yoko-len,"");
}
}
if( i<LCDSIZE_TATE){ // ページ余白の消去
for(i;i<LCDSIZE_TATE;++i){
hyouji(yoko,i ,LCDSIZE_YOKO-yoko,"");
}
}
if( LCDSIZE_TATE<ondohyouji_suu){
delay(2500);
}
}
// データの保存
void data_hozon(){
static int h;
char *file_tmp;
char file[FILENAME_SUU+5];
if (h != tm.hour){
h = tm.hour;
file_tmp=filename();
strcpy(file,file_tmp);
bool ari=isfile(file);
// open a file
myFile = SD.open(file, FILE_WRITE);
if(myFile){
int kaisuu=ONDOKEI_SUU;
if(DS_3231 ){
kaisuu += 1;
}
if(ari==0){
myFile.print(""ネン","ツキ","ヒ","ジ","フン","ビョウ"");
int i=0;
String str_s;
char *str_henkan;
for(i=0;i<kaisuu;++i){
str_s=String(","オンド")+String(i+1)+String(""");
str_henkan=str_to_char(str_s);
myFile.print(str_henkan);
}
myFile.println("");
}
myFile.print(tm.year);
myFile.print(",");
myFile.print(tm.month);
myFile.print(",");
myFile.print(tm.day);
myFile.print(",");
myFile.print(tm.hour);
myFile.print(",");
myFile.print(tm.minute);
myFile.print(",");
myFile.print(tm.second);
int i=0;
for(i=0;i<kaisuu;++i){
myFile.print(",");
if(ondo1[i]>-125+ tmp_tyousei[i]){
myFile.print(ondo1[i]);
}
}
myFile.println("");
hyouji(0, 1 , 16,"カキコミシュウリョウ");
}else{
hyouji(0, 1 , 16,"ファイルオープンエラー");
}
myFile.close();
delay(1000);
hyouji(0, 1, 16, "@ ");
}
}
//液晶表示用関数 char
void hyouji(int yoko, int tate, int haba, char *text) {
utf_del_uni(text);
//文字化け防止のため1字ずつ表示
int i = 0;
int j = 0;
while (text[i] != ” && i<haba ) {
lcd.setCursor(yoko + i, tate);
lcd.print(text[i]);
i++;
}
while (i < haba) {
lcd.setCursor(yoko + i, tate);
lcd.print(‘ ’);
i++;
}
}
// UTF-8 to ASCIIコード変換
void utf_del_uni(char *s) {
byte i = 0;
byte j = 0;
while (s[i] != ”) {
if ((byte)s[i] == 0xEF) {
if ((byte)s[i + 1] == 0xBE) s[i + 2] += 0x40;
i += 2;
}
s[j] = s[i];
i++;
j++;
}
s[j] = ”;
}
//stringの表示
char *string_hyouji(int yoko, int tate, int haba, String hyouji1) {
//最後に文字を入れておかないと数字の最後が表示されない
hyouji1 = hyouji1 + ’ ’;
int len = hyouji1.length()-1; // 文字列長さ
hyouji1[len]=”;
char *str_henkan;
str_henkan=str_to_char(hyouji1);
hyouji(yoko, tate, haba,str_henkan);
//短いときに旧表示を消去
return(str_henkan);
}
//string to char[]変換
char *str_to_char(String text1){
static char str_henkan[STR_HENKAN_BUFF];
int len = text1.length(); // 文字列長さ
text1.toCharArray(str_henkan, len + 1);
return str_henkan;
}
// 数字桁合わせ表示 01 など
char * ketahyouji(int yoko, int tate, int haba, int suu) {
String hyouji1 = String(suu);
int len = hyouji1.length(); // 文字列長さ
int i = 0;
while (i + len < haba) {
hyouji1 = "0" + hyouji1;
++i;
}
char *str_henkan;
str_henkan=str_to_char(hyouji1);
hyouji(yoko, tate, haba, str_henkan);
return(str_henkan);
}
//温度 0.1℃表示
float ondo_hyouji(int yoko, int tate, float t) {
// 小数第1位までで四捨五入する
t = round1(t,-1);
String hyouji1 = String(t);
char *str_henkan;
str_henkan=str_to_char(hyouji1);
int len = hyouji1.length(); // 文字列長さ
*(str_henkan+len-1)=’xDF’;
*(str_henkan+len)=’C’;
*(str_henkan+len+1)=”;
hyouji(yoko, tate,LCDSIZE_YOKO-yoko, str_henkan);
return(t);
}
/*四捨五入(10のn乗の位を処理)*/
float round1(float d, int n){
double dst;
d = d * pow(10, -n ); /*処理を行う桁を10-1 の位にする*/
if(d>=0){
dst = (double)(int)(d + 0.5);
}else{ // マイナスの時は絶対値にマイナスを付ける
dst = (double)(int)(d - 0.5);
}
return dst * pow(10, n ); /*処理を行った桁を元に戻す*/
}
//時間取得関数
//時間設定ONの時のみ パソコンと同期 時間初期設定
// get the date and time the compiler was run
void time_settei(bool settei1){
//時計初期設定
static bool timefirst=true; //初回呼び出し時のみ実行
if (settei1 && timefirst) {
clock.setDateTime(__DATE__, __TIME__);
tm = clock.getDateTime();
//時計時間微調整
if (tm.second + TIMETYOUSEI >= 60) {
tm.second = tm.second + TIMETYOUSEI - 60;
tm.minute += 1;
} else {
tm.second = tm.second + TIMETYOUSEI;
}
// and configure the RTC with this info
clock.setDateTime(tm.year,tm.month, tm.day,tm.hour,tm.minute, tm.second);
}
timefirst=false;
return;
}
// ファイル関係関数
// SDセットアップ
void sdsetup(){
if (!SD.begin(SD_SS)) {
hyouji(0, 0, 16, "SDinitialization");
hyouji(0, 1, 16, " failed!");
delay(5000);
return;
}
}
// file有り無し
bool isfile(char *text){
if (SD.exists(text)) {
return 1;
} else {
return 0;
}
}
//保存filename決定
char *filename(){
String filename_s;
static char filename1[FILENAME_SUU+4]="";
static int i=1;
uint32_t filesize=FILEMAX; // FILEMAXバイト以下で保存
int isfile=0;
char *filename_c;
while(isfile==0 && filesize>=FILEMAX){ // FILEMAXバイト以下で保存
filename_s=String(FILENAME)+String(i)+String(".csv");
filename_c=str_to_char(filename_s);
strcpy(filename1,filename_c);
myFile=SD.open(filename1,FILE_READ);
if(myFile){
filesize=myFile.size();
isfile=0;
}else{
isfile=1;
}
myFile.close();
++i;
}
–i;
return filename1;
}