#include #include /* * Day/Night time monitor (6314 bytes) * 2012.1.21 by radiopenchi * http://radiopench.blog96.fc2.com/ * Pin 8:昼/夜信号入力、Hi = 昼, Low = 夜 * Pin 7:強制運針スイッチ、 ON(LOW)でアクティブ */ LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // LCD Pin Assign unsigned long timePassed; // 経過時間保持タイマー unsigned long lastNightTime; // unsigned long lastDayTime; // long int a; // 汎用変数 long int i; // 汎用変数 long int ii; long int iii; unsigned long outPulse; // 時計の現在の出力パルス数 unsigned long targetPulse; // 時計の目標パルス数 unsigned long lastTargetPulse; unsigned long targetTime; // 時計の目標時間 unsigned long targetNext; // 目標時間 unsigned long targetTheNext; // 次の目標時間 unsigned long eightHr = 28800; // 最初の2回の設定速度、デフォルト=28800(8Hr) デバッグ時:40 unsigned long sixHr = 21600; // 時計半周分のパルス数、デフォルト=21600(6Hr) デバッグ時:30 boolean dispFlag = false; // 表示ブリンクフラグ boolean nowIsDay; // TRUEなら今は昼 boolean lastIsDay; // TRUEなら前は昼 boolean nodata=true; // 全く測定データ無し。昼夜変わったか確認のために必要 boolean dayNightChanged = false; // 昼夜が変わったらセット boolean firstDayNightChanged = false; // 一番最初に昼夜が変わったらセット boolean driveflag = true; // 時計コイルのドライブ極性反転フラグ void setup() { Serial.begin(9600); lcd.begin(16, 2); //LCDのサイズ設定 pinMode(7, OUTPUT); // 強制運針スイッチ digitalWrite(7, HIGH); // プルアップ pinMode(8, INPUT); // 昼夜信号入力ピン digitalWrite(8, HIGH); // プルアップ // 時計インターフェイス定義 pinMode(9, OUTPUT); // conect coil thrugh 330Ω pinMode(10, OUTPUT); // coil return digitalWrite(9, LOW); // reset coil digitalWrite(10, LOW); // reset coil pinMode(13, OUTPUT); // 動作モニタ、割込み処理中にON outPulse = sixHr; // 最初の周回のために初期値を6H分にしておく lastTargetPulse = sixHr; targetNext = eightHr; // 初期値は8H つまり先途中で昼夜が変わらない値 targetTheNext = eightHr; // 初期値は8H MsTimer2::set(1000, timeIntrp); // 1秒毎に timeIntrpをコール MsTimer2::start(); } void loop() { // メインルーチンは何もしない } void timeIntrp() { digitalWrite(13, HIGH); // 割り込み処理の開始をLED表示 if ( digitalRead(7) == LOW ) { stepUpClock(); // 7ピンがLOWなら時計を強制的に動かす } else { timePassed ++; // 経過時間をインクリメント timeDisp(); // LCD表示処理 if ( firstDayNightChanged == true){ // 昼夜が一度も変わってなけば何もしない。 clockDrive(); // 時計表示処理 } } digitalWrite(13,LOW); // LED OFF } void clockDrive(){ //時計の操作ルーチン開始 if( dayNightChanged == true ){ // 昼夜が変わった時はパラメータ更新 targetTime = targetNext; targetPulse = sixHr + (lastTargetPulse - outPulse); // 半周分+残りパルス数をセット lastTargetPulse = targetPulse; // 繰越分の計算用に保存 dayNightChanged = false; iii ++; /* Serial.print("*** "); Serial.print(iii); Serial.print(", "); Serial.print(outPulse); Serial.print(", "); Serial.println(targetPulse); */ outPulse =0; } if ( outPulse >= targetPulse ) { // 時計が半周してたら targetTime = 0; // 時計を進めないようにして outPulse = sixHr; // 余分に進めている場合があるので値を戻す lastTargetPulse = sixHr; } if ( timePassed >= 1 ) { // 昼夜が変わった直後でなければ、 ii = int((timePassed * targetPulse) / targetTime)-int(((timePassed-1) * targetPulse) / targetTime); if ( ii >= 1 ){ // 1以上だったらだめなんだけど・・・ stepUpClock(); // 時計を進める outPulse ++; // ドライブパルス数をカウントアップ } } /* Serial.print(timePassed); Serial.print(", "); Serial.print(outPulse); Serial.print(", "); Serial.print(targetTime); Serial.print(", "); Serial.print(targetPulse); Serial.print(", "); Serial.println(ii); */ } // 時計の操作の終了 void timeDisp() { // LCD表示ルーチン if (digitalRead(8) == HIGH) { // 昼か夜かを読み取り、フラグセット nowIsDay = true; } else{ nowIsDay = false; } if ( nodata == true ){ // 以前のデータが無ければ、 nodata = false; // フラグを反転させ、 lastIsDay = nowIsDay; // 昼か夜だったかを記録して、おしまい。 } else{ if (nowIsDay != lastIsDay){ // 昼夜が変わっていたら、、、 dayNightChanged = true; // 時計で使用 lcd.noCursor(); // カーソルOnの場合があるので、消す if( nowIsDay == true ){ // 夜→昼の場合は、 lcd.setCursor(9, 0); dispHMX(timePassed); // 今日の夜の値を表示 lcd.setCursor(9,1); dispHMX(lastNightTime); // 前日の夜の値を表示 lastNightTime = timePassed; // 再使用するため保存 } else{ // 昼→夜になったなら、 lcd.setCursor(0, 0); dispHMX(timePassed); // 今日の昼の値を一行目に表示 lcd.setCursor(0,1); dispHMX(lastDayTime); // 前日の昼の値を二行目に表示 lastDayTime = timePassed; // 再使用するため保存 } targetNext = targetTheNext; // 2段FIFOで過去の昼夜の長さを保持 if (firstDayNightChanged == true){ // 但し、初回の測定結果は targetTheNext = timePassed; // 書き換えず初期値を残す。 } firstDayNightChanged = true; // 最初に昼夜が変わったフラグセット(時計で使用) timePassed = 0; // 時計をリセット lastIsDay = nowIsDay; } // 昼夜が変わっていた場合の処理完了 else{ // 昼夜が変わっていない場合は、 if( nowIsDay == true ){ // 昼なら、 lcd.setCursor(0, 0); dispFlag = ! dispFlag; // ブリンクフラグ反転 if( dispFlag == true ){ dispHMX(timePassed); // 現在値表示。 lcd.setCursor(6, 0); lcd.cursor(); // 現在値であることを示すためにカーソル点灯 } else{ lcd.noCursor(); dispHMX(lastDayTime); // 前日の値を表示 } } else{ // 夜なら、 lcd.setCursor(9, 0); dispFlag =! dispFlag; if( dispFlag == true ){ dispHMX(timePassed); // 現在値表示 lcd.setCursor(15, 0); lcd.cursor(); // 現在値であることを示すためにカーソル点灯 } else{ lcd.noCursor(); dispHMX(lastNightTime); // 前の値を表示 } } } } } // timeDispルーチンの終了 void dispHMX(unsigned long xxx){ // 引数の値をLCDにHH:MM.x形式で書き込む unsigned long sec; unsigned long hh; unsigned long mm; unsigned long ss; unsigned long xx; sec= xxx; // スケーリング、、、しない hh = sec / 3600; // 時間 mm = (sec - hh * 3600) / 60; // 分 ss = (sec % 60); // 秒 xx = ss / 6; // 1/10分 if(hh < 10) lcd.print("0"); // 文字数調整(本当は文字列操作で2文字切り出すべき) lcd.print(hh); lcd.print(":"); if(mm < 10) lcd.print("0"); // 文字数調整 lcd.print(mm); lcd.print("."); lcd.print(xx); // 1/10分を表示 } void stepUpClock() { // 時計駆動処理ルーチン a=0; i=0; driveflag = ! driveflag; if (driveflag == true) { digitalWrite(9, HIGH); // coil drive Forward while( i < 26500 ){ // ドライブ時間稼ぎ a = a + i; // コンパイラの最適化対策? i++; } digitalWrite(9, LOW); // coil drive end } else { digitalWrite(10, HIGH); // coil drive Revers while( i < 26500 ){ a = a + i; i++; } digitalWrite(10, LOW); // coil drive end } }