[2004/05/09 11:35:24]
この連休に残っていた PIC16C84(今なら PIC16F84A でしょうね? これも古いかも)を使っての長時間(9時間59分)用のタイマーを作りました。これは秋月のソリッドステートリレー(SSR)の制御に使う目的で作った物です。水晶発振子が無かったので発振周波数は正確ではないのですが10MHz のセラミック発振子を使っています。周波数が正確でなくてもプログラムによる調節で最長時間で1秒以内の誤差におさめることができます。
作ったAC100Vタイマー
● 回路図
時分の表示は7セグメントのLED3個を HC4511 でデコードしダイナミック点灯で使用しています。表示は時分です。秒も表示したかったら BCD-DEC デコーダ回路を追加して下さい。ソリッドステートリレーは秋月のキットで T20C6F を使った物です。
あとは特に変わった点は無いと思います。
● 動作
電源を投入すると LED に 2.00 と表示されます(デフォルトで2時間タイマーになっている)。左側のスイッチを上に倒すと1時間だけタイマー時間が増加します。逆に手前に倒すと1時間減少します。右のスイッチは同様に分の設定です。よって最大設定時間は9時間59分です。タイマー時間を設定したら右のプッシュスイッチを押してタイマーを動作させます。もう一度プッシュするとタイマーは一時停止します。一時停止中は出力がオフになります。また一時停止中に再度タイマー時間の設定ができます。一時停止だけであれば秒は保持されますがタイマー時間を再設定すると秒はクリアされます。
AC はゼロクロスのソリッドステートリレーを使っているのでタイマーのオンオフでノイズは発生しないと思われます(たぶん!)。流す事が出来る電流は T20C6F を使っているので最大 20A となっています。 T20C6F は結構発熱するのでケースで放熱しています。安全を考えると 5A 程度にしたほうが良いのでは。
動作に関してはプログラムでどうにでもなるので目的に合わせて改造して下さい。
● その他
作るに要した日数は二日、費用約4千円。買った方が安く、早く、高機能のタイマーが手に入ったでしょう。作っている間は何とも思わないのに完成するとまた無駄金を使ってしまったと反省してしまいます(いつもの事です)。
ハードとソフトは一日で出来ますが時間の調整に時間がかかります。タイマーをセットし、ずれた時間から微調整のための定数を計算します。これを2〜3回繰返さないと正確な時間を刻んでくれません。面倒な作業です。最初から水晶にしたほうが簡単だったかもしれません。
● プログラム
プログラムは CCS の PIC C Compiler を使っています。というか、楽なCを使ってしまうともうアセンブラには戻れない頭になってしまいました。
タイマーカウントには RTCC 割込みを使っています。 10000000/4/256/256 = 38.1470 Hz の割り込みなので 38回の割り込みで1秒になります。割り切れない値は後で調整。実際の発振周波数が 10MHz より少し高かったので調整では3秒に一回と18秒に一回、39回の割込みで1秒を作っています。また微調整で18分(1115回の割込み)毎に1秒を作るのに37回の割り込みにしています(ややこしいですね!)。この調整で最長タイマー時間(9時間59分)設定で誤差は1秒以下になりました。たぶん使用環境の室温によって発振周波数が変化するはずなので正確の所は不明です。
さて、実際のプログラムは下記のようにしました(参考にはならないと思いますが)。
// Timer // 2004/05/07 by Nishimura Hiromi #include <16C84.h> #use delay(CLOCK=10000000) // #define Amode 0x0f //port A initial mode #define Bmode 0x01 //port B initial mode #byte DISPLAY = 6 // #define HR_UP PIN_A0 // input #define HR_DN PIN_A1 // input #define MIN_UP PIN_A2 // input #define MIN_DN PIN_A3 // input #define T_OUT PIN_A4 // output #define START_STOP PIN_B0 // input // #define ins_sec 38 #define trim_count 1115 // 38 byte SEC; byte MIN; byte HUR; byte COUNT; byte DISP_PIN; byte STATUS; long TRIM; // #define TOUT_OFF output_high(T_OUT) #define TOUT_ON output_low(T_OUT) // #INT_RTCC clock() { if(STATUS==1){ if(COUNT==0) { if(SEC==0){ if(MIN==0){ if(HUR==0){ STATUS = 0; TOUT_OFF; return 0; } else HUR--; MIN = 59; } else MIN--; SEC = 59; } else SEC--; COUNT = ins_sec; // おおまかな調節 if((SEC-(SEC/3)*3)==0) COUNT++; if((SEC-(SEC/18)*18)==0) COUNT++; } // 微妙な調節 TRIM--; if(TRIM==0){ TRIM = trim_count; COUNT--; if(COUNT==0) COUNT++; } COUNT --; } } // LED のダイナミック点灯 // 残り時間が1分以内になったら残り時間を秒で表示 disp_led() { int dsp; int xxx; int yyy; if(HUR==0&&MIN==0&&STATUS==1&&SEC!=0){ xxx = SEC; yyy = 10; } else{ xxx = MIN; yyy = HUR; } if(DISP_PIN==2) dsp = (xxx - (xxx/10)*10)<<4; else if(DISP_PIN==4) dsp = (xxx/10)<<4; else dsp = yyy<<4; DISPLAY = dsp | DISP_PIN; DISP_PIN = DISP_PIN<<1; if(DISP_PIN>8) DISP_PIN = 2; } // resetValiables() { TOUT_OFF; SEC = 0; MIN = 0; HUR = 2; COUNT = ins_sec; DISP_PIN= 2; STATUS = 0; TRIM = trim_count; } // init_timer() { set_tris_a(Amode); set_tris_b(Bmode); resetValiables(); } // プログラム領域が余ったので電源オン時に 123 200 を表示するようにした。 initial_disp() { int i; HUR = 0; MIN = 1; for(i=0;i<100;i++) {disp_led(); delay_ms(5);} HUR = 0; MIN = 12; for(i=0;i<100;i++) {disp_led(); delay_ms(5);} HUR = 1; MIN = 23; for(i=0;i<100;i++) {disp_led(); delay_ms(5);} HUR = 2; MIN = 30; for(i=0;i<100;i++) {disp_led(); delay_ms(5);} HUR = 3; MIN = 00; for(i=0;i<100;i++) {disp_led(); delay_ms(5);} HUR = 0; MIN = 02; for(i=0;i<100;i++) {disp_led(); delay_ms(5);} HUR = 0; MIN = 20; for(i=0;i<100;i++) {disp_led(); delay_ms(5);} HUR = 2; MIN = 00; for(i=0;i<100;i++) {disp_led(); delay_ms(5);} resetValiables(); } // main() { init_timer(); initial_disp(); set_rtcc(0); setup_counters( RTCC_INTERNAL, RTCC_DIV_256); enable_interrupts(RTCC_ZERO); enable_interrupts(GLOBAL); while(1){ if(input(START_STOP)==0){ if(STATUS==0) COUNT = ins_sec; if(SEC==0 && MIN==0 && HUR==0){ STATUS = 0; TOUT_OFF; } else { STATUS = 1; TOUT_ON; } } else { STATUS = 0; TOUT_OFF; if(input(HR_UP)==0){ delay_ms(5); if(input(HR_UP)==0){ HUR++; if(HUR>9) HUR = 0; while(input(HR_UP)==0) {disp_led(); delay_ms(5);} SEC = 0; COUNT = ins_sec; } } else if(input(HR_DN)==0){ delay_ms(5); if(input(HR_DN)==0){ HUR--; if(HUR>9) HUR = 9; while(input(HR_DN)==0) {disp_led(); delay_ms(5);} SEC = 0; COUNT = ins_sec; } } else if(input(MIN_UP)==0){ delay_ms(5); if(input(MIN_UP)==0){ MIN++; if(MIN>59) MIN = 0; while(input(MIN_UP)==0) {disp_led(); delay_ms(5);} SEC = 0; COUNT = ins_sec; } } else if(input(MIN_DN)==0){ delay_ms(5); if(input(MIN_DN)==0){ MIN--; if(MIN>59) MIN = 59; while(input(MIN_DN)==0) {disp_led(); delay_ms(5);} SEC = 0; COUNT = ins_sec; } } } disp_led(); delay_ms(5); } }