VFD時計の作り方

VFD時計キットの作り方
 
========================================
 仕様
========================================
・電源電圧5V 電流約80mA
・日付表示可 スイッチを押したときのみ3秒だけ
・キッチンタイマー機能
・ボタン電池による日時バックアップ
・USB経由時刻同期機能 Windowsパソコンのみ対応
・アラーム ブザーが鳴ります
・時刻校正 使用している水晶の精度が低いので校正が必要。校正後の日差1秒以下
・一週間以上電源を入れていないとその間の時刻校正は行われない

========================================
 注意
========================================
・電源電圧が4.85V以下だと蛍光表示管が点灯しません
・昔の電卓に使用されていた物なので文字が小さく遠くからは読めません ガラス管の直径は7.5mmです
・プログラムは書き込まれていません
 プログラムを書き込むためのプログラム(Arduinoブートローダー)だけが書き込まれているので
 USB経由でプログラムを書き込んで使用して下さい
・明るさについては下のほうにある写真を見てください
 古い蛍光表示管なのでかなり輝度にばらつきがあります
 スタティック点灯させているのでこれ以上輝度は上がりません
 抵抗値を変更すると輝度が変わります
 変更方法は下のほうに書いてあります
・USBシリアル変換ICは中国メーカーのCH340を使用しています
 CH340ドライバーをインストールしないとArduinoとして認識されないためプログラムの書き込みが出来ません
・部品が小さいので不器用な人は組み立てられません
 老眼の場合眼鏡をかけても部品が小さくて見えません。拡大鏡が必要です
・フラックスを使用した場合は洗浄してください
 フラックスを使う場合は内部に洗浄液が入ると問題のある 電解コンデンサ、スイッチ、ブザー、コイル(電気的には影響ないが乾くのに時間がかかる) の半田付けを後回しにして
 洗浄後にこれらをフラックスなしで半田付けします

========================================
 使い方
========================================
設定した値は不揮発メモリーに記録されるため電源を切っても消えない

●カレンダー
 ・アラームが鳴っていないときにSW3を押すと3秒間日付が表示される

●アラーム時刻設定
 ・キット完成直後の初期値はAM7:00、アラーム機能はOFFになっている
 ・SW1を押すとアラーム時刻が表示される。そのまま3秒放置すると通常の時刻表示に戻る
 ・3秒以内に再度SW1を押すとアラーム音が鳴りアラーム時刻設定モードになる
 ・アラーム時刻の設定は年月日の設定が無いことを除いて時刻の設定と同じ。時刻の設定方法は少し下を参照

●アラームON/OFF切り替え
 ・SW2を押すとアラーム有効/無効が切り替わる
  アラームが有効な時は赤色LEDが点灯、スイッチを押したときにアラーム音が鳴る
  アラームが無効な時は赤色LEDが消灯

●アラーム音停止
 ・アラームが鳴り始めてから1分放置するとアラーム音は自動的に止まる
 ・SW3を押すとアラームを強制停止できる
 ・アラーム時刻設定やアラームON/OFF切り替えの操作をすることによってもアラーム音は止まる

●時刻設定
 ・本体のスイッチでもUSB経由でも時刻設定できる
  本体のスイッチで設定する場合は以下の手順となる
 ・SW1を押しながら電源を入れる。SW1を押しながらS1を押してもよい
  設定モードに入るときはブザーが3回鳴る
 ・年->月->日->時->分->12/24時間表示->時刻校正 の順番で設定
  秒はゼロ以外の値に出来ないため入力不能
  SW1を押すと次の設定項目に移動
  設定中の桁が3回点滅する
  時刻校正後にSW1を押すと秒はゼロになり時計が動き出す
 ・年は下2ケタまでのため2099が最大値
 ・SW2が数値増加、SW3が数値減少
  12/24時間表示の設定時はSW2,SW3どちらを押しても同じ動作をする
 ・時刻校正は一日に時計が何秒進むか送れるかを入力する
  進む場合はプラスの値、遅れる場合はマイナスの値を入力する
  校正は1日にここで指定した秒数(=回数)だけ時計を調整するため
  1秒が2秒になったり1秒飛んだりする
  キットの水晶は8秒/日程度進むものが多いため初期値は+8秒に設定してあります

●キッチンタイマー
 ・SW4を押すとキッチンタイマーモードになる
  再度SW4を押すとキッチンタイマーモードから抜ける
 ・10秒単位でしか時間を設定できない
 ・最大60分、最小10秒
 ・SW1を押すとタイマースタート
 ・カウントダウンしてゼロになるとブザーが鳴る
  しばらくすると初期値に戻る
 ・設定した初期値はキッチンタイマーモードを抜けても記憶されている
  再度キッチンタイマーモードにすると初期値は前回設定した値になる

●USB時刻同期
 ・使い方を書いても読む人はいないので特に説明はなし
  USB時刻同期プログラムを実行していじってみればわかる
  このページの下のほうに画面イメージ有り
 ・データ形式にGPSで使用されているNMEAフォーマットを使っているので回路を少し変更(スイッチでCH340<->GPSモジュールを切り替える)すればソフト変更無しでGPSによる同期も可能

●その他
 ・大きい28ピンICのすぐ横にあるスイッチ(S1)はリセットスイッチ(Arduinoのリセットスイッチ)
  プログラムを自分で書く人専用の機能


2016-11-25

このキットはプログラムの書き込みが必要です。キットが完成したら以下のリンクの説明に従ってプログラムを書き込んでください
Arduino系キットのプログラム書き込み方法
このリンクはArduino系キット共通の手順が書いてあります
各キット用のプログラム(=スケッチ)はこのページの下のほうに添付してあります
書き込みが完了するとブザーが鳴り赤いLEDが一瞬だけ点灯します
書き込み直後の日時は 2017/01/01 00:00:00 です

完成するとこうなります。電源はキットに付属していません。5VのAC-DCアダプターを購入して下さい。
YouTube動画 VFD時計
フラックスを使った場合の洗浄方法 YouTube動画 基板洗浄

R0032538.jpg

基板表面
・LEDはこの写真右側がプラスで足が長い
・ケースに入れる場合はスイッチの各端子から電線を引き出してスイッチを増設する。増設した場合は基板上のスイッチと増設したスイッチどちらも機能する

PICT3959.jpg

基板表面 部品配置図 黄色い部品は裏面の部品

brdimg.png

基板裏面
・裏面のICは全部ハーフピッチ(足間隔1.27mm)の面実装品です
・ICは全部取付向きがあります
 丸い凹み、半円形の凹み、文字の向きで判断して下さい
・LTC1707はパッケージの1-4番ピン側(この写真右側)が斜めに削られた形状で判断しますがかなり拡大しないと解らないため文字の向きで判断して下さい

PICT3964.jpg

基板裏面 部品配置図

brdimgrev.png

部品表
電源はキットに付属していません

buhinhyo.png

CH340Gの取り付け向き

R0032547.jpg

面実装品はセロハンテープで仮固定してから半田付けする

R0032667.jpg

集合抵抗の取り付け向き。文字が裏側

R0032549.jpg

VFDは足を違う長さにしないと基板にさすのが困難です
赤いチューブがかぶさっている足を基板の〇マークに合わせます
★★★ 注意!! ★★★
垂直になっていることを確認すると同時に表示面が真正面を向いているか確認
足の数が多いので半田付け後は修正困難です
3本半田付けすると動きません

