;	SWI-X制御 & LED照明
;
; GP0 OUT : LED
; GP1 OUT : SWI-X Power
; GP2      N/A
; GP3      N/A (MCLR)
; GP4      N/A
; GP5 IN : touch switch
;
	ERRORLEVEL	-302	; (Erase Banksel Warning)

	list		p=PIC12F629, r=dec
	#include	p12f629.inc

	__CONFIG	_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_ON & _MCLRE_ON & _BODEN_ON & _CP_ON & _CPD_OFF

;
; 定数
;
TM0CT15	equ	256-58	; Timer0 4MHz/4/256=0.256ms 0.256*58=15msのタイマ
TM1CT30	equ	57	; Timer1 4MHz/4/8=8us 8*65536*57=30secのタイマ
;
; 変数定義
;
counter	equ	0x20	; Timer1用のカウンタ
sw_ct	equ	0x21	; Touch Switchカウンタ
sw_edge	equ	0x22	; タッチスイッチのエッジ検出フラグ
w_temp	equ	0x23	; Wレジスタ退避用
st_temp	equ	0x24	; STATUSレジスタ退避用

;
; プログラム領域
;

; リセットベクタ
RST	code	0x0
	goto	main

; 割り込みベクタ
INTR	code	0x4
;
; 割り込み処理
; 使用割り込みはタイマー1 (524ms)と タイマー0 (15ms)
; タイマー1割り込みはカウンターを減算して30秒経ったらLED OFF/SWI-X ON
; タイマー0割り込みではON状態のスイッチのカウンタをインクリメント
; 0x0～0x7fなら単純インクリメントだが、0x80～0xfeは0x80に、0xffは0xffにする。
;
	movwf	w_temp
	swapf	STATUS,W
	movwf	st_temp		; ここまでレジスタ退避
	banksel	PIR1
	btfsc	PIR1,TMR1IF	; TIMER1 割り込みなら
	goto	it1chk		; TIMER1割り込み処理へ
	btfsc	GPIO,GP5	; そうでなければTouch Switchチェック。OFFなら
	goto	intrend		; 割り込み処理終了
	incfsz	sw_ct,F		; ONならばスイッチカウンタをインクリメント
	goto	iswcc		; インクリメントして0でなければ0x80オーバーチェックへ
	movlw	0xff		; 0 なら w_ct = 0xffにする
	movwf	sw_ct
	goto	it0end
iswcc
	btfss	sw_ct,7		; 0x80以上かチェック
	goto	it0end		; 0x80未満なら割り込み処理終了
	movlw	0x80		; 0x80以上なら0x80にする
	movwf	sw_ct
it0end
	movlw	TM0CT15		; タイマー0リセット
	movwf	TMR0
	bcf	INTCON,T0IF	; 割り込みフラグクリア	
	goto	intrend
it1chk
	decfsz	counter,F	; カウンタ減算
	goto	int1cnt		; 0でなければ引き続きタイマー1セット
	bcf	GPIO,GP0	; 0なら30秒経過したのでLED OFF
	bsf	GPIO,GP1	; SWI-X ON
	clrf	T1CON		; タイマー1停止
int1cnt
	bcf	PIR1,TMR1IF	; 割り込みフラグクリア
intrend	
	swapf	st_temp,W	; ここからレジスタ復帰
	movwf	STATUS
	swapf	w_temp,F
	swapf	w_temp,W
	retfie


;
; メインプログラム
;
; メインループまでは起動処理
; 	I/Oポート初期化
;	制御出力初期化
;	変数、割り込みの初期化
;
main
;
; Initialize PORT
;
	banksel	OSCCAL		; 内部クロックをキャリブレート
	call	0x3FF
	movwf	OSCCAL
	banksel	PIR1		; 一応まずは全割り込みを停止
	clrf	PIR1
	clrf	INTCON
	banksel GPIO		; PORT出力を0に
	clrf	GPIO
	movlw	B'00000111'	; アナログコンパレータOFF
	movwf	CMCON
	banksel	TRISIO		; GPIOのI/Oをセット, GP5がInput
	movlw	B'00100000'
	movwf	TRISIO	
	bcf	OPTION_REG,NOT_GPPU ; GP5のPull-upをON
	movlw	B'00100000'
	movwf	WPU
;
; LEDとSWI-Xを初期状態にする
	banksel	GPIO
	bcf	GPIO,GP0	; LED OFF
	bsf	GPIO,GP1	; SWI-X ON
