// // リアルタイムRTC8564BNのテストRTC8564 // 動作:RTCの値をI2Cで読んで、液晶とシリアルに流す // 接続:RTCの /INT 信号を digitalの6PINに接続 // // 2012/10/8:時刻合わせ機能追加 #include #include #include #include #include File myFile; LiquidCrystal lcd(9, 8, 5, 4, 3, 2); // デフォルトから変更 12 ->9 11->8 // RTC関係の変数 char dtString[20]="yyyy/mm/dd hh:mm:ss"; // テンプレート用文字列で初期化 byte RtcADR = 0xA2 >> 1; // RTCのアドレス // 気圧計関係の変数 const int addresPsensor = 0x60; // 気圧計のI2Cアドレス float a0, b1, b2, c12, c11, c22; float Pha, Temp; int tempOffset, pressOffset; unsigned int Padc; unsigned int Tadc; float sumPadc; float sumTadc; float avPadc; float avTadc; int entB = 16; // EnterボタンのピンNo. 注;アナログピンをデジタルで使う時はA2とは書かない int selB = 17; // SelectボタンのピンNo. char fileName[11] = "yymmdd.csv"; // ファイル名 void setup() { unsigned int x; pinMode(6, INPUT); // RTCの /INT信号を接続 digitalWrite(6, HIGH); // オープンドレインなのでプルアップ pinMode(13, OUTPUT); // 動作表示LED pinMode(entB, INPUT); // ClockEnterボタン pinMode(selB, INPUT); // ClockSelectボタン digitalWrite(entB, HIGH); // プルアップ digitalWrite(selB, HIGH); // プルアップ Serial.begin(9600); lcd.begin(16, 2); Rtc.begin(); // RTCを開始 if(digitalRead(entB) == LOW){ // Enterボタンが押されていたら ClockSet(); // RTCの時刻を合わせる } lcd.clear(); SetRtcTimer(); // 定周期タイマーの設定 // SDカードの初期化 if (!SD.begin(10)) { Serial.println("SD initialization failed!"); lcd.print("SD failed. Halt!"); for(;;); // ここでHalt } Serial.println("SD initialization done."); lcd.print("SD ok!"); // 気圧計の初期設定 // EEPROM.write(1, 27); // 温度補正値書き込み // EEPROM.write(3, 75); // 気圧補正値 x = EEPROM.read(0); // EEROMから温度の補正値読み出し unit=0.1℃ x = x << 8; tempOffset = x; //上位8ビット x = EEPROM.read(1); tempOffset = tempOffset | x; // 下位8ビット x = EEPROM.read(2); // 気圧の補正値 x = x << 8; pressOffset = x; // 上位 x = EEPROM.read(3); pressOffset = pressOffset | x; // 下位 Serial.print(tempOffset); Serial.print(", "); Serial.println(pressOffset); byte doC[8] = { // 外字で℃を作る B00011, B00011, B01100, B10010, B10000, B10010, B01100, }; lcd.createChar(0, doC); delay(1000); // 気圧計が立ち上がるまで待つ Wire.beginTransmission(addresPsensor); Wire.write(0x04); // Read coefficient data Wire.endTransmission(); Wire.requestFrom(addresPsensor, 12); // Request 12 bytes if (Wire.available()) { a0 = read_coefficients(16, 3, 0); b1 = read_coefficients(16, 13, 0); b2 = read_coefficients(16, 14, 0); c12 = read_coefficients(14, 13, 9); c11 = read_coefficients(11, 10, 11); c22 = read_coefficients(11, 10, 15); } Serial.println("1000 * coefficient a0, b1, b2, c12, c11, c22 "); Serial.print(a0*1000); Serial.print(", "); Serial.print(b1*1000); Serial.print(", "); Serial.print(b2*1000); Serial.print(", "); Serial.print(c12*1000); Serial.print(", "); Serial.print(c11*1000); Serial.print(", "); Serial.println(c22*1000); Rtc.available(); // 時刻を取得 convString(); // RTCの時刻(BCD)を文字列に変換してdtStringに格納 fileName[0] = dtString[2]; // y ファイル名の決定 fileName[1] = dtString[3]; // y fileName[2] = dtString[5]; // m fileName[3] = dtString[6]; // m fileName[4] = dtString[8]; // d fileName[5] = dtString[9]; // d Serial.print("File Name = "); Serial.println(fileName); myFile = SD.open(fileName, FILE_WRITE); // setupで取得したファイル名を使用 myFile.println(); // 改行 myFile.print("Record Start. tempOffset="); myFile.print(tempOffset); myFile.print(" pressOffset="); myFile.println(pressOffset); myFile.close(); } void loop() { float sumP, sumT; long outP, outT; // 表示用データ int n; sumP = 0; sumT = 0; waitTimer(); // RTCの /INT信号を待つ for( n=0; n < 10; n++){ // 安定待ちのため10回ダミーリード sensData(); } sumPadc=0; sumTadc=0; for(n=0; n<100; n++){ // バラツキが大きいので100回アベレージング sensData(); sumP = sumP + Pha; sumT = sumT + Temp; sumPadc = sumPadc + Padc; sumTadc = sumTadc + Tadc; } outT = int(sumT /10 + 0.5) + tempOffset; // 小数点以下1桁の値に丸める outP = int(sumP /10 + 0.5) + pressOffset; avPadc = sumPadc / 100; avTadc = sumTadc / 100; Rtc.available(); // 時刻を取得 convString(); // RTCの時刻(BCD)を文字列に変換してdtStringに格納 Serial.print(dtString); // シリアルに書き出し Serial.print(", "); Serial.print(outT); Serial.print(", "); Serial.println(outP); //  SDカードに書き込み // if(dtString[18] == '0' ) { // 10秒毎に記録 if( ( (dtString[15] == '0') | (dtString[15] =='5') ) & (dtString[17] == '0') & (dtString[18] == '0') ) { // 5分00秒か0分00秒に記録 myFile = SD.open(fileName, FILE_WRITE); // setupで取得したファイル名を使用 myFile.print(dtString); myFile.print(", "); myFile.print(outT / 10); // 小数点以上の値 myFile.print("."); myFile.print(outT % 10); // 10で割った余り myFile.print(", "); myFile.print(outP/10); // 小数点以上の値 myFile.print("."); myFile.print(outP % 10); // 10で割った余り myFile.print(", "); myFile.print(avTadc,3); // 補正前の温度センサの値の100回平均値 myFile.print(", "); myFile.println(avPadc,3); // 補正前の圧力センサの値の100回平均値 myFile.close(); } lcd.setCursor(0, 0); // 液晶に書き出し 先頭に1文字ブランク lcd.print(" "); for( n=5; n <= 18; n++){ // 入りきらないので年は省略 lcd.print(dtString[n]); } lcd.setCursor(0 , 1); if(outT < 0){ lcd.print("-"); } else { lcd.print(" "); } if(abs(outT)<100){ lcd.print(" "); } lcd.print(outT/10); lcd.print("."); lcd.print(outT % 10); lcd.write(8); // 本当は0を指定すべき(後日修正要す) // lcd.print("C"); lcd.setCursor(7, 1); if(outP < 10000) { lcd.print(" "); } lcd.print(outP/10); lcd.print("."); lcd.print(outP % 10); lcd.print("hPa"); } // Loopの末尾 void convString(){ // RTCの2バイトのBCDを文字に変換し時刻の文字列を作る byte x; dtString[0]='2'; dtString[1]='0'; x = Rtc.years(); dtString[2] = upper2chr(x); dtString[3] = lower2chr(x); x = Rtc.months(); dtString[5] = upper2chr(x); dtString[6] = lower2chr(x); x = Rtc.days(); dtString[8] = upper2chr(x); dtString[9] = lower2chr(x); x = Rtc.hours(); dtString[11] = upper2chr(x); dtString[12] = lower2chr(x); x = Rtc.minutes(); dtString[14] = upper2chr(x); dtString[15] = lower2chr(x); x = Rtc.seconds(); dtString[17] = upper2chr(x); dtString[18] = lower2chr(x); } char upper2chr(byte x){ // 上位をAsciiコードに変換 return (x >> 4) + 0x30; } char lower2chr(byte x){ // 下位をAsciiコードに変換 return (x & 0x0f) + 0x30; } void waitTimer(){ // RTCの /INT信号を待つ while(digitalRead(6) == HIGH){ // HIGHなのでLOWになるまで待つ } while(digitalRead(6) == LOW){ // 再びHIGHになるまで待つ digitalWrite(13, HIGH); // LED ON } digitalWrite(13, LOW); // LED OFF } void SetRtcTimer(){ // 定周期タイマー割り込みの設定 Wire.beginTransmission(RtcADR); Wire.write(0x0e); // タイマー停止 Wire.write(0x00); Wire.endTransmission(); Wire.beginTransmission(RtcADR); Wire.write(0x01); // コントロールレジスタ-2の設定 Wire.write(0x11); // TI/TP=on, TIE=on Wire.endTransmission(); Wire.beginTransmission(RtcADR); Wire.write(0x0f); // タイマー設定値 Wire.write(0x01); // 1回毎 Wire.endTransmission(); Wire.beginTransmission(RtcADR); Wire.write(0x0e); // タイマースタート Wire.write(0x82); // TEビットon, カウンタソースクロックは1秒を設定 Wire.endTransmission(); } void sensData () { Wire.beginTransmission(addresPsensor); Wire.write(0x12); // Start both conversions(Pressure and Temperature) Wire.write(0x01); Wire.endTransmission(); delay(3); Wire.beginTransmission(addresPsensor); Wire.write((uint8_t)0x00); // Read pressure and temperature Wire.endTransmission(); Wire.requestFrom(addresPsensor, 4); // Request 4 bytes if(Wire.available()) { Padc = read_adc(); Tadc = read_adc(); int signedTadc = Tadc; // float Pcomp = a0 + (b1 + c11 * Padc + c12 * Tadc) * Padc + (b2 + c22 * Tadc) * Tadc; // 22976 float Pcomp = a0 + (b1 + c12 * Tadc) * Padc + (b2 * Tadc); // c11 とc22はゼロなので計算省略(84バイト節約) Pha = Pcomp * 650 / 1023 + 500; Temp = 25 - (signedTadc - 472) / 5.35; } delay(1); } float read_coefficients(int total_bits, int fractional_bits, int zero_pad) { unsigned char msb, lsb; msb = Wire.read(); lsb = Wire.read(); Serial.print("mbs = "); Serial.print(msb); Serial.print(", lsb = "); Serial.println(lsb); return ((float) ((msb << 8) + lsb) / ((long)1 << (16 - total_bits + fractional_bits + zero_pad))); } unsigned int read_adc() { unsigned char msb, lsb; msb = Wire.read(); lsb = Wire.read(); return (((unsigned int)msb << 8) + lsb) >> 6; } void ClockSet(){ int n, nen, tsuki, dayCount; lcd.setCursor(0,0); lcd.print("Clock set mode"); // モード入りメッセージ while(digitalRead(entB) == LOW){ // Clock EnterスイッチがOFFになるまで待つ } delay(30); lcd.setCursor(0,0); lcd.print("SEL=Val,ENT=Next"); Rtc.available(); // 現在の時刻を取得 convString(); // RTCの時刻(BCD)を文字列に変換してdtStringに格納 lcd.setCursor(0,1); for(n=0; n<=15;n++){ lcd.print(dtString[n]); } //データ位置とmin,max値を指定して数値設定プログラムを呼ぶ setV(3, 12, 32); // 年(2012〜2032年まで) setV(6, 1, 12); // 月 // 日は月の大小と閏年を反映して呼ぶ nen = (dtString[2] & 0x0f)*10 + (dtString[3] & 0x0f); tsuki = (dtString[5] & 0x0f)*10 + (dtString[6] & 0x0f); dayCount =31; if(tsuki == 4 | tsuki== 6 | tsuki == 9 | tsuki == 11){ dayCount =30; } if(tsuki == 2){ // 2月の処理 dayCount = 28; if((nen % 4) == 0){ dayCount =29; // うるう年 } } setV(9, 1, dayCount); // 日 setV(12, 0, 23); // 時 setV(15, 0, 59); // 分 updateClock(); // RTCに日時を設定 } // set ボタンが押される毎にdtStringの指定位置の値をインクリメント、液晶を更新 // ent ボタンが押されたら戻る void setV(int p, int minV, int maxV){ // p:ポインタ、minV:最小値、maxV:最大値 int xx; char upper; char lower; lcd.setCursor(p, 1); // 液晶のカーソルを移動 lcd.cursor(); // カーソル表示 xx = (dtString[p-1] & 0x0f) * 10 + (dtString[p] & 0x0f); //文字列から初期値を計算。BCDなので上位は10倍 while(digitalRead(entB)==LOW){ // entBがOFFになるまで待つ delay(30); } while(digitalRead(entB) == HIGH){ // entBがNOでなければ以下の処理行う if(digitalRead(selB) == LOW){ delay(30); // selBが押された! xx++; // xxをインクリメント if(xx >= maxV+1){ // 上限超えてたらゼロに戻す xx=minV; } upper = (xx / 10) | 0x30; // 上位をASCIIへ変換 lower = ( xx % 10) | 0x30; // 下位をASCIIへ変換 lcd.setCursor(p-1, 1); lcd.print(upper); // 表示更新 lcd.print(lower); lcd.setCursor(p, 1); // 液晶のカーソルを元の位置に戻す dtString[p-1]=upper; // データ文字列更新 dtString[p]=lower; while(digitalRead(selB)==LOW){ // selBが離されるまで待つ } delay(30); } } delay(30); } void updateClock(){ // RTCに値をセット byte data[7]; int yy, mm, dd, ww; yy = (dtString[2] & 0xf) * 10 + (dtString[3] &0xf) + 2000; mm = (dtString[5] & 0xf) * 10 + (dtString[6] &0xf); dd = (dtString[8] & 0xf) * 10 + (dtString[9] &0xf); if( mm <= 2){ // ツェラーの式で曜日を求める mm+=12; yy--; } ww = (yy + yy/4 - yy/100 + yy/400 + (13*mm + 8)/5 + dd) % 7; for(int n = 0; n <= 15; n++){ // デバッグ用 Serial.print(dtString[n]); } Serial.print(" Week= "); Serial.println(ww); data[0] = 0x00; // 00秒にリセット data[1] = ((dtString[14] & 0xf) << 4) | (dtString[15] & 0x0f); // 分 data[2] = ((dtString[11] & 0xf) << 4) | (dtString[12] & 0x0f); // 時 data[3] = ((dtString[8] & 0xf) << 4) | (dtString[9] & 0x0f); // 日 data[4] = ww; // 曜日 data[5] = ((dtString[5] & 0xf) << 4) | (dtString[6] & 0x0f); // 月 data[6] = ((dtString[2] & 0xf) << 4) | (dtString[3] & 0x0f); // 年 Rtc.sync(data); }