;***** ClapSwitch.asm *****************************************************
;
;	拍手スイッチ
;
;	origin:  http://homepage3.nifty.com/mitt/pic/pic6_03_0.html
;
;     ( coding:  Ver. 0.00   2011/01/02  by M.Yamamoto )
;	coding:  Ver. 1.00   2011/01/08  初期バージョン
;	update:  Ver. 1.01   2014/08/11  再度見直し変更
;	bugfix:  Ver. x.xx
;
;******************************************************* PicAsm 0227 ******

;	Device: PIC12F635	Clock: 1MHz (Internal OSC)

;	オリジナルとの主な相違点

;		ハードウェアの変更

;		・PIC12F683 から大量に手持ちの PIC12F635 に変更。

;		ソフトウェアの変更

;		・一部の変数名、ラベル名の付け直し。
;		・パターンを覚えやすいように変更と追加。

;	リズムパターンと制御する出力ポート

;		拍手のパターン（入力）	プログラムでの認識	出力ポート

;		パパン　パパン		１０１			GP0 を ON
;		パパン　パパパン	１０１１		GP1 を ON
;		パパン　パパパパン	１０１１１		GP2 を ON
;		パパン　パン　パン	１００			GP0,1,2 を ON
;		パパパン　パパン	１１０１		GP0 を OFF
;		パパパン　パパパン	１１０１１		GP1 を OFF
;		パパパン　パパパパン	１１０１１１		GP2 を OFF
;		パパパン　パン　パン	１１００		GP0,1,2 を OFF

;	PIC12F635 のピンと用途

;		① Vdd	電源 +5V DC		⑧ Vss	電源 GND
;		② GP5	空き			⑦ GP0	CH-1 出力
;		③ GP4	debug 出力	　	⑥ GP1	CH-2 出力
;		④ GP3	信号 入力		⑤ GP2	CH-3 出力

;	      GP3 は入力専用で、出力ポートには使えない。

;==========================================================================

		list		P=PIC12F635	;デバイス情報
		include        "P12F635.INC"	;インクルードファイル
		errorlevel	-302		;Eliminate bank warning

		__config	_CPD_OFF & _CP_OFF & _BOD_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

;==========================================================================
;		変数、定数の定義とレジスタ割付け
;==========================================================================

		radix	dec

t1ms		equ	1			;bit1:  1mS (1.024mS)
t10ms		equ	2			;bit2: 10mS (10.24mS)
st1		equ	1			;bit1: ピン変化割り込み発生で 90mS 割り込み禁止
st2		equ	2			;bit2: ピン変化割り込みを認識し、次のピン変化割り込みを待つ
st3		equ	3			;bit3: 600mS以上ピン変化割り込みが無くSLEEPになる前の50mS間（ピン変化割り込み禁止）
debug		equ	4			;GP4: debug 出力

		cblock	h'40'
tmflag						;タイマーフラグ(0:256μS,1:1mS,2:10mS)
count10						;10mS カウンタ、TMR0 割り込み(1024μS)を 10回(10.24mS)カウントする
xcount10					;10mS 単位のカウンタ
iocflag						;割り込みフラグ
state						;状態 (st1/st2/st3)
rhythm						;リズム（拍手の間隔の組み合わせ）
work1						;ワーク
		endc

		cblock	h'70'
w_save						;W レジスタの退避用
s_save						;STATUS レジスタの退避用
		endc

;==========================================================================
;		プログラム開始
;==========================================================================

		org	h'0000'		;リセットベクタ
		goto	start

;==========================================================================
;		割り込み処理
;==========================================================================

		org	h'0004'		;割り込みベクタ
interrupt
		; レジスタの保存

		movwf	w_save		;W レジスタの保存
		movf	STATUS,W
		movwf	s_save		;STATUS レジスタの保存

		bcf	STATUS,RP0	;バンク 0
		btfsc	INTCON,T0IF	;タイマー０割り込み か？
		goto	int_t0		;Yes

		btfsc	INTCON,RAIF	;ピン変化割込み か？
		goto	int_chg		;Yes
		goto	int_end		;(Illegal interrupt)

		; タイマー０割り込み処理

int_t0		bcf	INTCON,T0IF	;タイマー０割込みフラグをクリア

		bsf	tmflag,t1ms	;1mSフラグセット
		decfsz	count10,F	;10mS カウンタ - 1
		goto	int_end	

		bsf	tmflag,t10ms	;10mSフラグセット
		movlw	10
		movwf	count10		;10mS カウンタ初期化
		incf	xcount10,F	;10mS 単位のカウンタ + 1
		goto	int_end	

		; ピン変化割込み処理

int_chg		bcf	INTCON,RAIF	;ピン変化割込みフラグをクリア

		btfss	GPIO,3		;"0" → "1" の変化のみ拾う
		goto	int_end	

		btfsc	state,st3	;state = 3 か？
		goto	int_end		;Yes

		bsf	iocflag,0	;ピン変化割り込みフラグ = ON
		bsf	STATUS,RP0	;バンク 1
		clrf	IOCA		;ピン変化割り込み中断
		bcf	STATUS,RP0	;バンク 0

		; レジスタの復帰