R0032507.jpg

======= 冶具の使い方 注意点 =======
・冶具は購入者全員で使いまわすので使い終わったら返送用封筒に入れて返送してください
・冶具は分解しないでください。再組立てすると上下のアクリル板がずれます

・基板に押し込んだ後に管をひねることは出来ない。表示面が正面を向いた状態で基板に押し込む
・無理に押し込んで管を割らないように
・基板に管を押し込むときに足がくの字に曲がらないように

R0032720.jpg

1.最初に蛍光表示管が冶具の穴に収まるか確認。管の下部が変形していて奥まで差し込めない個体は後回しにする

R0032709.jpg

2.6本全部基板に挿す。抜けないように1,2本足を曲げておく

R0032717.jpg

3.冶具の中に管を収めてから冶具を基板に固定する。足を長く残しておくほうがやりやすい

R0032721.jpg

4.文字の向きはこの角度からが一番わかりやすい

R0032723.jpg

5.気が済むまで表示の向きと高さを調整してから半田付け。その後冶具を取り外す

R0032727.jpg

6.変形して入らなかった物を基板に挿して冶具を逆さまにして位置ぎめする

天候:くもり PM2:00 窓際での輝度。裏面からでも直射日光が当たる場所では文字が判別しにくくなります。真っ暗な部屋ではやや眩しい

R0032595.jpg
R0032593.jpg

夜間の室内ではこんな輝度

R0032601.jpg

昼間。輝度不足ではなく点灯していないセグメントが周囲の反射光に照らされて明るくなるため見づらくなる。昼間の明るい部屋ではスモークパネルを使用したほうがコントラストが高くなる

R0032627.jpg
R0032628.jpg

===================================
  輝度の変更方法
===================================

・輝度のばらつきが気になる人は以下の方法で輝度を変更してください
・輝度変更用の抵抗はキットに付属していません

<<<<<ヒーター電流を変更する>>>>>
・各管個別に輝度を変更できる
・R1~R6を変更するとヒーターに流れる電流が変わる
・R1~R6は少し位置がずれているがその前にある蛍光表示管に対応している
・抵抗値を
  小さくする->電流が多く流れて明るくなる
  大きくする->電流が減って暗くなる
・抵抗値の変更範囲
  10Ω以上 これ以上小さくしてはいけない
  小さくしすぎるとヒーター(文字の手前にある縦方向に1本ある細い線)が赤くなってしまう
・電流の計算式は以下のとおりであるが電流が分かっても輝度は目視してみないと分からないので現物合わせで調整する必要がある
  ヒーター電源電圧0.8[V] = (ヒーター抵抗値24[Ω] + R1~R6抵抗値)× ヒーター電流[A]

<<<<<グリッドおよびアノード電圧を変更する>>>>>
・電圧は各管共通なのでこれを変更すると6管全部の輝度が変わる
・抵抗R7を
  大きくする->電圧が上がる->明るくなる
  小さくする->電圧が下がる->暗くなる
・R7の抵抗値と電圧の関係
  7.5kΩ->12.68V
  8.2kΩ->13.75V
  9.1kΩ->15.12V
   10kΩ->16.49V キット標準
   11kΩ->18.02V
   12kΩ->19.54V 定格は12Vなのでこの電圧でやめておいたほうがいい

時刻同期プログラムの画面イメージ。最初にVFD時計がつながっているCOMポートを選択する。1つしかないときはソフトで自動的に選択するほうが親切だがこのプログラムはそこまでおせっかいではない。小さな文字は送受信しているデータ。この中身を理解する必要はない。12/24時間表示切替はよく変更するものでもないのでこのソフトでは変更できない

neonclockvb.png

=====================================
回路の解説
=====================================
・RN1は片側が繋がっているタイプの集合抵抗
・DS1307はリアルタイムクロック
・CH340はUSBシリアル変換IC
・LT1172は昇圧DC-DCコンバータ
・LT1707は降圧DC-DCコンバータ
・ICSP6ピンは特に使用していない
・ブザーは圧電タイプ ArduinoのanalogWrite約1kHzPWMで鳴らしている

・リアルタイムクロックのOUTはオープンドレイン出力
 1Hzの矩形波が出力されている
 信号の立下りで秒が変化する
 これを外部割り込みでとらえて時刻を更新している
・VFDのアノード&グリッド電圧を変更したいときはR7もしくはR8を変更する
 LT1172はFBの電圧が1.25Vになるように出力電圧を制御するので 1.25 / R8 = 出力電圧 / (R8 + R7) が成り立つ
・LTC1707はVFBが0.8ボルトになるように出力電圧を制御する
 ヒーター電圧はもう少し低いのでさらに電圧を下げたいが0.8V以下には出来ない
 DC-DCコンバーターの回路はほぼデータシート丸写し
・ヒーター電圧はR1~R6を変更すると変わる
 ヒーターの抵抗値を24Ωとして計算
 ヒーター電流20mAが最適値。26mAだとヒーターが赤熱しているのが解る
・MCP100-475は電源電圧が4.75V以下になるとVoutが0Vになる
 通常の状態ではVoutは電源電圧に等しい
 電源をOFFするとLTC1707のRUNが0Vになりヒーター電圧の0.8Vが止まる
 MCP100-475のVout電圧をA1ポートで監視し電圧が下がるとソフトでD3をHIGHにしてグリッド電圧の16.5Vを止めている
 電源を止めることによりC13に充電された電力が空になるのを遅らせている
 時間稼ぎをしている間に電源OFF時に退避させたい情報をDS1307のRAMに書き込む
 RAMはボタン電池でバックアップされているので電源を切っても消えない
 RAMに書き込んでいる情報は 電源をOFFした時刻
 この時刻を使って電源OFFしている間の時刻校正を起動時に実行している
・USBバスパワーの時、電源VCCはD3経由で繋がるためD3のVf(0.6V程度)だけ電圧が下がる
 このためMCP100-475のVoutがLOWになりヒーター電圧が出力されなくなりVFDは点灯しない
 D3の代わりに電線でショートさせるとUSBバスパワーでもVFDが点灯するようになるが
 誤ってUSBと電源を同時接続するとパソコンのUSBを壊してしまう危険性がある

GPSで時刻同期したい場合はGPSモジュールをシリアル接続する。GPSモジュールは初期値9600bpsになっているので特にスケッチを修正する必要は無い

schimg.png
プログラム
ファイル ファイルタイプ 添付ファイルの解説
vfdclock_ino.zip arduino スケッチ(=プログラム)これをUSB経由で書き込む
これ以外にtimeライブラリーとMsTimer2ライブラリーが必要
ライブラリーの場所はArduino系キットのプログラム書き込み方法のページにある
上記のライブラリーを正しくインストール出来たにもかかわらず 'tmElements_t' was not devlared in this scope のエラーが出たときは9行目の Time.h を TimeLib.h に書き換える

