;--------------------------------------------------------------------------
;	電動ガン 電子式セミ／フル切替システム 制御ソフト
;	マルイメカ換装64式用　ver0.90
;	2665年(平成17年) 石岡マロンズ 技術研究本部
;	URL:http://www.max.hi-ho.ne.jp/ksanso
;--------------------------------------------------------------------------
;	Electric Air Soft Gun
;	SemiAuto/FullAuto Change Control Software
;	for Type64 with TokyoMarui Mechanism ver0.90
;	written by Ishioka Marons R&D center 2005 
;--------------------------------------------------------------------------
;*** 書き込む際の注意 ***
;　書込前に,PICに書かれているOSCCALデータとBGデータを読み出しておくこと
;　（内部RC発振周波数に個体差があり,それを補正するために必要）

;*=*=*=*=*=*=*=*=*=*=*
;　変数の定義など
;*=*=*=*=*=*=*=*=*=*=*
	list		p=pic12f629		;PIC12F629に適用
	#include	p12f629.inc		;PIC12F629用インクルードファイル読込
	errorlevel	-302			;エラーレベル追加

	__CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT

;変数の定義
CNT1	EQU	20H		;タイマカウンタ 20us用
CNT2	EQU	21H		;タイマカウンタ 1ms用
CNT3	EQU	22H		;タイマカウンタ	50ms用
SWSTATE	EQU	25H		;各フラグ状態記憶用変数
						;bit0…安全
						;bit1…単発
						;bit2…3点射
						;bit3…連発
						;bit4…引金
						;bit5…（空き）
						;bit6…（空き）
						;bit7…カットオフ
FIRECNT	EQU	26H		;発射回数カウンタ
W_BAK	EQU	5DH		;割込発生時のWレジスタ内容待避
ST_BAK	EQU	5EH		;割込発生時のSTATUSレジスタ内容待避
PC_BAK	EQU	5FH		;割込発生時のPCLATHレジスタ内容待避

;*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
;　プログラム本体
;*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
	ORG		0x000
	GOTO	INIT			;初期設定へ

;+++++++++++++++++++++++++++++++++++++++++++++++++
;　割り込みルーチン（磁石検知）
;+++++++++++++++++++++++++++++++++++++++++++++++++
;割込みの処理時間は、48μs。
;割込みは、約60ms間隔なので、全く問題なし。

	ORG		0x004

;*** レジスタの退避 ***(7us)
ITRP_INIT
	MOVWF	W_BAK		;Wレジスタの内容を待避
	SWAPF	STATUS,W	;STATUSレジスタをWへ
	CLRF	STATUS		;バンク0にする
	MOVWF	ST_BAK		;STATUSレジスタの内容を待避
	MOVF	PCLATH,W	;PCLATHレジスタをWへ
	MOVFW	PC_BAK		;PCLATHレジスタの内容を待避
	CLRF	PCLATH		;PCLATHで指定するページも0にする

;*** 割込処理本体 ***
MGDT_MAIN
;LM311出力のノイズチェック(23or24us)
	CALL	TIM20U	    ;20us待つ(正確には21us)
	;↑機械スイッチよりも応答が速いので,この程度の時素とする
	BTFSC	GPIO,2		;再確認
	GOTO	ITRP_END	;ノイズと判断,割込終了
;モード判別(2or3us)
	BTFSC	SWSTATE,1	;単発モードであれば次行実行
	GOTO	MGDT_CUT	;カットオフ処理へジャンプ
;3点射カウント処理(5or6us)
	INCF  	FIRECNT,F	;発射回数カウンタを+1
	MOVF  	FIRECNT,W	;Wにもコピー
	XORLW  	D'6'		;FIRECNTと6のXORをWに格納
;	1回の磁石検知で2回割り込みが入るようなので、3×2=6とする。
	BTFSS	STATUS,Z	;FIRECNT=6のとき,次をスキップ
	GOTO	ITRP_END	;等しくなければ,次のカットオフ処理をスキップ
;カットオフ処理(2us)
MGDT_CUT
	BCF		GPIO,0		;ゲートオフ
	BSF		SWSTATE,7	;カットオフフラグを1にする

;*** 割込終了処理 ***(9us)
ITRP_END
	MOVFW	PC_BAK		;待避したPCLATHを読み出し
	MOVWF	PCLATH		;PCLATHを復旧
	SWAPF	ST_BAK,W 	;STATUSレジスタをWへ
	MOVWF	STATUS		;STAUTSレジスタを戻す
						;バンクも元に戻る
	SWAPF  	W_BAK,F		;SWAPを2回行うことでWレジスタを戻す
	SWAPF  	W_BAK,W		;これはSTATUSレジスタに影響させないため

	BCF		INTCON,INTF	;INTFを0クリア

	RETFIE				;割込終了！