int_end		movf	s_save,W
		movwf	STATUS		;STATUS レジスタの復帰
		swapf	w_save,F
		swapf	w_save,W	;W レジスタの復帰

		retfie

;==========================================================================
;		初期化処理
;==========================================================================

start
		clrf	STATUS		;STATUS クリア
	 	clrf	INTCON		;INTCON クリア

		; GPIO をデジタルI/O に設定
		clrf	GPIO
		movlw	h'07'		;Comparator mode Off
		movwf	CMCON0		;GP2-0 はデジタルI/O

		bsf	STATUS,RP0	;バンク 1
; 		clrf	ANSEL		;PIC12F675,683 の場合, デジタルI/O
		movlw	h'28'		;GP0-GP2,GP4: 出力, GP3,GP5: 入力
		movwf	TRISIO

		; 内部クロックを 1 MHz に設定
		movlw	h'40'		;CLOCK=1MHz
		movwf	OSCCON

		; ピン変化割り込みの設定
		movlw	h'08'		;GP3: ピン変化割り込み有効
		movwf	IOCA

		; タイマー０割り込みの設定
		movlw	h'08'		;プリスケーラ: 使用しない
		movwf	OPTION_REG

		bcf	STATUS,RP0	;バンク 0
		clrf	TMR0		;TMR0 クリア
		movlw	h'a8'		;GIE,T0IE,RAIE
		movwf	INTCON

		; 各変数の初期設定
		clrf	state		;状態
		clrf	iocflag		;ピン変化割り込みフラグ
		clrf	rhythm		;リズム(拍手の間隔の組み合わせ)

		movlw	10
		movwf	count10		;10mS カウンタ初期化

;==========================================================================
;		メイン・ルーチン
;==========================================================================

main
		btfsc	tmflag,t10ms	;10mS 経過 か？
		call	proc10ms	;Yes
		btfsc	iocflag,0	;ピン変化割り込み発生 か？
		call	pin_chg		;Yes
		goto	main

;==========================================================================
;		10 mS 経過処理
;==========================================================================

proc10ms
		bcf	tmflag,t10ms	;10mS 割り込みフラグクリア

		btfsc	state,st1	;state = 1 か？
		goto	p10_01		;Yes

		btfsc	state,st2	;state = 2 か？
		goto	p10_02		;Yes

		btfsc	state,st3	;state = 3 か？
		goto	p10_03		;Yes
		goto	p10_04		;No

p10_01		call	state1		;状態(state) = 1 の処理
		goto	p10_04

p10_02		call	state2		;状態(state) = 2 の処理
		goto	p10_04

p10_03		call	state3		;状態(state) = 3 の処理

p10_04		return

;==========================================================================

		; 状態(state) = 1 の処理
state1
		movlw	9
		subwf	xcount10,W	;xcount10 = 9 ?
		btfss	STATUS,Z	;ピン変化割り込みから 90mS 経過 か？
		goto	st1_01		;No
					;Yes
		bcf	GPIO,debug	;ピン変化割り込み毎にLEDを点滅

		call	cnt_init	;タイマ用カウンタ等初期化

		movlw	1 << st2
		movwf	state		;state = 2 設定

		movf	GPIO,W		;割り込み許可する前にダミーREAD
		bsf	STATUS,RP0	;バンク 1
		movlw	h'08'		;GP3: ピン変化割り込み有効
		movwf	IOCA		;
		bcf	STATUS,RP0	;バンク 0

st1_01		return

		; タイマ用カウンタ等初期化処理
cnt_init
		clrf	xcount10	;10mS 単位の時間
		movlw	10
		movwf	count10		;10mS カウンタ初期化
		return

;==========================================================================

		; 状態(state) = 2 （ピン変化割り込み待ち）の処理
