セラロックの精度による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;
}