;+++++++++++++++++++++++++++++++++++++++++++++++++
;　初期設定
;+++++++++++++++++++++++++++++++++++++++++++++++++
INIT
	;Bank0の設定
	BCF		STATUS,RP0		;バンク0に切替
 	MOVLW	0x07			;コンパレータを使わない
 	MOVWF	CMCON
	CLRF	INTCON			;割込禁止（初期設定が終わったところで解除）

	; Bank1の設定
 	BSF		STATUS,RP0		;バンク1に切替
	MOVLW	B'111110'		;GP0のみ出力ピンとする
							;GP0:点弧指令（出力）
							;GP1:連発（入力）
							;GP2:回転検知（入力）
							;GP3:3点射（入力）
							;GP4:単発（入力）
							;GP5:引金（入力）
							;ver0.12:GP1,2を入れ替え（回転検知で割込するため）
	BCF		OPTION_REG,6	;GP2がHigh→Lowになった時,割込発生
	MOVWF	TRISIO
	
	BCF		STATUS,RP0		;バンク0に戻す

;外部出力の初期化（初期値=0)
	BCF		GPIO,0			;点弧指令をオフとする

;変数の初期化（全て初期値=0)
	CLRF 	CNT1
	CLRF	CNT2
	CLRF	CNT3
;	CLRF	CNT4
;	CLRF	CNT5
	CLRF	SWSTATE
	CLRF	FIRECNT

	MOVLW	B'11010000'	;割込設定（GIE,PEIE,INTEを1）をWに書き込み…
	MOVWF	INTCON		;割込有効
	;デフォルトは割込有効。但し,連発モードでは無効とする。

;+++++++++++++++++++++++++++++++++++++++++++++++++
;　メインルーチン
;+++++++++++++++++++++++++++++++++++++++++++++++++
MAIN
;********************
;　外部入力処理
;********************
;*** 単発入力受付 ***
TANP
	BTFSC	GPIO,4		;単発SWが押されたか？0でオン
	GOTO	TANPOFF	    ;入力なし,オフ処理へ
	CALL	TIM20M	    ;20ms待つ
	BTFSC	GPIO,4		;再確認
	GOTO	BST3		;ノイズと判断,単発受付終了
	BSF		SWSTATE,1	;「単発」を1にする
	BCF		SWSTATE,2	;「3点射」を0にする
	BCF		SWSTATE,3	;「連発」を0にする

TANPOFF
	CALL	TIM20M	    ;20ms待つ
	BTFSS	GPIO,4		;再確認
	GOTO	BST3		;ノイズと判断,3点射入力受付へ
	BCF		SWSTATE,1	;「単発」を0にする

;*** ３点射入力受付 ***
BST3
	BTFSC	GPIO,3		;3点射SWが押されたか？0でオン
	GOTO	BST3OFF	    ;入力なし,オフ処理へ
	CALL	TIM20M	    ;20ms待つ
	BTFSC	GPIO,3		;再確認
	GOTO	RENP		;ノイズと判断,３点射受付終了
	BCF		SWSTATE,1	;「単発」を0にする
	BSF		SWSTATE,2	;「3点射」を1にする
	BCF		SWSTATE,3	;「連発」を0にする

BST3OFF
	CALL	TIM20M	    ;20ms待つ
	BTFSS	GPIO,3		;再確認
	GOTO	RENP		;ノイズと判断,連発入力受付へ
	BCF		SWSTATE,2	;「3点射」を0にする

;*** 連発入力受付 ***
RENP
	BTFSC	GPIO,1		;連発SWが押されたか？0でオン
	GOTO	RENPOFF		;入力なし,オフ処理へ
	CALL	TIM20M	    ;20ms待つ
	BTFSC	GPIO,1		;再確認
	GOTO	SAFE		;ノイズと判断,安全位置演算へ
	BCF		SWSTATE,1	;「単発」を0にする
	BCF		SWSTATE,2	;「3点射」を0にする
	BSF		SWSTATE,3	;「連発」を1にする
	CLRF	INTCON		;割込無効