state2
		movlw	60
		subwf	xcount10,W	;xcount10 >= 60 ?
		btfss	STATUS,C	;ピン変化割り込みなしで 600mS 経過 か？
		goto	st2_05		;No
					;Yes
		bsf	STATUS,RP0	;バンク 1
		clrf	IOCA		;ピン変化割り込み中断
		bcf	STATUS,RP0	;バンク 0

		; rhythm（リズム）の判定

		movlw	b'00000101'	;パパンパパン
		subwf	rhythm,W
		movlw	1		;GP0 を ON
		btfsc	STATUS,Z
		goto	st2_01		;Yes

		movlw	b'0001011'	;パパンパパパン
		subwf	rhythm,W
		movlw	2		;GP1 を ON
		btfsc	STATUS,Z
		goto	st2_01		;Yes

		movlw	b'00010111'	;パパンパパパパン
		subwf	rhythm,W
		movlw	4		;GP2 を ON
		btfsc	STATUS,Z
		goto	st2_01		;Yes

		movlw	b'00000100'	;パパンパンパン
		subwf	rhythm,W
		movlw	7		;GP2-0 全て ON
		btfsc	STATUS,Z
		goto	st2_01		;Yes

		movlw	b'00001101'	;パパパンパパン
		subwf	rhythm,W
		movlw	1		;GP0 を OFF
		btfsc	STATUS,Z
		goto	st2_02		;Yes

		movlw	b'00011011'	;パパパンパパパン
		subwf	rhythm,W
		movlw	2		;GP1 を OFF
		btfsc	STATUS,Z
		goto	st2_02		;Yes

		movlw	b'00110111'	;パパパンパパパパン
		subwf	rhythm,W
		movlw	4		;GP2 を OFF
		btfsc	STATUS,Z
		goto	st2_02		;Yes

		movlw	b'00001100'	;パパパンパンパン
		subwf	rhythm,W
		movlw	7		;GP2-0 全て OFF
		btfsc	STATUS,Z
		goto	st2_02		;Yes

		call	cnt_init	;タイマ用カウンタ等初期化処理
		goto	st2_04

st2_01		iorwf	GPIO,W		;該当ビットを追加
		andlw	h'07'
		movwf	work1
		goto	st2_03

st2_02		andwf	GPIO,W		;GP2-0 の
		xorwf	GPIO,W		;該当ビットだけをクリア
		movwf	work1

st2_03		movlw	h'38'
		andwf	GPIO,W		;GP5-3 を取り出す
		iorwf	work1,W		;
		movwf	GPIO		;GP2-0 にセット（GP5-3 は変えない）

st2_04		clrf	rhythm
		movlw	1 << st3
		movwf	state		;state = 3 設定

st2_05		return

;==========================================================================

		; 状態(state) = 3 の処理
state3
		movlw	5
		subwf	xcount10,W	;xcount10 >= 5 ?
		btfss	STATUS,C	;ピン変化割り込みなしで 50mS 経過 か？
		goto	st3_01		;No
					;Yes
		bcf	GPIO,debug	;ピン変化割り込み毎にLEDを点滅

		movf	GPIO,W		;割り込み許可する前にダミーREAD
		bsf	STATUS,RP0	;バンク 1
		movlw	h'08'		;GP3: ピン変化割り込み有効
		movwf	IOCA		;
		bcf	STATUS,RP0	;バンク 0

		sleep			;ピン変化割り込みで抜ける

		movlw	1 << st1
		movwf	state		;state = 1 設定

		bsf	STATUS,RP0	;バンク 1
		clrf	IOCA		;ピン変化割り込み中断
		bcf	STATUS,RP0	;バンク 0

		clrf	rhythm		;リズム(拍手の間隔の組み合わせ)
		call	pin_chg		;

st3_01		return

		; ピン変化割り込み処理
pin_chg
		bcf	iocflag,0	;ピン変化割り込みフラグクリア

		bsf	GPIO,debug	;ピン変化割り込み毎にLEDを点滅

		btfsc	state,st2	;state = 2 か？
		call	width_chk	;Yes, 拍手の間隔チェック

		call	cnt_init	;タイマ用カウンタ等の初期化

		btfsc	state,st3	;state = 3 か？
		goto	pchg_01		;Yes

		movlw	1 << st1
		movwf	state		;state = 1 設定

pchg_01		return

		; 拍手の間隔（リズム）チェック
		; state = 2 でピン変化割り込み発生時
width_chk
		movlw	3
		subwf	xcount10,W	;xcount10 < 3 ?  （前回割り込みから 20mS 以下？(対象外)）
		btfss	STATUS,C	;
		goto	wck_03		;Yes

		movlw	51
		subwf	xcount10,W	;xcount10 >= 51 ?（前回割り込みから 510mS 以上？(対象外)）
		btfsc	STATUS,C	;
		goto	wck_03		;Yes

		movlw	21
		subwf	xcount10,W	;xcount10 < 21 ? （前回割り込みから 200mS 以下？(短拍)）
		btfss	STATUS,C	;
		goto	wck_01		;Yes

		movlw	30
		subwf	xcount10,W	;xcount10 >= 30 ?（前回割り込みから 300mS 以上？(長拍)）
		btfsc	STATUS,C	;
		goto	wck_02		;Yes
		goto	wck_03		;No

		; 短拍	rhythm の０ビット目に１を挿入
wck_01		bsf	STATUS,C
		rlf	rhythm,F
		goto	wck_04

		; 長拍	rhythm の０ビット目に０を挿入
wck_02		bcf	STATUS,C
		rlf	rhythm,F
		goto	wck_04

		; 対象外
wck_03		call	cnt_init	;タイマ用カウンタ等初期化
		movlw	1 << st3
		movwf	state		;state = 3 設定

wck_04		return

;==========================================================================

		end			;プログラムの終了
