目次>6章 第3ステップ(実用品)>永久回転こま>ソース

永久回転こま(ソース)
<PIC16F648A> PICC

更新日2007.12.8

以下のソースを取り込んで、コンパイル→PIC書き込み→実行して下さい。
PICC−Liteを使用しました。

// ========================== ここから ==============================
// PIC16F627A(実使用は648A)
// CLOCK : INT 4MHz
// PIC26F648Aでコマを制御する
//
// TMR0を0.256mS毎にカウントアップし、
// RB0INT割込み(磁界検出)時にTMR0の値を「T0_save」に保存した後、TMR0をクリアする。
// ここからTMR0が「T0_save/2」経過した時点でRB1をONにする。
// RB1をONにしてから、TMR0が「T0_save/4」経過した時点でRB1をOFFにする。
//
//
//
//
// RB0:RB0INT 磁界検出コイルをオペアンプで増幅した出力
// RB1:コマを制御する電磁石(FETで制御)
//


#include "pic.h"

__CONFIG(INTIO & WDTDIS & PWRTDIS & LVPDIS & BORDIS & MCLRDIS);

static	unsigned int		T0_save;
static	unsigned int		T0_save_2;
static	unsigned int		T0_save_4;
static	unsigned int		T0_save_8;
static	unsigned int		T0_save_16;
static	unsigned int		T0_work;
static	unsigned int		RB1_on_cnt;
static	unsigned int		RB1_off_cnt;
static	unsigned int		RB1_off2_cnt;
static			 bit		T0_over;
static			 bit		T0_2round;

// =================== 割り込み処理 ====================
static void interrupt intr(void) {
	if	(INTF) {
		INTF = 0;	// RB0INT割り込みクリア
		T0_save = TMR0;
		TMR0 = 0;
		if	(T0_2round) {
			T0_save = T0_save | 0x0100;
			T0_2round = 0;
		}
		T0_save_2 = T0_save >>1;		// TMR0/2
		T0_save_4 = T0_save_2 >>1;		// TMR0/4
		T0_save_8 = T0_save_4 >>1;		// TMR0/8
		T0_save_16 = T0_save_8 >>1;		// TMR0/16
		RB1_on_cnt = T0_save_2 - T0_save_8;			// TMR0/2 - TMR0/8
		RB1_off_cnt = T0_save_2 + T0_save_4 - T0_save_16;		// TMR0/2 + TMR0/4 - TMR0/16
		RB1_off2_cnt = RB1_off_cnt + T0_save_16;	// TMR0/2 + TMR0/4 + TMR0/16
	} else
	if (T0IF) {
		T0IF = 0;	// TMR0割り込みクリア
		if	(T0_2round) {
			T0_over = 1;
		} else {
			T0_2round = 1;
		}
	}
}


// ==================== PICの初期化 ===========================
static void pic_init() {
	OPTION = 0xC7;		// プリスケーラ:256
	PORTA = 0;
	CMCON = 0x07;		// コンパレータ未使用
	TRISA = 0xFF;		// PORTA:in
	TRISB = 0xF9;		// RB1,2:out
	PORTB = 0x00;
	TMR0 = 0;
	INTCON = 0xA0;		// TMR0 enable
	T0_over = 0;
	T0_2round = 0;
	RB1_on_cnt = 0;
	RB1_off_cnt = 0;
}


// =============== RB2のLEDを0.5秒間隔で点滅する ================
static void RB2_onoff()	{
	char	i;
	char	j;

	for	(j=10 ; j>0 ; j--) {
		for	(i=4 ; i>0 ; i--) {		// 0.5秒待つ (131mS×4=524mS)
			while(!T0_over) {}	// 0.256mS×512=131mS
			TMR0 = 0;
			T0_over = 0;
			T0_2round = 0;
		}
		if	(RB2) {
			RB2 = 0;
		} else {
			RB2 = 1;
		}
	}
}

// ==================== メイン処理 ===========================
main()	{
	pic_init();			// PICの初期化
	RB2_onoff();		// RB2のLEDを0.5秒間隔で点滅する
	INTF = 0;
	INTE = 1;

	while(1) {
		T0_work = TMR0;
		if	(T0_2round) {
			T0_work = T0_work | 0x0100;
		}
		if	((T0_work > RB1_on_cnt) && (T0_work < RB1_off_cnt)) {
			INTE = 0;
			RB1 = 1;
		} else {
			if	(RB1) {
				RB1 = 0;
			}
			if	(T0_work > RB1_off2_cnt) {
				if	(!INTE) {
					INTF = 0;
					INTE = 1;
				}
			}
		}

		if	(T0_over) {
			RB1 = 0;
			RB2 = 0;
			INTE = 1;
			SLEEP();			// ■ SLEEP
			RB2 = 1;
			TMR0 = 0;
			T0_over = 0;
			T0_2round = 0;
			RB1_on_cnt = 0;
			RB1_off_cnt = 0;
		}
	}
}
// =========================== ここまで ===============================