;
; 変数初期化、タイマー0セット、割り込み許可
;
	clrf	sw_ct
	clrwdt			; Timer0は内部クロック、プリスケーラ－使用
	banksel	OPTION_REG
	movlw	B'11100000'
	andwf	OPTION_REG,F
	bcf	OPTION_REG,T0CS
	movlw	B'00000111'	; Timer0のプリスケーラ－を1/256分周に
	iorwf	OPTION_REG,F
	movlw	TM0CT15		; 15msタイマーをセット
	banksel	TMR0
	movwf	TMR0
	clrf	T1CON		; Timer1をリセットしておく
	banksel	PIE1		; Timer1の割り込みを許可
	clrf	PIE1
	bsf	PIE1,T1IE
	banksel	GPIO		; bank0に戻す
	bsf	INTCON,T0IE	; Timer0割り込み許可
	bsf	INTCON,PEIE	; 周辺割り込み許可
	bsf	INTCON,GIE	; 全体割り込み許可	
;
; メインループ 
;
; ONだったスイッチは、割り込みによりカウンタで秒数がカウントされている。
; カウンタが0
;	何もしない
; カウンタが0x80 (2秒以上長押し)
;	点きっぱなしにするためにTimer0を停止。処理終了記憶のためにカウンタ0xffにセット。
; カウンタが0x01～0x7f (2秒以内)
;	スイッチOFFならカウンタ0リセット。
;	スイッチONかつONエッジであればLEDとSWI-Xを反転。ONエッジでなければ何もしない。
; カウンタがそれ以外(0x81～0xff)なら
;	スイッチOFFならカウンタ0リセット。
;	スイッチONなら何もしない。
;
mainloop
	movf	sw_ct,F	
	btfsc	STATUS,Z	; sw_ct==0ならメインループを戻る
	goto	mainloop
	movlw	0x80
	xorwf	sw_ct,W
	btfsc	STATUS,Z	; w_ct == 0x80 なら
	goto	tm1stp		; Timer1停止で連続点灯の処理へ
	btfss	sw_ct,7		; w_ct < 0x80かチェック
	goto	swtch		; そうであれば状態反転処理へ
	btfss	GPIO,GP5	; w_ct >= 0x80 ならタッチスイッチの状態チェック
	goto	mainloop	; Switch ONなら何もしない
	clrf	sw_ct		; Switch OFFならカウンタクリア
	clrf	sw_edge		; エッジ検出フラグもクリア
	goto	mainloop
tm1stp
	clrf	T1CON		; 0x80時の処理。Timer1停止。
	movlw	0xFF		; sw_ct = 0xffに 
	movwf	sw_ct
	btfss	GPIO,GP0	; LEDが点灯していなければ
	goto	mainloop	; メインループに戻る
	bcf	GPIO,GP0	; 点いていればLEDを一瞬消す
	clrf	T1CON		; Timer1をクリア
	banksel	PIE1		; Timer1の割り込みを一旦停止
	bcf	PIE1,T1IE
	banksel	TMR1H		; Timer1をポーリングで利用
	movlw	0x9E		; カウンタセット 0x9e58 = 40536 = 65536-25000
	movwf	TMR1H		; 25000*8us=200ms
	movlw	0x58
	movwf	TMR1L
	movlw	B'00110001'	; 内部クロック, プリスケーラー1/8で
	movwf	T1CON		; タイマー1カウント開始
	btfss	PIR1,TMR1IF	; TIMER1終了待ち
	goto	$-1
	clrf	T1CON		; TIMER1の利用をクリア
	bcf	PIR1,TMR1IF	
	banksel	PIE1		; Timer1の割り込みを再度許可
	bsf	PIE1,T1IE
	banksel	GPIO
	bsf	GPIO,GP0	; LEDを100ms後に再点灯
	goto	mainloop
swtch
	btfss	GPIO,GP5	; 0x01～0x7f時の処理。 タッチスイッチチェック
	goto	swflip		; Switch ONならONエッジ確認処理へ
	clrf	sw_ct		; Switch OFFならカウンタクリア
	clrf	sw_edge		; エッジ検出フラグクリア
	goto	mainloop
swflip
	btfsc	sw_edge,0	; Switch ONの時はONエッジを確認
	goto	mainloop	; ONエッジでなければ何もしない
	bsf	sw_edge,0	; ONエッジならエッジ検出フラグセット
	movlw	B'00000011'	; LED出力とSWI-X出力を反転
	xorwf	GPIO,F
	clrf	T1CON
	clrf	TMR1H		; Timer1カウンタリセット。
	clrf	TMR1L		; 
	movlw	TM1CT30		; 約30秒のタイマーをセット
	movwf	counter
	movlw	B'00110001'	; 内部クロック, プリスケーラー1/8で
	movwf	T1CON		; タイマー1カウント開始
	goto	mainloop

	end
