セラロックのみの見直しの失敗

PIC時計が「どうせ止まっているから・・・」と、この前見直したのを試してみた。
64×25×25×25というのを64×125×125として、プリスケールを64に、タイマー0のカウンターを256-125=131を設定して、タイマー0の関数でさらに125をカウントして、秒をカウントするようにしてテスト。
しかし、どうもあきらかに遅れる(-0.5秒/1分)。

本当はどこが悪いのかチェックしたいけど、精度が出る方法が別にあるので、機能追加の方に力をかけたいので、これで終わりにする。

この時点でのソースコードは以下。

#include <pic.h>

__CONFIG(XT & WDTDIS & PWRTEN & BOREN & LVPDIS & UNPROTECT);

#define USE_TIMER_0

// 現在の時間
#define CURRENT_HOUR	2
#define CURRENT_MIN		7

#ifdef USE_TIMER_1
// タイマー1の設定
#define SETTING_TIMER1_HI	0x80
#define SETTING_TIMER1_LO	0x02
#endif // USE_TIMER_1

#ifdef USE_TIMER_0
// タイマーの設定
#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	64		// Timer 0 prescaler
#define T0_TICKS 125	// 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 unsigned char reload = RELOADS;
#endif // USE_TIMER_0

// GLOBALS
unsigned char dp;
unsigned char sec = 0;
unsigned char min = 0;
unsigned char hour = 0;
unsigned char selector = 0;

#ifdef USE_TIMER_1
void interrupt timer1itr(void)
{
	TMR1L = SETTING_TIMER1_LO;
	TMR1H = SETTING_TIMER1_HI;
	TMR1IF = 0;
	sec++;
	if (sec > 59) {
		sec = 0;
		min++;
		if (min > 59) {
			min = 0;
			hour++;
			if (hour > 23) {
				hour = 0;
			}
		}
	}
}
#endif // USE_TIMER_1

#ifdef USE_TIMER_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.
#if 0
		if (sec & 1) {
			reload = RELOADS;
		} else if (sec & 2) {
			reload = RELOADS;
		} else {
			reload = RELOADS + 1;
		}
#else
		reload = RELOADS;
#endif
		sec++;
		if (sec > 59) {
			sec = 0;
			min++;
			if (min > 59) {
				min = 0;
				hour++;
				if (hour > 23) {
					hour = 0;
				}
			}
		}
	}
	TMR0 = 0x100 - T0_TICKS;
	reload--;
	T0IF = 0;
}
#endif // USE_TIMER_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:
		RB0 = 0;
		RB1 = 1;
		RB2 = 1;
		RB3 = 1;
		RB4 = 1;
		RB5 = 1;
		break;
	case 1:
		RB0 = 1;
		RB1 = 0;
		RB2 = 1;
		RB3 = 1;
		RB4 = 1;
		RB5 = 1;
		break;
	case 2:
		RB0 = 1;
		RB1 = 1;
		RB2 = 0;
		RB3 = 1;
		RB4 = 1;
		RB5 = 1;
		break;
	case 3:
		RB0 = 1;
		RB1 = 1;
		RB2 = 1;
		RB3 = 0;
		RB4 = 1;
		RB5 = 1;
		break;
	case 4:
		RB0 = 1;
		RB1 = 1;
		RB2 = 1;
		RB3 = 1;
		RB4 = 0;
		RB5 = 1;
		break;
	case 5:
		RB0 = 1;
		RB1 = 1;
		RB2 = 1;
		RB3 = 1;
		RB4 = 1;
		RB5 = 0;
		break;
	default:
		RB0 = 1;
		RB1 = 1;
		RB2 = 1;
		RB3 = 1;
		RB4 = 1;
		RB5 = 1;
		return;
	}
}

void outputDigit(unsigned char val)
{
	switch (val) {
	case 0:
		PORTD = 0b00111111;
		break;
	case 1:
		PORTD = 0b00000110;
		break;
	case 2:
		PORTD = 0b01011011;
		break;
	case 3:
		PORTD = 0b01001111;
		break;
	case 4:
		PORTD = 0b01100110;
		break;
	case 5:
		PORTD = 0b01101101;
		break;
	case 6:
		PORTD = 0b01111101;
		break;
	case 7:
		PORTD = 0b00000111;
		break;
	case 8:
		PORTD = 0b01111111;
		break;
	case 9:
		PORTD = 0b01101111;
		break;
	default:
		PORTD = 0;
		break;
	}
}

void outputDP(unsigned char dp)
{
	if (dp) {
		RD7 = 1;
	} else {
		RD7 = 0;
	}
}

