;---- interval
;---- インターバルタイマ・ファームウェア
;---- by K.I	since 050107

;TXLをLにしている間、
;	HTIMEに指定した時間、TXDをHに、
;	LTIMEに指定した時間、TXDをLに、を繰返す。
;ワンショットになっているので、最低限HTIMEの時間H出力される。
;TXLがHでTXDがLの場合は、スリープ状態になる。→TXLがLでウェイクアップ

;	LIST	P=PIC12F629
;	INCLUDE	P12F629.INC
	LIST	P=PIC12F675
	INCLUDE	P12F675.INC

;---- 3V電源で使用する場合は、_BODEN_OFFにして下さい。
	__CONFIG _CPD_OFF & _CP_OFF & _BODEN_ON & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

; CPD		: data memory Code Protect [ON,OFF]
; CP		: flash program memory Code Protect [ALL,HALF,UPPER_256,OFF]
; BODEN		: BrownOut reset ENable [ON,OFF]
; MCLRE		: MCLR Enable [ON,OFF]
; PWRTE		: PoWeR up Timer Enable (72ms) [ON,OFF]
; WDT		: Watch Dog Timer [ON,OFF]
; LP OSC		; Low Power OSC
; XT OSC		; XT OSC (normal speed)
; HS OSC		: High Speed mode OSC
; EC OSC		: RC mode OSC
; INTRC_OSC	; Intenal RC OSC [CLKOUT,NOCLKOUT]
; EXTRC_OSC	; External RC OSC [CLKOUT,NOCLKOUT]

	__IDLOCS H'0100'	;V1.00

;--------------------------------
BOD	EQU	0		;PCON-Brown Outreset Detect
;--------------------------------
TXD	EQU	0		;GP0, O, 送信データ
IN0	EQU	1		;GP1, I, bit0
IN1	EQU	2		;GP2, I, bit1
TXEN	EQU	3		;GP3, I, /送信イネーブル
IN2	EQU	4		;GP4, I, bit2
IN3	EQU	5		;GP5, I, bit3
;--------------------------------

GPIODIR	EQU	B'00111110'	;GPIO入出力設定
GPIOINI	EQU	B'00001000'	;GPIO InitValue
OPT_INI	EQU	B'00000111'	;OPTION Init(1/256 pre-scaler)
WPU_INI	EQU	B'00000000'	;WPU Init
CMP_INI	EQU	B'00000111'	;CMP Init
AD0_INI	EQU	B'00000000'	;ADCON0 Init
ANS_INI	EQU	B'00000000'	;ANSEL Init

PRELOAD	EQU	-50000/256	;TMR0 preload (50ms)
LTIME	EQU	-(4*60+50)*20	;4分50秒 -(min*60+sec)*20
HTIME	EQU	-(0*60+10)*20	;   10秒 -(min*60+sec)*20
;-------------------------------------------------------
;LTIME,HTIMEは、最大65536/20=約3276秒=約54分
;注:Default Radixが10進になっていることを確認すること!
;-------------------------------------------------------

	CBLOCK	H'20'

	W_TEMP			;Wレジスタ退避用
	STATUS_TEMP		;STATUSレジスタ退避用

	COUNTL			;カウンタ L
	COUNTH			;カウンタ H

	GPIOX			;チャタ処理済みGPIO値
	GPIOLAST			;前回のタイマ割込みのGPIO値

	LINE,LINE0		;汎用baffer

	ENDC

;--------------------------------------------------------
	ORG	0		;リセット・ベクタ
;--------------------------------------------------------
	goto	SETUPPORTS	;ポートの初期設定

;--------------------------------------------------------
	ORG	4		; interrupt vector location
;--------------------------------------------------------
	movwf   W_TEMP		; Wレジスタの退避
	movf	STATUS,W		; STATUSレジスタも
	movwf	STATUS_TEMP	; 退避する

	BTFSC	INTCON,T0IF	; T0割り込みならば
	CALL	T0WAKEUP		; T0WAKEUP処理へ

	BTFSC	INTCON,GPIF	; GP割り込みならば
	CALL	GPWAKEUP		; GPWAKEUP処理へ

	movf    STATUS_TEMP,w	; 退避していたSTATUSレジスタの内容を
	movwf	STATUS		; 回復させる
	swapf   W_TEMP,f
	swapf   W_TEMP,w		; Wレジスタも回復させて
	retfie			; インタラプト処理終了→GIE再設定される

;--------------------------------------------------------
	DT	"interval 050116 by K.I"	;<-- **** Version ****
;--------------------------------------------------------
; Timer0割込み処理→タイマプリセットとカウント、チャタ処理
;--------------------------------------------------------
T0WAKEUP
	BCF	INTCON,T0IF	;T0割込みフラグをクリアしておく

	movlw	PRELOAD
	addwf	TMR0,f