コンパイルエラーが出たときはArduinoやライブラリーのバージョン等の違いと思われるのでご連絡ください
VFDClockexe.zip OTHER 時刻同期プログラム Windows用 EXEアプリケーション インストール不要展開して実行
プログラムの解説 バージョンアップされてもここにあるプログラムは更新しません
0001  //-------------------------------------------------------------- 2016-11-27 -----
0002 // VFD Clock
0003 //
0004 // Ver1.00
0005 //-------------------------------------------------------------------------------
0006 #include <Wire.h>
0007 #include <MsTimer2.h>
0008 #include <EEPROM.h>
0009 #include <Time.h>
0010
0011 //---- PORT -------------------------------
0012 #define A6812_CLOCK 10 // VFD 20-bit serial-input latched source driver
0013 #define A6812_DATA 8
0014 #define A6812_BLANK 9
0015 #define A6812_STROBE A0
0016 #define LED 6 // red LED
0017 #define VOLTAGE_DETECTOR A1 // MCP100-475DI
0018 #define RTC_OUT 2 // DS1307
0019 #define BUZZER 5 // BUZZER port
0020 #define SW1 7 // SW1 port
0021 #define SW2 4 // SW2 port
0022 #define SW3 A3 // SW3 port
0023 #define SW4 A2 // SW4 port
0024 #define DC_DC_DISABLE 3 // 18V DC-DC
0025
0026 //---- PUSH SWITCH ------------------------
0027 #define SW_ON LOW
0028 #define SW_OFF HIGH
0029 #define SW_NO1 1
0030 #define SW_NO2 2
0031 #define SW_NO3 3
0032 #define SW_NO4 4
0033 #define SW_DEFAULT_ON_TIME 20 // 20[msec]
0034 #define SW_DEFAULT_OFF_TIME 50 // 50[msec]
0035
0036 //---- DS1307 -----------------------------
0037 #define CLOCK_HALT 0b10000000
0038 #define CLOCK_START 0b00000000
0039 #define OUT_1Hz 0b00010000
0040 #define OUT_4096HZ 0b00010001
0041 #define OUT_8192HZ 0b00010010
0042 #define OUT_32768HZ 0b00010011
0043 #define OUT_OFF 0b00000000
0044 #define DS1307_DEVICE_ADDRESS 0x68
0045 #define DS1307_READ 0b00000001
0046 #define DS1307_WRITE 0b00000000
0047 #define HOURS_AM 1
0048 #define HOURS_PM 0
0049 #define ADDRESS_SECONDS 0
0050 #define ADDRESS_MINUTES 1
0051 #define ADDRESS_HOURS 2
0052 #define ADDRESS_DAY 3
0053 #define ADDRESS_DATE 4
0054 #define ADDRESS_MONTH 5
0055 #define ADDRESS_YEAR 6
0056 #define ADDRESS_CONTROL 7
0057
0058 #define OFFSET_ADDRESS_POWER_OFF_TIME 0x08
0059 #define OFFSET_ADDRESS_CALIBRATION_COUNTER 0x0C
0060
0061 //---- EEPROM address -----------
0062 #define EEPADDR_ALARM_HOURS 0 // 1 byte default value = 7
0063 #define EEPADDR_ALARM_MINUTES 1 // 1 byte default value = 0
0064 #define EEPADDR_ALARM_ENABLE 2 // 1 byte default value = 0 = disable
0065 #define EEPADDR_CALIBRATION_SIGN 3 // 1 byte '+': fast '-': behind
0066 #define EEPADDR_CALIBRATION_TIME 4 // 1 byte XX sec / day fast or behind
0067 #define EEPADDR_DISPLAY_FORMAT 5 // 1 byte default value = DISPLAY_24HOUR
0068 #define EEPADDR_TIMER_SEC 6 // 1 byte kitchen timer second
0069 #define EEPADDR_TIMER_MIN 7 // 1 byte kitchen timer minute
0070
0071 #define DISPLAY_12HOUR 0
0072 #define DISPLAY_24HOUR 1
0073 #define DISPLAY_ALARM 2
0074 #define DISPLAY_DATE 3
0075 #define DISPLAY_TIMER 4
0076 #define DISPLAY_CALIBRATION 5
0077
0078 #define EEPADDR_CRC_LOW 0x10 // 1 byte
0079 #define EEPADDR_CRC_HIGH 0x11 // 1 byte
0080
0081 #define EEPROM_DATA_SIZE 8
0082
0083 //---- Alarm ---------------------
0084 #define ALARM_ENABLE 0
0085 #define ALARM_DISABLE 1
0086 #define ALARM_DEFAULT_HOUR 6
0087 #define ALARM_DEFAULT_MINUTE 9
0088
0089 //---- Gloval Variable -------------------------------
0090 time_t alarm_time;
0091 boolean alarm_enable;
0092 byte display_format; // 12hour / 24hour
0093 byte tick_flag;
0094 // byte green_bulb;
0095
0096 boolean sw1_enable;
0097 boolean sw2_enable;
0098 boolean sw3_enable;
0099 boolean sw4_enable;
0100 word sw1_disable_time;
0101 word sw2_disable_time;
0102 word sw3_disable_time;
0103 word sw4_disable_time;
0104 word sw1_disable_counter;
0105 word sw2_disable_counter;
0106 word sw3_disable_counter;
0107 word sw4_disable_counter;
0108
0109 boolean alarm_beep_enable;
0110 byte alarm_beep_table_index;
0111 word alarm_beep_counter;
0112 // on off on off on off on off
0113 const word alarm_beep_time_table[8] = { 100, 100, 100, 100, 100, 100, 100, 400 };
0114
0115 char gps_buffer[100];
0116 byte gps_buffer_index;
0117 boolean gps_buffer_full;
0118
0119 char serial_write_buffer[100];
0120
0121 long cal_counter;
0122 long cal_set;
0123 byte cal_time;
0124 byte cal_sign;
0125
0126 word digit6;
0127 word digit5;
0128 word digit4;
0129 word digit3;
0130 word digit2;
0131 word digit1;
0132
0133 boolean kitchen_counter_init;
0134 boolean kitchen_counter_tick;
0135
0136 time_t current_time;
0137
0138 //---- small function -------------
0139 #define buzzer_on() analogWrite( BUZZER, 128 )
0140 #define buzzer_off() digitalWrite( BUZZER, LOW )
0141 #define led_on() digitalWrite( LED, HIGH )
0142 #define led_off() digitalWrite( LED, LOW )
0143
0144 //===============================================================================
0145 // rtc interrupt
0146 //===============================================================================
0147 void rtcEvent()
0148 {
0149 if ( digitalRead( RTC_OUT ) == 0 ) {
0150 tick_flag = true;
0151 current_time++;
0152 }
0153 }
0154
0155 //===============================================================================
0156 // timer interrupt 1[msec] period
0157 //===============================================================================
0158 void timerEvent()
0159 {
0160 static word timer = 0;
0161
0162 //---------------------------------------------------
0163 if ( kitchen_counter_init ) {
0164 timer = 1000;
0165 kitchen_counter_init = false;
0166 } else {
0167 if ( timer > 0 ) {
0168 timer--;
0169 }
0170 if ( timer == 0 ) {
0171 kitchen_counter_tick = true;
0172 timer = 1000;
0173 }
0174 }
0175
0176 //-------- Switch test -------------------------------------------
0177 //------------- SW1 ------------------
0178 if ( digitalRead(SW1) == SW_ON ) {
0179 sw1_disable_counter = sw1_disable_time;
0180 } else {
0181 if ( sw1_disable_counter > 0 ) {
0182 sw1_disable_counter--;
0183 } else {
0184 sw1_enable = true;
0185 }
0186 }
0187
0188 //------------- SW2 ------------------
0189 if ( digitalRead(SW2) == SW_ON ) {
0190 sw2_disable_counter = sw2_disable_time;
0191 } else {
0192 if ( sw2_disable_counter > 0 ) {
0193 sw2_disable_counter--;
0194 } else {
0195 sw2_enable = true;
0196 }
0197 }
0198
0199 //------------- SW3 ------------------
0200 if ( digitalRead(SW3) == SW_ON ) {
0201 sw3_disable_counter = sw3_disable_time;
0202 } else {
0203 if ( sw3_disable_counter > 0 ) {
0204 sw3_disable_counter--;
0205 } else {
0206 sw3_enable = true;
0207 }
0208 }
0209
0210 //------------- SW4 ------------------
0211 if ( digitalRead(SW4) == SW_ON ) {
0212 sw4_disable_counter = sw4_disable_time;
0213 } else {
0214 if ( sw4_disable_counter > 0 ) {
0215 sw4_disable_counter--;
0216 } else {
0217 sw4_enable = true;
0218 }
0219 }
0220
0221 //-------- alarm beep ------------------------
0222 if( alarm_beep_enable ) {
0223 if( alarm_beep_counter == 0 ) {
0224 if( alarm_beep_table_index % 2 == 0 ) {
0225 buzzer_on();
0226 } else {
0227 buzzer_off();
0228 }
0229 alarm_beep_counter = alarm_beep_time_table[ alarm_beep_table_index ];
0230 if( alarm_beep_table_index == 7 ) {
0231 alarm_beep_table_index = 0;
0232 } else {
0233 alarm_beep_table_index++;
0234 }
0235 } else {
0236 if( alarm_beep_counter > 0 ) {
0237 alarm_beep_counter--;
0238 }
0239 }
0240 }
0241 }
0242
0243 //-------------------------------------------------------------------------------
0244 // serial interrupt
0245 //-------------------------------------------------------------------------------
0246 void serialEvent()
0247 {
0248 byte recieve_data;
0249
0250 //------- GPS -------------------------------------------------
0251 if( Serial.available() > 0 ) {
0252 recieve_data = Serial.read();
0253 if( recieve_data == '$') {
0254 gps_buffer_index = 0;
0255 }
0256 gps_buffer[gps_buffer_index] = recieve_data;
0257 if( (gps_buffer_index == 64) or ( recieve_data == 0x0D ) or ( recieve_data == 0x0A ) ) {
0258 gps_buffer_full = true;
0259 } else {
0260 gps_buffer_index++;
0261 }
0262 }
0263 }
0264
0265 //-------------------------------------------------------------------------------
0266 // beep
0267 //-------------------------------------------------------------------------------
0268 void beep( word time )
0269 {
0270 word count;
0271
0272 buzzer_on();
0273 for ( count = 0 ; count <= time ; count++ ) {
0274 delay( 1 );
0275 }
0276 buzzer_off();
0277 }
0278
0279 //-------------------------------------------------------------------------------
0280 // beep beep
0281 //-------------------------------------------------------------------------------
0282 void beep2( byte count )
0283 {
0284 byte counter;
0285
0286 for ( counter = 0 ; counter < count ; counter++ ) {
0287 buzzer_on();
0288 delay(100);
0289 buzzer_off();
0290 delay(100);
0291 }
0292 }
0293
0294 //-------------------------------------------------------------------------------
0295 // error beep
0296 //-------------------------------------------------------------------------------
0297 void beep_error()
0298 {
0299 byte counter;
0300
0301 for ( counter = 0 ; counter < 5 ; counter++ ) {
0302 buzzer_on();
0303 delay(30);
0304 buzzer_off();
0305 delay(30);
0306 }
0307 }
0308
0309 //-------------------------------------------------------------------------------
0310 // convert bcd <-> decimal
0311 //-------------------------------------------------------------------------------
0312 byte bcd2dec(byte val)
0313 {
0314 return ( (val / 16 * 10) + (val % 16) );
0315 }
0316
0317 byte dec2bcd(byte val)
0318 {
0319 return ( (val / 10 * 16) + (val % 10) );
0320 }
0321
0322 //-------------------------------------------------------------------------------
0323 // Real Time Clock write
0324 //-------------------------------------------------------------------------------
0325 void write_ds1307(byte address, byte w_data )
0326 {
0327 Wire.beginTransmission( DS1307_DEVICE_ADDRESS );
0328 Wire.write(address);
0329 Wire.write(w_data);
0330 Wire.endTransmission();
0331 }
0332
0333 //-------------------------------------------------------------------------------
0334 // Real Time Clock read
0335 //-------------------------------------------------------------------------------
0336 byte read_ds1307( byte address )
0337 {
0338 Wire.beginTransmission( DS1307_DEVICE_ADDRESS );
0339 Wire.write(address);
0340 Wire.endTransmission();
0341 Wire.requestFrom( DS1307_DEVICE_ADDRESS , 1 ) ;
0342 return Wire.read();
0343 }
0344
0345 //-------------------------------------------------------------------------------
0346 // Real Time Clock read CLOCK HALT
0347 //-------------------------------------------------------------------------------
0348 boolean ds1307_get_halt()
0349 {
0350 byte sec;
0351
0352 sec = read_ds1307( ADDRESS_SECONDS );
0353 if ((sec & CLOCK_HALT) == CLOCK_HALT ) {
0354 return true;
0355 } else {
0356 return false;
0357 }
0358 }
0359
0360 //-------------------------------------------------------------------------------
0361 // Real Time Clock read minutes
0362 //-------------------------------------------------------------------------------
0363 boolean get_alarm_enable()
0364 {
0365 if ( EEPROM.read( EEPADDR_ALARM_ENABLE ) == ALARM_ENABLE ) {
0366 led_on();
0367 return true;
0368 } else {
0369 led_off();
0370 return false;
0371 }
0372 }
0373
0374 //-------------------------------------------------------------------------------
0375 // Real Time Clock read minutes
0376 //-------------------------------------------------------------------------------
0377 void put_alarm_enable( boolean enable )
0378 {
0379 if ( enable ) {
0380 EEPROM.write( EEPADDR_ALARM_ENABLE, ALARM_ENABLE ); // enable
0381 led_on();
0382 } else {
0383 EEPROM.write( EEPADDR_ALARM_ENABLE, ALARM_DISABLE ); // disable
0384 led_off();
0385 }
0386 crc_eeprom_write();
0387 }
0388
0389 //-------------------------------------------------------------------------------
0390 // Real Time Clock get time
0391 //-------------------------------------------------------------------------------
0392 time_t ds1307_gettime()
0393 {
0394 tmElements_t tm;
0395 time_t temp;
0396
0397 Wire.beginTransmission( DS1307_DEVICE_ADDRESS );
0398 Wire.write( 0 );
0399 Wire.endTransmission();
0400 Wire.requestFrom( DS1307_DEVICE_ADDRESS , 7 ) ;
0401
0402 tm.Second = bcd2dec(Wire.read() & 0x7f);
0403 tm.Minute = bcd2dec(Wire.read() );
0404 tm.Hour = bcd2dec(Wire.read() & 0x3f); // mask assumes 24hr clock
0405 tm.Wday = bcd2dec(Wire.read() ); // not use
0406 tm.Day = bcd2dec(Wire.read() );
0407 tm.Month = bcd2dec(Wire.read() );
0408 tm.Year = bcd2dec(Wire.read()) + 30;
0409
0410 return makeTime( tm );
0411 }
0412
0413 //-------------------------------------------------------------------------------
0414 // Real Time Clock set time
0415 //-------------------------------------------------------------------------------
0416 void ds1307_settime(
0417 byte year,
0418 byte month,
0419 byte date,
0420 byte hour, // 0 to 23
0421 byte minutes,
0422 byte seconds )
0423 {
0424 write_ds1307(ADDRESS_SECONDS, CLOCK_HALT );
0425 write_ds1307(ADDRESS_YEAR, dec2bcd(year) );
0426 write_ds1307(ADDRESS_MONTH, dec2bcd(month) );
0427 write_ds1307(ADDRESS_DATE, dec2bcd(date) );
0428 write_ds1307(ADDRESS_HOURS, dec2bcd(hour) );
0429 write_ds1307(ADDRESS_MINUTES, dec2bcd(minutes) );
0430 write_ds1307(ADDRESS_SECONDS, dec2bcd(seconds) );
0431 cal_counter = 0;
0432 }
0433
0434 //-------------------------------------------------------------------------------
0435 // power off time -> Real Time Clock RAM
0436 //-------------------------------------------------------------------------------
0437 void ds1307_write_ram_long(byte offset_address, long long_data)
0438 {
0439 union ulong_convert {
0440 time_t tm;
0441 byte data[4];
0442 } convert_data;
0443
0444 convert_data.tm = long_data;
0445 Wire.beginTransmission( DS1307_DEVICE_ADDRESS );
0446 Wire.write( offset_address );
0447 for( byte index = 0; index < 4 ; index++ ) {
0448 Wire.write(convert_data.data[index]);
0449 }
0450 Wire.endTransmission();
0451 }
0452
0453 //-------------------------------------------------------------------------------
0454 // return Real Time Clock RAM
0455 //-------------------------------------------------------------------------------
0456 time_t ds1307_read_ram_long(byte offset_address)
0457 {
0458 union ulong_convert {
0459 time_t tm;
0460 byte data[4];
0461 } convert_data;
0462
0463 Wire.beginTransmission( DS1307_DEVICE_ADDRESS );
0464 Wire.write( offset_address );
0465 Wire.endTransmission();
0466 Wire.requestFrom( DS1307_DEVICE_ADDRESS, 4 );
0467 for( byte index = 0; index < 4 ; index++ ) {
0468 convert_data.data[index] = Wire.read();
0469 }
0470
0471 return convert_data.tm;
0472 }
0473
0474 //-------------------------------------------------------------------------------
0475 // set time
0476 //-------------------------------------------------------------------------------
0477 void settime( time_t tm )
0478 {
0479 byte yr;
0480
0481 yr = year(tm) % 100;
0482 ds1307_settime( yr, month(tm), day(tm), hour(tm), minute(tm), second(tm) );
0483 }
0484
0485 //-------------------------------------------------------------------------------
0486 // push switch ON test
0487 //-------------------------------------------------------------------------------
0488 boolean sw_on_test( byte sw_no, word sw_on_time, word sw_off_time )
0489 {
0490 word sw1_on_counter;
0491 word sw2_on_counter;
0492 word sw3_on_counter;
0493 word sw4_on_counter;
0494
0495 sw1_on_counter = 0;
0496 sw2_on_counter = 0;
0497 sw3_on_counter = 0;
0498 sw4_on_counter = 0;
0499 switch ( sw_no ) {
0500 case 1:
0501 while ( (digitalRead(SW1) == SW_ON) && (sw1_enable == true) ) {
0502 delay(1);
0503 if ( sw1_on_counter > sw_on_time ) {
0504 sw1_disable_time = sw_off_time;
0505 sw1_enable = false;
0506 return true;
0507 }
0508 sw1_on_counter++;
0509 }
0510 break;
0511 case 2:
0512 while ( (digitalRead(SW2) == SW_ON) && (sw2_enable == true) ) {
0513 delay(1);
0514 if ( sw2_on_counter > sw_on_time ) {
0515 sw2_disable_time = sw_off_time;
0516 sw2_enable = false;
0517 return true;
0518 }
0519 sw2_on_counter++;
0520 }
0521 break;
0522 case 3:
0523 while ( (digitalRead(SW3) == SW_ON) && (sw3_enable == true) ) {
0524 delay(1);
0525 if ( sw3_on_counter > sw_on_time ) {
0526 sw3_disable_time = sw_off_time;
0527 sw3_enable = false;
0528 return true;
0529 }
0530 sw3_on_counter++;
0531 }
0532 break;
0533 case 4:
0534 while ( (digitalRead(SW4) == SW_ON) && (sw4_enable == true) ) {
0535 delay(1);
0536 if ( sw4_on_counter > sw_on_time ) {
0537 sw4_disable_time = sw_off_time;
0538 sw4_enable = false;
0539 return true;
0540 }
0541 sw4_on_counter++;
0542 }
0543 break;
0544 }
0545
0546 return false;
0547 }
0548
0549 //-------------------------------------------------------------------------------
0550 // alarm beep on
0551 //-------------------------------------------------------------------------------
0552 void alarm_beep_on()
0553 {
0554 alarm_beep_counter = 0;
0555 alarm_beep_table_index = 0;
0556 alarm_beep_enable = true;
0557 }
0558
0559 //-------------------------------------------------------------------------------
0560 // alarm beep off
0561 //-------------------------------------------------------------------------------
0562 void alarm_beep_off()
0563 {
0564 alarm_beep_enable = false;
0565 digitalWrite( BUZZER, LOW );
0566 }
0567
0568 #define Digit_0 0x003F
0569 #define Digit_1 0x0006
0570 #define Digit_2 0x005B
0571 #define Digit_3 0x004F
0572 #define Digit_4 0x00E6
0573 #define Digit_5 0x006D
0574 #define Digit_6 0x007D
0575 #define Digit_7 0x0007
0576 #define Digit_8 0x007F
0577 #define Digit_9 0x006F
0578 #define Digit_E 0x0079
0579 #define Digit_F 0x0071
0580 #define Digit_U 0x003E
0581 #define Digit_u 0x001C
0582 #define Digit_L 0x0038
0583 #define Digit_C 0x0039
0584 #define Digit_P 0x0073
0585 #define Digit_Y 0x006E
0586 #define Digit_A 0x0077
0587 #define Digit_r 0x0050
0588 #define Digit_n 0x0054
0589 #define Digit_d 0x005E
0590 #define Digit_t 0x0078
0591 #define Digit_G 0x003D
0592 #define Digit_b 0x007C
0593 #define Digit_i 0x0010
0594 #define Digit_l 0x0006
0595 #define Digit_NON 0x0000
0596 #define Digit_o 0x005C
0597 #define Digit_S 0x006D
0598 #define Digit_h 0x0074
0599 #define Digit_H 0x0076
0600 #define Digit_c 0x0058
0601 #define Digit_US 0x0008
0602 #define Digit_MINUS 0x0040
0603 #define Digit_PLUS 0x00C6
0604 #define Digit_DP 0x0100
0605
0606 word decode_number( byte number )
0607 {
0608 switch ( number ) {
0609 case 0: return Digit_0; break;
0610 case 1: return Digit_1; break;
0611 case 2: return Digit_2; break;
0612 case 3: return Digit_3; break;
0613 case 4: return Digit_4; break;
0614 case 5: return Digit_5; break;
0615 case 6: return Digit_6; break;
0616 case 7: return Digit_7; break;
0617 case 8: return Digit_8; break;
0618 case 9: return Digit_9; break;
0619 }
0620 }
0621
0622 void A6812_send( word bit1to10, word bit11to20 )
0623 {
0624 for ( byte counter = 1 ; counter <= 10 ; counter++ ) {
0625 if ( (bit11to20 & 0x0200) == 0x0200 ) {
0626 digitalWrite( A6812_DATA, HIGH );
0627 } else {
0628 digitalWrite( A6812_DATA, LOW );
0629 }
0630 digitalWrite( A6812_CLOCK, HIGH );
0631 digitalWrite( A6812_CLOCK, LOW );
0632 bit11to20 <<= 1;
0633 }
0634 for ( byte counter = 1 ; counter <= 10 ; counter++ ) {
0635 if ( (bit1to10 & 0x0200) != 0x0000 ) {
0636 digitalWrite( A6812_DATA, HIGH );
0637 } else {
0638 digitalWrite( A6812_DATA, LOW );
0639 }
0640 digitalWrite( A6812_CLOCK, HIGH );
0641 digitalWrite( A6812_CLOCK, LOW );
0642 bit1to10 <<= 1;
0643 }
0644 }
0645
0646 void display_char( byte chr6, byte chr5, byte chr4, byte chr3, byte chr2, byte chr1 )
0647 {
0648 A6812_send( chr6, chr5 );
0649 A6812_send( chr4, chr3 );
0650 A6812_send( chr2, chr1 );
0651
0652 digitalWrite( A6812_STROBE, HIGH );
0653 digitalWrite( A6812_STROBE, LOW );
0654 digitalWrite( A6812_BLANK, LOW );
0655 }
0656
0657 void display_number( byte dig6, byte dig5, byte dig4, byte dig3, byte dig2, byte dig1 )
0658 {
0659 display_char( decode_number( dig6 ), decode_number( dig5 ) | Digit_DP,
0660 decode_number( dig4 ), decode_number( dig3 ) | Digit_DP,
0661 decode_number( dig2 ), decode_number( dig1 ) | Digit_DP );
0662 }
0663
0664 void display_refresh()
0665 {
0666 A6812_send( digit6, digit5 );
0667 A6812_send( digit4, digit3 );
0668 A6812_send( digit2, digit1 );
0669
0670 digitalWrite( A6812_STROBE, HIGH );
0671 digitalWrite( A6812_STROBE, LOW );
0672 digitalWrite( A6812_BLANK, LOW );
0673 }
0674
0675 void display_clear()
0676 {
0677 A6812_send( 0, 0 );
0678 A6812_send( 0, 0 );
0679 A6812_send( 0, 0 );
0680 digitalWrite( A6812_STROBE, HIGH );
0681 digitalWrite( A6812_STROBE, LOW );
0682 digitalWrite( A6812_BLANK, LOW );
0683 }
0684
0685 //-------------------------------------------------------------------------------
0686 // display time
0687 //-------------------------------------------------------------------------------
0688 void display_time( time_t tm, byte format )
0689 {
0690 byte hr;
0691 byte min;
0692 byte sec;
0693 boolean pad0;
0694
0695 hr = hour(tm);
0696 min = minute(tm);
0697 sec = second(tm);
0698 switch ( format ) {
0699 case DISPLAY_12HOUR:
0700 if ( hr > 12 ) {
0701 hr -= 12;
0702 }
0703 digit6 = decode_number( hr / 10 );
0704 if( digit6 == Digit_0 ) { digit6 = Digit_NON; }
0705 digit5 = decode_number( hr % 10 ) | Digit_DP;
0706 digit4 = decode_number( min / 10 );
0707 digit3 = decode_number( min % 10 ) | Digit_DP;
0708 digit2 = decode_number( sec / 10 );
0709 digit1 = decode_number( sec % 10 ) | Digit_DP;
0710 display_refresh();
0711 break;
0712 case DISPLAY_24HOUR:
0713 digit6 = decode_number( hr / 10 );
0714 if( digit6 == Digit_0 ) { digit6 = Digit_NON; }
0715 digit5 = decode_number( hr % 10 ) | Digit_DP;
0716 digit4 = decode_number( min / 10 );
0717 digit3 = decode_number( min % 10 ) | Digit_DP;
0718 digit2 = decode_number( sec / 10 );
0719 digit1 = decode_number( sec % 10 ) | Digit_DP;
0720 display_refresh();
0721 break;
0722 case DISPLAY_ALARM:
0723 digit6 = decode_number( hr / 10 );
0724 if( digit6 == Digit_0 ) { digit6 = Digit_NON; }
0725 digit5 = decode_number( hr % 10 );
0726 digit4 = decode_number( min / 10 );
0727 digit3 = decode_number( min % 10 );
0728 digit2 = Digit_MINUS;
0729 digit1 = Digit_MINUS;
0730 display_refresh();
0731 break;
0732 case DISPLAY_DATE:
0733 digit6 = decode_number( (year(tm) % 100) / 10 );
0734 digit5 = decode_number( year(tm) % 10 ) | Digit_DP;
0735 digit4 = decode_number( month(tm) / 10 );
0736 digit3 = decode_number( month(tm) % 10 ) | Digit_DP;
0737 digit2 = decode_number( day(tm) / 10 );
0738 digit1 = decode_number( day(tm) % 10 ) | Digit_DP;
0739 display_refresh();
0740 break;
0741 case DISPLAY_TIMER:
0742 pad0 = true;
0743 digit6 = Digit_MINUS;
0744 digit5 = Digit_MINUS;
0745 digit4 = decode_number( min / 10 );
0746 if ( (digit4 == Digit_0) && pad0 ) {
0747 digit4 = Digit_MINUS;
0748 } else {
0749 pad0 = false;
0750 }
0751 digit3 = decode_number( min % 10 );
0752 if ( (digit3 == Digit_0) && pad0 ) {
0753 digit3 = Digit_MINUS;
0754 } else {
0755 pad0 = false;
0756 }
0757 digit2 = decode_number( sec / 10 );
0758 if ( (digit2 == Digit_0) && pad0 ) {
0759 digit2 = Digit_MINUS;
0760 } else {
0761 pad0 = false;
0762 }
0763 digit1 = decode_number( sec % 10 );
0764 display_refresh();
0765 break;
0766 }
0767 }
0768
0769 //-------------------------------------------------------------------------------
0770 // display calibration time
0771 //-------------------------------------------------------------------------------
0772 void display_calibration( int cal_time )
0773 {
0774 word sign_char;
0775 byte digit;
0776
0777 digit6 = Digit_NON;
0778 digit5 = Digit_NON;
0779 digit4 = Digit_NON;
0780 digit3 = Digit_NON;
0781 digit2 = Digit_NON;
0782 digit1 = Digit_NON;
0783
0784 if ( cal_time == 0 ) {
0785 digit1 = Digit_0;
0786 display_refresh();
0787 return;
0788 }
0789
0790 if ( cal_time > 0 ) {
0791 sign_char = Digit_PLUS;
0792 } else {
0793 sign_char = Digit_MINUS;
0794 cal_time = -cal_time;
0795 }
0796 digit = 1;
0797 while ( cal_time > 0 ) {
0798 switch ( digit ) {
0799 case 1: digit1 = decode_number( (word)(cal_time % 10) ); break;
0800 case 2: digit2 = decode_number( (word)(cal_time % 10) ); break;
0801 }
0802 cal_time /= 10;
0803 digit++;
0804 }
0805 switch ( digit ) {
0806 case 2: digit2 = sign_char; break;
0807 case 3: digit3 = sign_char; break;
0808 }
0809 display_refresh();
0810 }
0811
0812 //-------------------------------------------------------------------------------
0813 // display calibration time
0814 //-------------------------------------------------------------------------------
0815 void display_hour_format( byte format )
0816 {
0817
0818 digit6 = Digit_NON;
0819 digit5 = Digit_NON;
0820 digit4 = Digit_h;
0821 digit3 = Digit_o;
0822 digit2 = Digit_u;
0823 digit1 = Digit_r;
0824
0825 if( format == DISPLAY_12HOUR ) {
0826 digit6 = Digit_1;
0827 digit5 = Digit_2;
0828 } else {
0829 digit6 = Digit_2;
0830 digit5 = Digit_4;
0831 }
0832 display_refresh();
0833 }
0834
0835 //-------------------------------------------------------------------------------
0836 // brink
0837 //-------------------------------------------------------------------------------
0838 void brink( boolean dig6, boolean dig5, boolean dig4, boolean dig3, boolean dig2, boolean dig1 )
0839 {
0840 word save_dig6;
0841 word save_dig5;
0842 word save_dig4;
0843 word save_dig3;
0844 word save_dig2;
0845 word save_dig1;
0846
0847 save_dig6 = digit6;
0848 save_dig5 = digit5;
0849 save_dig4 = digit4;
0850 save_dig3 = digit3;
0851 save_dig2 = digit2;
0852 save_dig1 = digit1;
0853 for ( byte i = 0 ; i < 3 ; i++ ) {
0854 if ( dig6 ) { digit6 = 0; }
0855 if ( dig5 ) { digit5 = 0; }
0856 if ( dig4 ) { digit4 = 0; }
0857 if ( dig3 ) { digit3 = 0; }
0858 if ( dig2 ) { digit2 = 0; }
0859 if ( dig1 ) { digit1 = 0; }
0860 display_refresh();
0861 delay(100);
0862 digit6 = save_dig6;
0863 digit5 = save_dig5;
0864 digit4 = save_dig4;
0865 digit3 = save_dig3;
0866 digit2 = save_dig2;
0867 digit1 = save_dig1;
0868 display_refresh();
0869 delay(100);
0870 }
0871 }
0872
0873 //-------------------------------------------------------------------------------
0874 // input 24hour format time
0875 //-------------------------------------------------------------------------------
0876 time_t input_time( time_t argtm )
0877 {
0878 tmElements_t tm;
0879 byte hours;
0880 byte minutes;
0881
0882 breakTime( argtm, tm );
0883 display_time( argtm, DISPLAY_ALARM );
0884 brink( true, true, false, false, false, false );
0885 while ( true ) {
0886 //----- increment hour -------------
0887 if ( sw_on_test( SW_NO2, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
0888 beep(10);
0889 if ( tm.Hour == 23 ) {
0890 tm.Hour = 0;
0891 } else {
0892 tm.Hour++;
0893 }
0894 display_time( makeTime( tm ), DISPLAY_ALARM );
0895 }
0896
0897 //----- decrement hour -------------
0898 if ( sw_on_test( SW_NO3, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
0899 beep(10);
0900 if ( tm.Hour == 0 ) {
0901 tm.Hour = 23;
0902 } else {
0903 tm.Hour--;
0904 }
0905 display_time( makeTime( tm ), DISPLAY_ALARM );
0906 }
0907 if ( sw_on_test( SW_NO1, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME) ) {
0908 break;
0909 }
0910 }
0911 beep(100);
0912
0913 brink( false, false, true, true, false, false );
0914 while ( true ) {
0915 //----- increment minutes -------------
0916 if ( sw_on_test( SW_NO2, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
0917 beep(10);
0918 if ( tm.Minute == 59 ) {
0919 tm.Minute = 0;
0920 } else {
0921 tm.Minute++;
0922 }
0923 display_time( makeTime( tm ), DISPLAY_ALARM );
0924 }
0925 //----- decrement minutes -------------
0926 if ( sw_on_test( SW_NO3, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
0927 beep(10);
0928 if ( tm.Minute == 0 ) {
0929 tm.Minute = 59;
0930 } else {
0931 tm.Minute--;
0932 }
0933 display_time( makeTime( tm ), DISPLAY_ALARM );
0934 }
0935 //------ exit ----------
0936 if ( sw_on_test( SW_NO1, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME) ) {
0937 break;
0938 }
0939 }
0940
0941 tm.Second = 0;
0942 beep(100);
0943
0944 return makeTime( tm );
0945 }
0946
0947 //-------------------------------------------------------------------------------
0948 // input date
0949 //-------------------------------------------------------------------------------
0950 time_t input_date( time_t current_time )
0951 {
0952 tmElements_t tm;
0953
0954 display_time( current_time, DISPLAY_DATE );
0955 breakTime( current_time, tm );
0956
0957 brink( true, true, false, false, false, false );
0958 while ( true ) {
0959 //----- increment year -------------
0960 if ( sw_on_test( SW_NO2, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
0961 beep(10);
0962 if ( tm.Year == 2099 ) {
0963 tm.Year = 0;
0964 } else {
0965 tm.Year++;
0966 }
0967 display_time( makeTime( tm ), DISPLAY_DATE );
0968 }
0969 //----- decrement minutes -------------
0970 if ( sw_on_test( SW_NO3, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
0971 beep(10);
0972 if ( tm.Year == 2000 ) {
0973 tm.Year = 2099;
0974 } else {
0975 tm.Year--;
0976 }
0977 display_time( makeTime( tm ), DISPLAY_DATE );
0978 }
0979 //------ exit ----------
0980 if ( sw_on_test( SW_NO1, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME) ) {
0981 break;
0982 }
0983 }
0984
0985 brink( false, false, true, true, false, false );
0986 while ( true ) {
0987 //----- increment month -------------
0988 if ( sw_on_test( SW_NO2, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
0989 beep(10);
0990 if ( tm.Month == 12 ) {
0991 tm.Month = 1;
0992 } else {
0993 tm.Month++;
0994 }
0995 display_time( makeTime( tm ), DISPLAY_DATE );
0996 }
0997 //----- decrement month -------------
0998 if ( sw_on_test( SW_NO3, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
0999 beep(10);
1000 if ( tm.Month == 1 ) {
1001 tm.Month = 12;
1002 } else {
1003 tm.Month--;
1004 }
1005 display_time( makeTime( tm ), DISPLAY_DATE );
1006 }
1007 //------ break ---------------
1008 if ( sw_on_test( SW_NO1, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME) ) {
1009 break;
1010 }
1011 }
1012 beep(100);
1013
1014 brink( false, false, false, false, true, true );
1015 while ( true ) {
1016 //----- increment date -------------
1017 if ( sw_on_test( SW_NO2, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
1018 beep(10);
1019 if ( tm.Day == 31 ) {
1020 tm.Day = 1;
1021 } else {
1022 tm.Day++;
1023 }
1024 display_time( makeTime( tm ), DISPLAY_DATE );
1025 }
1026 //----- decrement date -------------
1027 if ( sw_on_test( SW_NO3, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
1028 beep(10);
1029 if ( tm.Day == 1 ) {
1030 tm.Day = 31;
1031 } else {
1032 tm.Day--;
1033 }
1034 display_time( makeTime( tm ), DISPLAY_DATE );
1035 }
1036 //------ exit ----------
1037 if ( sw_on_test( SW_NO1, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME) ) {
1038 break;
1039 }
1040 }
1041 beep(100);
1042
1043 return makeTime( tm );
1044 }
1045
1046 //-------------------------------------------------------------------------------
1047 // input calibration time
1048 //-------------------------------------------------------------------------------
1049 void input_calibration()
1050 {
1051 int calibration_time;
1052
1053 calibration_time = EEPROM.read( EEPADDR_CALIBRATION_TIME );
1054 if ( EEPROM.read( EEPADDR_CALIBRATION_SIGN ) == '-' ) {
1055 calibration_time = -calibration_time;
1056 }
1057 display_calibration( calibration_time );
1058 while ( true ) {
1059 //----- increment -------------
1060 if ( sw_on_test( SW_NO2, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
1061 beep(10);
1062 if ( calibration_time < 99 ) {
1063 calibration_time++;
1064 }
1065 display_calibration( calibration_time );
1066 }
1067 //----- decrement -------------
1068 if ( sw_on_test( SW_NO3, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
1069 beep(10);
1070 if ( calibration_time > -99 ) {
1071 calibration_time--;
1072 }
1073 display_calibration( calibration_time );
1074 }
1075 //------ exit ----------
1076 if ( sw_on_test( SW_NO1, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME) ) {
1077 if ( calibration_time < 0 ) {
1078 EEPROM.write( EEPADDR_CALIBRATION_SIGN, '-' );
1079 EEPROM.write( EEPADDR_CALIBRATION_TIME, (byte)(-calibration_time) );
1080 } else {
1081 EEPROM.write( EEPADDR_CALIBRATION_SIGN, '+' );
1082 EEPROM.write( EEPADDR_CALIBRATION_TIME, (byte)(calibration_time) );
1083 }
1084 crc_eeprom_write();
1085 break;
1086 }
1087 }
1088 }
1089
1090 //-------------------------------------------------------------------------------
1091 // input 12hour / 24hour format
1092 //-------------------------------------------------------------------------------
1093 void input_hour_format()
1094 {
1095 byte format;
1096
1097 format = EEPROM.read( EEPADDR_DISPLAY_FORMAT );
1098 display_hour_format( format );
1099
1100 while ( true ) {
1101 //----- toggle -------------
1102 if( sw_on_test( SW_NO2, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ||
1103 sw_on_test( SW_NO3, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME ) ) {
1104 beep(10);
1105 if( format == DISPLAY_12HOUR ) {
1106 format = DISPLAY_24HOUR;
1107 } else {
1108 format = DISPLAY_12HOUR;
1109 }
1110 display_hour_format( format );
1111 }
1112 //------ exit ----------
1113 if ( sw_on_test( SW_NO1, SW_DEFAULT_ON_TIME, SW_DEFAULT_OFF_TIME) ) {
1114 EEPROM.write( EEPADDR_DISPLAY_FORMAT, format );
1115 crc_eeprom_write();
1116 break;
1117 }
1118 }
1119 }
1120
1121 //-------------------------------------------------------------------------------
1122 // CRC check
1123 //-------------------------------------------------------------------------------
1124 word crc16( word crc, char str[], int len )
1125 {
1126 const word CRC_CCITT = 0x8408;
1127 byte i;
1128 byte j;
1129 word tmp_word;
1130
1131 crc = ~crc;
1132 for ( i = 0 ; i <= (len - 1) ; i++ ) {
1133 tmp_word = str[i];
1134 crc = crc ^ tmp_word;
1135 for ( j = 0 ; j <= 7 ; j++ ) {
1136 if ( crc & 1 ) {
1137 crc = (crc >> 1) ^ CRC_CCITT;
1138 } else {
1139 crc >>= 1;
1140 }
1141 }
1142 }
1143
1144 return ~crc;
1145 }
1146
1147 //-------------------------------------------------------------------------------
1148 // HEX to char
1149 //-------------------------------------------------------------------------------
1150 char hex2char( byte hex_value )
1151 {
1152 if ( hex_value <= 9 ) {
1153 return hex_value + '0';
1154 } else {
1155 return hex_value - 10 + 'A';
1156 }
1157 }
1158
1159 //-------------------------------------------------------------------------------
1160 // char to HEX
1161 //-------------------------------------------------------------------------------
1162 byte char2hex( char ch )
1163 {
1164 if ( ch <= '9' ) {
1165 return ch - '0';
1166 } else {
1167 return ch - 'A' + 10;
1168 }
1169 }
1170
1171 //------------------------------------------------------------------------------------------
1172 // calc eeprom crc
1173 //------------------------------------------------------------------------------------------
1174 word crc_eeprom()
1175 {
1176 byte eeprom_counter;
1177 char eep_str[EEPROM_DATA_SIZE];
1178
1179 for ( eeprom_counter = 0 ; eeprom_counter < EEPROM_DATA_SIZE ; eeprom_counter++ ) {
1180 eep_str[eeprom_counter] = EEPROM.read( eeprom_counter );
1181 }
1182
1183
行番号
解説
全体
リアルタイムクロックDS1307のライブラリーはOUTピンの出力機能がなかったので使用していません
40-42
定義のいくつかは使われていない
113
アラームの鳴動パターン
115
シリアル入力のバッファー 名称がGPSになっているのはこのプログラムの元ネタのネオン管時計の名残
126-131
この変数にVFDの点灯パターンを書き込んで display_refresh() を呼び出すと表示が更新される
147
リアルタイムクロックのOUTピン出力による1Hz割り込み
158
タイマー割り込み MsTimer2による
178
スイッチを押したとき放すまでそのスイッチが有効にならないようにする処理。この面倒な処理を入れないとスイッチを押したときの処理がスイッチを押し続けている限り何回も実行されてしまう
221
アラームブザーが鳴っている間もスイッチの入力は受け付けないといけないので(そうしないとアラームを停止できない)割り込み処理内でブザーを鳴らしている
246
シリアル入力割り込み
258
一行分のデータを受信完了するとgps_buffer_fullがTrueになる
568-604
VFDの点灯パターン。使われていないものも多い
659-661
| Digit_DP を取り去ると日時表示の小数点が点灯しなくなる
1183
このホームページの制約でソース全体を表示できないのでこれ以降は現物を見てください。行番号などずれているかもしれません
1124
プログラムを更新したときにEEPROMを初期化する方法がArduinoには存在しない。そのためEEPROMのcrc(チェックサムのこと)を計算してそれが一致しなかったらEEPROMのデータ構造に変化が有ったとしてEEPROMを初期化している。EEPROM.writeをしたらcrc_eeprom_write()を呼び出しcrcを更新する必要がある。これを怠るとEEPROMの内容が初期値に戻ってしまう
1374
86400は1日の秒数。これを大きくすると校正の精度を上げることができる。2倍にすれば2日あたり何秒進むか/遅れるか になる。1587行目にも同じものがある
ご参考 プログラム開発や回路変更が出来る人向け情報
ファイル ファイルタイプ 添付ファイルの解説
VFD_CLOCK_eagle.zip EAGLE EAGLEV4.15以上用の回路図&基板レイアウト
schimgL.png PNG 大きな回路図
VFDClockVBall.zip OTHER 時刻同期プログラムソースなど一式 VisualStudio2010 BASIC
注意!! ネオン管時計のプログラムを微修正したものなのでその名残で無駄なデータ構造がある