セラロックの精度によるPIC時計をブレッドボード上に組んでみました。
動かし始めたのは23:38で、4:31に誤差を確認しました。
経過時間は293分で、PIC時計は14分遅れました。
誤差は5%近くなります。
セラロックの精度は±0.5%なので、10倍も誤差が大きいので他の要因が大きいのかも知れません。
回路図は以下の通りです。LEDに付けた抵抗はすべて1.2kΩです。
動かしたのは以下のソースコード(動かしたありのままで整理していないので、途中でテスト的に入れた意味のないコードも入っています)。
コンパイラはHI-TECH C PRO Liteモードです。
#include <pic.h> __CONFIG(XT & WDTDIS & PWRTEN & BOREN & LVPDIS & UNPROTECT); // タイマーの設定 #define PERIOD 1000000 // period in uS - one second here #define XTAL 4000000 // crystal frequency - 4MHz #define IPERIOD (4 * 1000000 / XTAL) // Period of instruction clock in uSeconds #define SCALE 256 // Timer 0 prescaler #define T0_TICKS 256 // Number of counts for interrupt #define TICK_PERIOD (SCALE * IPERIOD) // Period (uSec) of one increment of timer 0 #define RELOADS ((PERIOD/T0_TICKS)/TICK_PERIOD) near char reload = 0; // GLOBALS unsigned char counter1 = 0; unsigned char dp; unsigned char sec = 0; unsigned char min = 0; unsigned char hour = 0; unsigned char selector = 0; void interrupt timer0_proc(void) { if(reload == 0){ // effect a change on PORTB whenever our desired period is reached. // Note this timing will contain a margin of error. reload = RELOADS + 1; sec++; if (sec > 59) { sec = 0; min++; if (min > 59) { min = 0; hour++; if (hour > 23) { hour = 0; } } } RB0 = !RB0; RB1 = !RB1; } reload--; T0IF = 0; } void delay(unsigned char t) { for (unsigned char a = 0; a < t; a++) { for (unsigned char b = 0; b < 255; b++) { } } } void selectDigit(unsigned char sel) { switch (sel) { case 0: RC0 = 0; RC1 = 1; RC2 = 1; RC3 = 1; break; case 1: RC0 = 1; RC1 = 0; RC2 = 1; RC3 = 1; break; case 2: RC0 = 1; RC1 = 1; RC2 = 0; RC3 = 1; break; case 3: RC0 = 1; RC1 = 1; RC2 = 1; RC3 = 0; break; default: RC0 = 1; RC1 = 1; RC2 = 1; RC3 = 1; return; } } void outputDigit(unsigned char val) { switch (val) { case 0: RD0 = 1; RD1 = 1; RD2 = 1; RD3 = 1; RD4 = 1; RD5 = 1; RD6 = 0; break; case 1: RD0 = 0; RD1 = 1; RD2 = 1; RD3 = 0; RD4 = 0; RD5 = 0; RD6 = 0; break; case 2: RD0 = 1; RD1 = 1; RD2 = 0; RD3 = 1; RD4 = 1; RD5 = 0; RD6 = 1; break; case 3: RD0 = 1; RD1 = 1; RD2 = 1; RD3 = 1; RD4 = 0; RD5 = 0; RD6 = 1; break; case 4: RD0 = 0; RD1 = 1; RD2 = 1; RD3 = 0; RD4 = 0; RD5 = 1; RD6 = 1; break; case 5: RD0 = 1; RD1 = 0; RD2 = 1; RD3 = 1; RD4 = 0; RD5 = 1; RD6 = 1; break; case 6: RD0 = 1; RD1 = 0; RD2 = 1; RD3 = 1; RD4 = 1; RD5 = 1; RD6 = 1; break; case 7: RD0 = 1; RD1 = 1; RD2 = 1; RD3 = 0; RD4 = 0; RD5 = 0; RD6 = 0; break; case 8: RD0 = 1; RD1 = 1; RD2 = 1; RD3 = 1; RD4 = 1; RD5 = 1; RD6 = 1; break; case 9: RD0 = 1; RD1 = 1; RD2 = 1; RD3 = 1; RD4 = 0; RD5 = 1; RD6 = 1; break; default: RD0 = 0; RD1 = 0; RD2 = 0; RD3 = 0; RD4 = 0; RD5 = 0; RD6 = 0; break; } } void outputDP(unsigned char dp) { if (dp) { RD7 = 1; } else { RD7 = 0; } } int main() { // 時間設定 hour = 23; min = 38; // ポートの設定 TRISB = 0xFC; // 0, 1 出力 TRISC = 0xF0; // 0, 1, 2, 3 出力 TRISD = 0x00; // 全部出力 // ポートの初期化 RB0 = 1; RB1 = 0; RC0 = 1; RC1 = 1; RC2 = 1; RC3 = 1; // タイマー1の設定 OPTION = 0b0111; // prescale by 256 T0CS = 0; // select internal clock T0IE = 1; // enable timer interrupt GIE = 1; // enable global interrupts while (1) { dp = sec % 2; selectDigit(99); outputDigit(10); outputDP(0); selectDigit(selector++); outputDigit(min % 10); outputDP(dp); delay(1); selectDigit(99); outputDigit(10); outputDP(0); selectDigit(selector++); outputDigit(min / 10); outputDP(0); delay(1); selectDigit(99); outputDigit(10); outputDP(0); selectDigit(selector++); outputDigit(hour % 10); outputDP(0); delay(1); selectDigit(99); outputDigit(10); outputDP(0); selectDigit(selector++); outputDigit(hour / 10); outputDP(0); delay(1); counter1++; if (counter1 > 120) { counter1 = 0; } selector = 0; } return 0; }