RENPOFF
	CALL	TIM20M	    ;20ms待つ
	BTFSS	GPIO,1		;再確認
	GOTO	SAFE		;ノイズと判断,安全位置演算へ
	BCF		SWSTATE,3	;「連発」を0にする
	MOVLW	B'11010000'	;割込設定（GIE,PEIE,INTEを1）をWに書き込み…
	MOVWF	INTCON		;割込有効

;*** 安全位置演算 ***
;SWSTATEのbit1～3が全て0なら,安全位置と見なす
SAFE
	MOVLW 	B'00001110'	;bit1～3以外をマスク
	ANDWF	SWSTATE,W	;00001110とSWSTATEの論理積をWに代入
	BTFSS	STATUS,Z	;結果=0（安全有効）ならZ=1,次をスキップ
	GOTO	SAFE_OFF	;安全解除へジャンプ
	BSF		SWSTATE,0	;「安全」を1にする
	GOTO	TRG			;引金入力受付へ
SAFE_OFF				;安全解除の処置
	BCF		SWSTATE,0	;「安全」を0にする（解除）

;*** 引金入力受付 ***
TRG
	BTFSC	GPIO,5		;引金が引かれたか？0でオン
	GOTO	TRGOFF	    ;入力なし,オフ処理へ
	CALL	TIM20M	    ;20ms待つ
	BTFSC	GPIO,5		;再確認
	GOTO	GATEON		;ノイズと判断,点弧指令演算へ
	BSF		SWSTATE,4	;「引金」を1にする
TRGOFF
	CALL	TIM20M	    ;20ms待つ
	BTFSS	GPIO,5		;再確認
	GOTO	GATEON		;ノイズと判断,点弧指令演算へ
	BCF		SWSTATE,4	;「引金」を0にする
	CLRF	FIRECNT		;発射回数カウンタを0クリア
						;↑ver0.31　クリアタイミングを引金オフに変更
	BCF		SWSTATE,7	;「カットオフ」を0にする（解除）

;********************
;　点弧指令演算
;********************
GATEON
	BTFSS	SWSTATE,4	;引金入力ありか？1なら点弧処理開始
	GOTO	GATEOFF		;引金入力無ければ,GATEOFF処理へ
	MOVLW 	B'10000001'	;点弧禁止条件の照査(bit0,7)
	ANDWF	SWSTATE,W	;10000001とSWSTATEの論理積をWに代入
	BTFSS	STATUS,Z	;点弧禁止条件がなければ,次をスキップ
	GOTO	GATEOFF
	BSF		GPIO,0		;点弧指令をHi(5V)にする
	GOTO	MAIN
GATEOFF
	BCF		GPIO,0		;点弧指令をLow(0V)にする
	GOTO	MAIN		;最初に戻る

;+++++++++++++++++++++++++++++++++++++++++++++++++
;　サブルーチン
;+++++++++++++++++++++++++++++++++++++++++++++++++
;**************************
;*** タイマサブルーチン ***
;**************************
;１サイクル=4クロック(4MHzクロックの時,1サイクル=1μ秒)
;*** 20μ秒タイマ ***
;LM311専用
TIM20U
	MOVLW	D'4'		;2（呼出元のCALLで2サイクル）+1=3
	MOVWF	CNT1		;3+1=4
TIMLP1	NOP
	DECFSZ	CNT1,F		;1+1+2=4(ループ1回で4サイクル)
	GOTO	TIMLP1		;4+4*4-1=19（最後の1周は1サイクル少ないので-1）
	RETURN				;19+2=21(1多いが妥協）

;*** 1m秒タイマ ***
;基本
TIM01M
	MOVLW	D'248'		;2（呼出元のCALLで2サイクル）+1=3
	MOVWF	CNT2		;3+1=4
TIMLP2	NOP
	DECFSZ	CNT2,F		;1+1+2=4(ループ1回で4サイクル)
	GOTO	TIMLP2		;4+4*248-1=995（最後の1周は1サイクル少ないので-1）
	GOTO	$+1			;995+2=997
	NOP					;997+1=998
	RETURN				;998+2=1000

;*** 20m秒タイマ ***
;スイッチ入力用
TIM20M
	MOVLW	D'20'		;2（呼出元のCALLで2サイクル）+1=3
	MOVWF	CNT3		;3+1=4
TIMLP3
	CALL	TIM01M		;1000サイクル
	DECFSZ	CNT3,F		;1000+1+2=1003(ループ1回で1003サイクル)
	GOTO	TIMLP3		;4+1003*20-1=20063
	RETURN				;20063+2=20065(誤差：0,3%)

	END