;---- 以下、タイマ割込みによるチャタ処理
	movf	GPIOLAST,w
	movwf	LINE0		;line0:前回のGPIO値
	movf	GPIO,w
	movwf	LINE		;line:今回のGPIO値
	movwf	GPIOLAST		;今回のGPIO値の保存
	xorwf	LINE0,w		;前回との違いを求める
	andwf	LINE0,f		;違ってる部分は前回のまま
	xorlw	0xff		;反転
	andwf	LINE,w		;同じ部分を求める
	iorwf	LINE0,w		;違ってる部分と同じ部分を合成
	movwf	GPIOX		;チャタ処理済みデータを保存

	goto	TX_COUNT

;--------------------------------------------------------
; GP変化割込み→なにもしない(SLEEPから抜けるだけ)
;--------------------------------------------------------
GPWAKEUP
	BCF	INTCON,GPIF	;GP割込みフラグをクリアしておく
	return

;--------------------------------------------------------
; 入出力ポートの初期設定を行う
;--------------------------------------------------------
SETUPPORTS

	call    0x3FF		; calibration値は3FF番地にRETLWで記録済みとする
	bsf     STATUS,RP0	; set file register bank to 1 
	movwf   OSCCAL		; update register with factory cal value 

	MOVLW	OPT_INI		;WAKE-UP,PULL-UP,1:256 PRESCALER
	MOVWF	OPTION_REG

	MOVLW	GPIODIR		;Set I/O direction
	MOVWF	TRISIO
	MOVLW	WPU_INI
	MOVWF	WPU
;	BSF	PCON,BOD
	MOVLW	ANS_INI		;Init Analog Input Select
	MOVWF	ANSEL		;(12F675 only)

	BCF	STATUS,RP0	;select bank0

	MOVLW	GPIOINI		;Init I/O data
	MOVWF	GPIO
	MOVLW	CMP_INI		;Init CMP data (CMP off)
	MOVWF	CMCON
	MOVLW	AD0_INI		;Init A/D control
	MOVWF	ADCON0		;(12F675 only)

	movf	GPIO,w
	movwf	GPIOX
	movwf	GPIOLAST

	movlw	PRELOAD		;タイマプリセット
	movwf	TMR0

; ---- 割込み許可 ----------------

	BSF	STATUS,RP0	;select bank1
	BSF	IOC,3		;GP3の変化によるインタラプト設定
	BCF	STATUS,RP0	;select bank0
	BSF	INTCON,GPIE	;GPレジスタ変化によるインタラプト許可
	BSF	INTCON,T0IE	;Timer0 overflowによるインタラプト許可
	BSF	INTCON,GIE	;グローバルインタラプト許可

	goto	SLEEPSTART	;スリープ状態からスタートする

; ---- TXD出力 ---------------------
TXD_OUT
	CALL	TX_HIGH

; ---- メインループ ----------------
LOOP
	BTFSS	GPIOX,TXEN	;TXENが'L'ならばLOOP
	GOTO	LOOP
	BTFSC	GPIO,TXD		;TXDが'H'ならばLOOP
	GOTO	LOOP

; ---- スリープ ----------------
SLEEPSTART
	BCF	GPIO,TXD		;TxD をクリア
	BSF	INTCON,GPIE	;GPレジスタ変化によるインタラプト許可
	SLEEP			;スリープ状態へ

	BCF	INTCON,GPIE	;GP割込み禁止
	GOTO	TXD_OUT		;TXD出力へ

;--------------------------------------------------------
; 割込みをカウントしてTxDを出力するルーチン
;--------------------------------------------------------
TX_COUNT
	INCFSZ	COUNTL,F
	return
	INCFSZ	COUNTH,F
	return

	BTFSS	GPIO,0		;GP0チェック
	GOTO	TX_HIGH		; 'L'ならば'H'に変更
	GOTO	TX_LOW		; 'H'ならば'L'に変更
TX_HIGH
	MOVLW	0x01		;High出力と時間設定
	IORWF	GPIO,F
	MOVLW	low(HTIME)
	MOVWF	COUNTL
	MOVLW	high(HTIME)
	MOVWF	COUNTH
	return
TX_LOW
	MOVLW	0xFE		;Low出力と時間設定
	ANDWF	GPIO,F
	MOVLW	low(LTIME)
	MOVWF	COUNTL
	MOVLW	high(LTIME)
	MOVWF	COUNTH
	return

;--------------------------------------------------------
	ORG	0x3FF
;--------------------------------------------------------
;	RETLW	0xA0		;キャリブレーションデータ
;これは通常は書き込まれてる値をそのまま使うので上書きしない。

	END