int main()
{
	// 時間設定
	hour = CURRENT_HOUR;
	min = CURRENT_MIN;
	// ポートの設定
	TRISB = 0xC0;	// 0, 1, 2, 3, 4, 5 出力
	TRISD = 0x00;	// 全部出力
	// ポートの初期化
	RB4 = 1;
	RB5 = 0;
	RB0 = 1;
	RB1 = 1;
	RB2 = 1;
	RB3 = 1;
#ifdef USE_TIMER_1
	// タイマー1の設定
	TMR1CS = 1;	// 0=内部クロック、1=外部クロック
	T1CKPS1 = 0;
	T1CKPS0 = 0;
	T1OSCEN = 1;
	T1SYNC = 0;
	TMR1L = SETTING_TIMER1_LO;
	TMR1H = SETTING_TIMER1_HI;
	TMR1IF = 0;
	TMR1IE = 1;
	TMR1ON = 1;
	PEIE = 1;
	GIE = 1;
#endif // USE_TIMER_1
#ifdef USE_TIMER_0
	// タイマー0の設定
	OPTION = 0b0101;	// prescale by 111=256, 101=64
	TMR0 = 0x100 - T0_TICKS;
	T0CS = 0;			// select internal clock
	T0IE = 1;			// enable timer interrupt
	GIE = 1;			// enable global interrupts
#endif // USE_TIMER_0
	while (1) {
		dp = sec % 2;

		selectDigit(99);
		outputDigit(10);
		outputDP(0);
		selectDigit(selector++);
		outputDigit(sec % 10);
		outputDP(dp);
		delay(1);

		selectDigit(99);
		outputDigit(10);
		outputDP(0);
		selectDigit(selector++);
		outputDigit(sec / 10);
		outputDP(0);
		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(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);

		selector = 0;
	}
	return 0;
}
カテゴリー: PIC, プロトタイプ タグ: , パーマリンク

セラロックのみの見直しの失敗 への4件のフィードバック

  1. 加藤 慎一郎 のコメント:

     ただいまPICで7SEGダイナミック表示時計を作っていまして、誤差に挑戦してます。  x’talは温度保障なしの19.6608MHzを使用して、TMR0フリーラン(256)で
    プリスケーラは1/4です。  割り込みでは4800カウントで1秒を作り。
    割り込み周期208.333です。 12時間で1秒進む誤差で現在は製作停滞ぎみです。

    キャパシタもHigh側に10p、Low側に33pとかにしてますが1秒しか追い込めずに
    います。 ちなみにLowに51pに交換すると発振せずです。

     x’talはプリスケーラが16進なので、切りのいいHzなら誤差がひどいので
    こんな切りの悪いx’talを使っています。 18.432 16.384 16.128 14.7456
    12.8 9.8304MHzとかでも良いんですが、入手が困難な物も多いです。

     秋月電子の12.8MHzの温度保障のオシレーターでは24時間で狂いなしでしたが、
    オシレーターの値段が高いので普通の水晶振動子で挑戦です。
    複数個作る予定なのでなるべくコストはダウンしたいのです。

     誤差なくしたいですね。

  2. yuji のコメント:

    加藤さん
    コメントありがとうございます。
    PIC時計の誤差はハマりますね。
    切りの悪い周波数のものを使うというのは面白いです。
    私は今は精度より時間合わせの機能の方が必要になっていて、そちらが中心になっていますが、何かありましたらまたコメントください。

  3. 加藤 慎一郎 のコメント:

    本当に誤差にはハマりますね。
    周波数なんですが、少々の誤差はキャパシタで吸収なんてキツいです。
    きちんと計算で割り切れる周波数がいいようです。 32.768KHz 6.4MHz 8.192MHz
    12.8NHz 16.384MHz 25.6MHz 32.786MHz あたりでは割り切れるので良いようです。
     ところで、上記周波数で32.786MHzでPIC16F877Aで動かしたら動くんですヨ、
    ひょっとしたら、40MHzでも動いたりして・・・・。

     私のPIC時計では16F877Aで、12.8MHzと32.768MHzは誤差が24時間誤差なしは
    確認は取れてますが・・・本日で19.6608MHzはあきらめました。

     では、お互いがんばりましょう!!

  4. yuji のコメント:

    加藤さん

    やはりキリのいい周波数の方がいいですか。
    PICはかなり許容範囲が広いようですね。
    なんか適当な感じでも動くので気楽に手をつけられます。
    私の方はようやくGPSとの通信ができるようになったので、これからGPSのログから時間を抜き出して設定する部分です。
    でも、その前にボタンのチャタリング対応が先かも知れません。

    こちらこそ、今後もよろしくお願いします!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください