/* * * 時計プログラム * 2008 nazo-fjt.com * by Hiroshi FJT * * Device=PIC16F877/877A * * 2008/05/13 Ver.01.03.04 * */ #include /* define設定 */ #define TimIntLoop 100 /* 0.5秒を生成する為のタイマー割り込み回数 */ #define IdleLoopCount 120 /* 時間稼ぎループ回数(0-255) */ #define SwPushCount 5 /* SWが押されたと認識するカウント数 */ #define SwLongCount 660 /* SWが長押しされたと認識するカウント数 */ #define SwContenuCount 110 /* SWが長押しが継続されたと認識するカウント数 */ #define HourSec 3600 /* 一時間の秒数(ソフトウエアキャリブレーション用) */ #define DispBlank 30 /* 表示ブランク時間調整ループカウンタ */ /* コンフィグビット設定 */ __CONFIG(UNPROTECT & PWRTEN & WDTDIS & XT & LVPDIS & BORDIS); /* EEPROM */ __EEPROM_DATA(7,0,9,0,12,0,13,0); __EEPROM_DATA(14,0,15,0,59,5,59,10); __EEPROM_DATA(0,0,0,0xff,0xff,1,3,4); /********************************************************************/ /* プロトタイプ宣言 */ /********************************************************************/ /* I/O処理レイヤー */ void DispOut(void); void SWscan(void); void IntTimer(void); /* イベント通知レイヤー */ void InitDone(void); /* 初期化終了通知 */ void SW1Long(void); /* SW1(mode) */ void SW1Rel(void); void SW2Push(void); /* SW2(hh) */ void SW3Push(void); /* SW3(mm) */ void SW4Push(void); /* SW4(m) */ void SW5Push(void); /* SW5(SecReset) */ void SW6Long(void); /* SW6(Alm1 Snooze/Stop) */ void SW6Rel(void); void SW7Long(void); /* SW7(Alm2 Snooze/Stop) */ void SW7Rel(void); void HalfSec(void); /* 0.5sec通知 */ void LoopEvnt(void); /* loopイベント通知 */ /* アプリ処理レイヤー */ void ClockProc(void); /* 現在時刻処理 */ void ClockDisp(void); /* 表示指示 */ void AlmTimeOut(void); /* アラーム&タイマ処理 */ /* アプリ利用関数 */ /* 時刻調整用加算共有処理 */ unsigned char AddHH(unsigned char WHH); unsigned char AddMM(unsigned char WMM); unsigned char AddM(unsigned char WM); unsigned char AddMM2(unsigned char WMM); /* 表示内容渡し */ void Display(unsigned char D12,unsigned char D34,unsigned char D56,unsigned char DispMode); /* EEPROM */ void SaveEEPROM(void); void LoadEEPROM(void); /********************************************************************/ /* グローバル変数定義 */ /********************************************************************/ /* システム利用変数 */ /* 表示 */ unsigned char D1; unsigned char D2; unsigned char D3; unsigned char D4; unsigned char D5; unsigned char D6; bit DP2; bit DP4; bit DP6; bit DAM; bit DPM; /* SW status */ /* 0 - open * 1 - push * 2 - long push * 3 - long push contenues */ unsigned char SW1status; unsigned char SW2status; unsigned char SW3status; unsigned char SW4status; unsigned char SW5status; unsigned char SW6status; unsigned char SW7status; /* ソフトウエアキャリブレーション用 */ unsigned char SC1; /* 1秒単位 */ unsigned char SC2; /* 1/100秒単位 */ unsigned int SCset; /* 設定値 */ bit SCPM; /* 方向 0:進める 1:遅らせる */ unsigned int SCcount; /* 実行用カウンタ */ bit SCflag; /* 実行フラグ */ /* アプリ利用変数 */ /* 時刻 */ unsigned char NowHH; unsigned char NowMM; unsigned char NowSS; bit NowHS; /* Alarm Timer設定時刻 */ unsigned char A1HH; unsigned char A1MM; unsigned char A1onMM; unsigned char A1snooze; unsigned char A2HH; unsigned char A2MM; unsigned char A2onMM; unsigned char A2snooze; unsigned char T1onHH; unsigned char T1onMM; unsigned char T1offHH; unsigned char T1offMM; unsigned char T2onHH; unsigned char T2onMM; unsigned char T2offHH; unsigned char T2offMM; /* Alarm停止時刻・snooz時刻処理用 */ unsigned char S1HH; unsigned char S1MM; unsigned char A1offHH; unsigned char A1offMM; unsigned char S2HH; unsigned char S2MM; unsigned char A2offHH; unsigned char A2offMM; /* snooze待機フラグ */ bit S1waiting; bit S2waiting; /* mode */ /* Disp Set * 0 - Nomal mode * 50 - Adjust mode * 11 61 - Alarm1 set mode * (12) 62 - Alarm1 on time mode * (13) 63 - Alarm1 snooze time mode * 21 71 - Alarm2 set mode * (22) 72 - Alarm2 on time mode * (23) 73 - Alarm2 snooze time mode * 31 81 - Timer1 on set mode * 32 82 - Timer1 off set mode * 43 91 - Timer2 on set mode * 42 92 - Timer2 off set mode * 99 - Software calibration */ unsigned char SetMode; /* Alm SW notify */ /* 0 - non * 1 - snooze * 2 - stop */ unsigned char A1SWnotif; unsigned char A2SWnotif; /* 秒リセットフラグ */ bit SecRstFlg; /********************************************************************/ /* システムレイヤー */ /********************************************************************/ /* メイン */ void main() { unsigned char i; /* PIC初期化 */ /* デフォルト値のままでいいところはコメントアウトしておく */ /************ I/O設定 ************/ /* ADコンバータの機能を殺す */ /* PORTAとPORTEを汎用I/Oとして使うため */ /* デフォルトではA/DコンバータはDisableなのにポート設定はアナログ入力になっている */ // ADCON0=0b00000000; ADCON1=0b00000110; /* * 7 6 5 4 3 2 1 0 * RA - - O/NC I/SW5 I/SW4 I/SW3 I/SW2 I/SW1 * RB O/colC O/colB O/colA O/D.P. O/numD O/numC O/numB O/numA * RC O/T2 O/T1 O/A2 O/A1 O/1Hz O/Test O/Test O/NC * RD I/SW12 ISW11 I/SW10 I/SW9 O/NC I/SW8 I/SW7 I/SW6 * RE - - - - - O/PM O/AM O/DispEna * * TRISx 0 output * 1 input * bit76543210 */ // TRISA=0b00011111; TRISB=0b00000000; TRISC=0b00000000; // TRISD=0b11110111; TRISE=0b00000000; /* ↑PORTAとPORTDは一部未使用なためOUTPUTにしておく予定だったが */ /* ポートをまとめてプルアップしているのでデフォルトのままにしておく */ RE0=0; PORTC=0; /* システム変数初期化 */ SW1status=0; SW2status=0; SW3status=0; SW4status=0; SW5status=0; SW6status=0; SW7status=0; /************ タイマ設定 ************/ /* * Clock * 3.2768MHz * | * 1/4 (819.200KHz) * | * Prescaler * 1/16 (51.200KHz) * | * TMR2 Reg ---Comparator--- PR2 Reg * 0-255 1/(PR2+1) 127 * (400Hz) * | * Postscaler * 1/2 * | * 200Hz * Postscaler * +-------- TOUTPS3 0000: 1/1 * |+------- TOUTPS2 0001: 1/2 * ||+------ TOUTPS1 : * |||+----- TOUTPS0 1111: 1/16 * |||| * ||||+---- TMR2ON 0:Stop 1:Start * ||||| * ||||| Prescaler * |||||+--- T2CKPS1 00: 1/1 * ||||||+-- T2CKPS0 01: 1/4 * |--|||| 1x: 1/16 */ T2CON=0b00001111; PR2=127; /************ 割り込み設定フラグ設定 ************/ /* PIE1 * +----TMR2IE * | */ PIE1=0b00000010; /* PIE2 */ //PIE2=0b00000000; /* INTCON * +---- GIE * |+--- PEIE * || */ INTCON=0b11000000; /* 初期化終了通知呼び出し */ InitDone(); /* Idol Loop */ while(1) { /* TestOutをHにする */ RC2=1; /* 表示実行 */ DispOut(); /* SW Sclan呼び出し */ SWscan(); /* loopイベント通知 */ LoopEvnt(); /* TestOutをLにする */ RC2=0; /* 時間稼ぎループ */ i=0; do{ i++; }while(i=10){ /* D12の内容が10以上の場合表示抑止 */ k=0; PORTB=0b00100000+16*DP2+0; }else{ PORTB=0b00100000+16*DP2+D2; } break; case 2: PORTB=0b01000000+D3; break; case 3: PORTB=0b01100000+16*DP4+D4; break; case 4: PORTB=0b10000000+D5; break; case 5: PORTB=0b10100000+16*DP6+D6; break; } /* ブランク時間調整ループ */ j=0; do{ j++; }while(j=SCcount){ SCflag=1; RC0=1; TSCcount=0; } } } /********************************************************************/ /* loopイベント通知 */ void LoopEvnt(void) { /* 通常モードでSW3とSW4が同時長押し継続でキャリブレーションモード突入 */ if(SetMode==0 && SW3status==3 && SW4status==3){SetMode=99;} /* 表示内容指示 */ ClockDisp(); } /********************************************************************/ /* アプリ処理レイヤー */ /********************************************************************/ /* 現在時刻処理 */ void ClockProc(void) { NowSS++; /* 時刻計算 */ if(NowSS==60){ NowSS=0; NowMM++; if(NowMM==60){ NowMM=0; NowHH++; if(NowHH==24){ NowHH=0; } } } } /********************************************************************/ /* 表示内容指示(Loopイベント毎) */ /* SW押下時に設定内容を即時表示更新 */ /* モードによる表示内容を表示メモリに渡す */ /* 共通する処理は外部に持っていく */ void ClockDisp(void) { char TSetMode; /* 分岐条件を減らすためのモード選択用変数 */ /* switch〜caseは条件が増えるほどメモリを消費する */ DP6=NowHS; if(SetMode<50){ /* 50未満のモード(表示モード+現在時刻)はそのまま渡す */ /* 小数点は常時点灯 */ DP2=1; DP4=1; TSetMode=SetMode; }else{ /* 50以上のモード(現在時刻・アラーム・タイマ設定)はそのまま渡すSetModeから50引く */ /* 表示モードと設定モードは数字が50違う */ /* 小数点はNowHSを代入して点滅させる */ DP2=NowHS; DP4=NowHS; TSetMode=SetMode-50; } switch(TSetMode) { case 0: Display(NowHH,NowMM,NowSS,0); break; case 11: Display(A1HH,A1MM,61,0); break; case 12: Display(0,A1onMM,62,1); D2=15; /* 表示メモリD2の10以上を設定して表示消灯 */ break; case 13: Display(0,A1snooze,63,1); D2=15; /* 表示メモリD2の10以上を設定して表示消灯 */ break; case 21: Display(A2HH,A2MM,71,0); break; case 22: Display(0,A2onMM,72,1); D2=15; /* 表示メモリD2の10以上を設定して表示消灯 */ break; case 23: Display(0,A2snooze,73,1); D2=15; /* 表示メモリD2の10以上を設定して表示消灯 */ break; case 31: Display(T1onHH,T1onMM,81,0); break; case 32: Display(T1offHH,T1offMM,82,0); break; case 41: Display(T2onHH,T2onMM,91,0); break; case 42: Display(T2offHH,T2offMM,92,0); break; case 49: Display(SC1,SC2,99,1); DP2=0; if(SCPM==0){DAM=0;DPM=0;}else{DAM=1;DPM=1;} } } /********************************************************************/ /* アラーム&タイマ処理*/ void AlmTimeOut(void) { /* 入力 * RD0 : Alarm1 snooze * RD1 : Alarm2 snooze * * RD4 : Alarm1 on * RD5 : Alarm2 on * RD6 : Timer1 on * RD7 : Timer2 on * * 出力 * RC4 : Alarm1 out * RC5 : Alarm2 out * RC6 : Timer1 out * RC7 : Timer2 out */ /* 時刻設定中にアラーム・タイマーが誤動作しないよう、表示モード以外の時は処理をしない */ if(SetMode>=50){return;} /*===============================================================*/ /* Alarm1処理 */ if(RD4==0){ /* RD4=L(Alarm1SW=on)のとき */ if(RC4==0){ /* RC4(Alarm1)=Lのとき、ON時刻と比較してRC4=HにしてOFF時刻を設定する */ if(NowHH==A1HH && NowMM==A1MM && NowSS==0){RC4=1;} if(S1waiting==1 && NowHH==S1HH && NowMM==S1MM && NowSS==0){RC4=1;} if(RC4==1){ S1waiting=0; A1offMM=NowMM+A1onMM; A1offHH=NowHH; if(A1offMM>=60){ A1offMM=A1offMM-60; A1offHH++; if(A1offHH>=24){A1offHH=A1offHH-24;} } } }else{ /* RC4(Alarm1)=Hのとき、OFF時刻もしくはSW状態通知を確認してRC4=Lにする */ /* Snoozeの場合は次回時刻を設定してスヌーズフラグを立てる */ if(NowHH==A1offHH && NowMM==A1offMM){RC4=0;} if(A1SWnotif==2){RC4=0;} if(A1SWnotif==1){ RC4=0; S1waiting=1; S1MM=NowMM+A1snooze; S1HH=NowHH; if(S1MM>=60){ S1MM=S1MM-60; S1HH++; if(S1HH>=24){S1HH=S1HH-24;} } } } }else{ /* RD4=H(Alarm1SW=off)のとき、スヌーズフラグを倒してRC4(Alarm1)をLにする */ RC4=0; S1waiting=0; } /* SW状態通知をクリアする */ A1SWnotif=0; /*===============================================================*/ /* Alarm2処理 */ if(RD5==0){ /* RD5=L(Alarm2SW=on)のとき */ if(RC5==0){ /* RC5(Alarm2)=Lのとき、ON時刻と比較してRD4=HにしてOFF時刻を設定する */ if(NowHH==A2HH && NowMM==A2MM && NowSS==0){RC5=1;} if(S2waiting==1 && NowHH==S2HH && NowMM==S2MM && NowSS==0){RC5=1;} if(RC5==1){ S2waiting=0; A2offMM=NowMM+A2onMM; A2offHH=NowHH; if(A2offMM>=60){ A2offMM=A2offMM-60; A2offHH++; if(A2offHH>=24){A2offHH=A2offHH-24;} } } }else{ /* RC5(Alarm2)=Hのとき、OFF時刻もしくはSW状態通知スを確認してRC5=Lにする */ /* Snoozeの場合は次回時刻を設定してスヌーズフラグを立てる */ if(NowHH==A2offHH && NowMM==A2offMM){RC5=0;} if(A2SWnotif==2){RC5=0;} if(A2SWnotif==1){ RC5=0; S2waiting=1; S2MM=NowMM+A2snooze; S2HH=NowHH; if(S2MM>=60){ S2MM=S2MM-60; S2HH++; if(S2HH>=24){S2HH=S2HH-24;} } } } }else{ /* RD5=H(Alarm2SW=off)のとき、スヌーズフラグを倒してRC5(Alarm2)をLにする */ RC5=0; S2waiting=0; } /* SW状態通知をクリアする */ A2SWnotif=0; /*===============================================================*/ /* Timer1処理 */ if(RD6==0){ /* On設定時刻が現在時刻と一致した場合、RC6(Timer1 out)をHにする */ if(NowHH==T1onHH && NowMM==T1onMM && NowSS==0){RC6=1;} /* Off設定時刻が現在時刻と一致した場合、RC6(Timer1 out)をLにする */ if(NowHH==T1offHH && NowMM==T1offMM){RC6=0;} }else{ /* RD6=H(Timer1がoff)のとき、RC6(Timer1 out)をLにする */ RC6=0; } /*===============================================================*/ /* Timer2処理 */ if(RD7==0){ /* On設定時刻が現在時刻と一致した場合、RC7(Timer2 out)をHにする */ if(NowHH==T2onHH && NowMM==T2onMM && NowSS==0){RC7=1;} /* Off設定時刻が現在時刻と一致した場合、RC7(Timer2 out)をLにする */ if(NowHH==T2offHH && NowMM==T2offMM){RC7=0;} }else{ /* RC7(Timer2 out)=HでRD7=H(Timer2がoff)のとき、RC7(Timer2 out)をLにする */ RC7=0; } } /********************************************************************/ /* アプリ利用関数 */ /********************************************************************/ unsigned char AddHH(unsigned char WHH) { /* 時の加算(時刻設定・キャリブレーション兼用) */ WHH++; if (WHH >= 24){ WHH=0; } return WHH; } /********************************************************************/ unsigned char AddMM(unsigned char WMM) { /* 10分の加算(時刻設定用) */ WMM=WMM+10; if (WMM >= 60){ WMM=WMM-60; } return WMM; } /********************************************************************/ unsigned char AddM(unsigned char WM) { /* 分の加算(時刻設定・キャリブレーション兼用) */ unsigned char WMM; WMM=WM/10; WMM=WMM*10; WM=WM-WMM; WM++; if (WM >= 10){ WM=0; } WM=WM+WMM; return WM; } /********************************************************************/ unsigned char AddMM2(unsigned char WMM) { /* 10の加算(キャリブレーション用) */ WMM=WMM+10; if (WMM >= 100){ WMM=WMM-100; } return WMM; } /********************************************************************/ /* 表示内容指示 */ /* 渡された引数を元に桁の分離、AM/PM処理等行い表示用メモリに格納 */ void Display(unsigned char D12,unsigned char D34,unsigned char D56,unsigned char DispMode) { if(DispMode==0){ /* 12h/24hの切り替え */ /* RD2 : SW8 L:12h H:24h */ if(RD2==0){ if(D12<12){ DAM=1; DPM=0; }else{ DAM=0; DPM=1; D12=D12-12; } if(D12==0){D12=12;} }else{ DAM=0; DPM=0; } }else{ DAM=0; DPM=0; } D1=D12/10; D2=D12-D1*10; D3=D34/10; D4=D34-D3*10; D5=D56/10; D6=D56-D5*10; } /********************************************************************/ /* EEPROMに設定値保存 */ void SaveEEPROM(void) { eeprom_write(0x00, A1HH); eeprom_write(0x01, A1MM); eeprom_write(0x02, A2HH); eeprom_write(0x03, A2MM); eeprom_write(0x04, T1onHH); eeprom_write(0x05, T1onMM); eeprom_write(0x06, T1offHH); eeprom_write(0x07, T1offMM); eeprom_write(0x08, T2onHH); eeprom_write(0x09, T2onMM); eeprom_write(0x0A, T2offHH); eeprom_write(0x0B, T2offMM); eeprom_write(0x0C, A1onMM); eeprom_write(0x0D, A1snooze); eeprom_write(0x0E, A2onMM); eeprom_write(0x0F, A2snooze); eeprom_write(0x10,SC1); eeprom_write(0x11,SC2); eeprom_write(0x12,SCPM); } /********************************************************************/ /* EEPROMから設定値取出 */ void LoadEEPROM(void) { A1HH = eeprom_read(0x00); A1MM = eeprom_read(0x01); A2HH = eeprom_read(0x02); A2MM = eeprom_read(0x03); T1onHH = eeprom_read(0x04); T1onMM = eeprom_read(0x05); T1offHH= eeprom_read(0x06); T1offMM= eeprom_read(0x07); T2onHH = eeprom_read(0x08); T2onMM = eeprom_read(0x09); T2offHH= eeprom_read(0x0A); T2offMM= eeprom_read(0x0B); A1onMM = eeprom_read(0x0C); A1snooze = eeprom_read(0x0D); A2onMM = eeprom_read(0x0E); A2snooze = eeprom_read(0x0F); SC1 = eeprom_read(0x10); SC2 = eeprom_read(0x11); SCPM = eeprom_read(0x12); /* 値が不正な場合はデフォルト値置き換え */ /* あらかじめデフォルト値を書き込んでいるが、 */ /* 書き込み中電源断などで不正値が書き込まれた時用 */ if(A1HH >= 24){A1HH = 7;} if(A1MM >= 60){A1MM = 0;} if(A2HH >= 24){A2HH = 9;} if(A2MM >= 60){A2MM = 0;} if(T1onHH >= 24){T1onHH = 12;} if(T1onMM >= 60){T1onMM = 0;} if(T1offHH >= 24){T1offHH= 13;} if(T1offMM >= 60){T1offMM= 0;} if(T2onHH >= 24){T2onHH = 14;} if(T2onMM >= 60){T2onMM = 0;} if(T2offHH >= 24){T2offHH= 15;} if(T2offMM >= 60){T2offMM= 0;} if(A1onMM >= 60){A1onMM = 59;} if(A1snooze >= 60){A1snooze = 5;} if(A2onMM >= 60){A2onMM = 59;} if(A2snooze >= 60){A2snooze = 10;} if(SC1 > 23){SC1=0;} if(SC2 > 99){SC2=0;} }