;------------------------------------------------------------------------------
; 振りスク
;------------------------------------------------------------------------------
; バージョン履歴
;
; Ver.1.0 2005/2/11
;	12C509Aへの移植と若干のコード変更。回路完成。
;
; Ver.0.9 2005/2/10
;	16F876プロトタイプ版のデバッグ完了。
;
; Ver.0.0 2005/2/7
;	基本回路完成。16F876にて開発開始。操作方法考案。
;
; Ver.-.- 2005/2/4
;	発案。

;------------------------------------------------------------------------------
; デバイス	PIC12C509A
; 動作周波数	32.768kHz
; FOSC	=LP
; WDTE	= Disable
; MCLRE	= MCLRpim
;------------------------------------------------------------------------------
	LIST	P=12C509A,R=DEC,N=0
	INCLUDE	"P12C509A.INC"
	ERRORLEVEL	0,-302,-306,-307

;------------------------------------------------------------------------------
; 変数宣言
;------------------------------------------------------------------------------
TIMER_H		EQU	0x07		; 上位カウント時間
TIMER_L		EQU	0x08		; 下位カウント時間
LIMIT_H		EQU	0x09		; 上位カウントリミット
LIMIT_L		EQU	0x0A		; 下位カウントリミット
TIMER		EQU	0x0B		; 分数のインデックス値
VIBRATOR	EQU	0x0C		; カウント終了時のバイブレータの振動パターン
FLAG		EQU	0x0D		; フラグ

TMP0		EQU	0x10
TMP1		EQU	0x11
TMP2		EQU	0x12
TMP3		EQU	0x13

;------------------------------------------------------------------------------
; 定数宣言
;------------------------------------------------------------------------------
MOTOR		EQU	0		; GPIO-0 モータ出力
SW		EQU	1		; GPIO-1,FLAG-1 スイッチ入力
LED		EQU	2		; GPIO-2 LED出力
CONTINUE	EQU	0		; FLAG-0 カウントを終了しても、カウントを続ける
N_TIMER		EQU	11		; タイマインデックスの個数(1,2,3,5,10,15,20,30,45,60,90)0分は含まない

;------------------------------------------------------------------------------
; メインプログラム
;------------------------------------------------------------------------------
		ORG	0
INIT_SFR				; SFRの初期化
	CLRF	GPIO			; 出力ポートのリセット
	MOVLW	B'10010110'		; プルアップあり、内部クロックタイマ
	OPTION				; キー待ちタイマ用プリスケーラ、1:128
	MOVLW	B'11111010'		; I/Oの方向設定
	TRIS	GPIO

PD_CHK					; パワーダウンチェック
	BTFSS	STATUS,NOT_PD		; 電池投入時の/PDビットがセットされているか?
	GOTO	SW_CHK
PD_INIT					; 電池交換時の初期化
	MOVLW	1			; パターン初期化
	MOVWF	VIBRATOR
	CLRF	FLAG
	MOVLW	B'00000101'		; LEDとモータの動作テストのため出力
	MOVWF	GPIO
	MOVLW	0			; ウエイト
	CALL	wait
	CLRF	GPIO			; 出力OFF
	SLEEP				; 終了

SW_CHK					; 起動モードチェック
	CALL	getkey			; /MCLRウェイク時、SWでバイブ変更モードへ移る
	BTFSS	FLAG,SW
	GOTO	CHG_TIMER
CHG_VIBRATOR				; バイブパターン変更モード
	INCF	VIBRATOR,F
	MOVLW	B'00000001'		; FLAG(CONTINUE)反転用
	BTFSC	VIBRATOR,2		; 3->4に繰り上がった時
	XORWF	FLAG,F			; 0ビット目だけを反転
	MOVLW	B'00000011'		; VIBRATORをマスク
	ANDWF	VIBRATOR,F

	BTFSC	FLAG,CONTINUE		; ループモードならLEDをつけて知らせる
	BSF	GPIO,LED
	MOVLW	B'10010100'		; プリスケーラの変更
	OPTION				; 1秒タイマ用プリスケーラ、1:32
	CLRF	TMR0
	CALL	vibrate			; バイブレータテスト
	BCF	GPIO,LED
	SLEEP				; 終了

CHG_TIMER				; タイマ時間の変更
	BSF	GPIO,LED		; 電源ON確認用のLED
	MOVLW	128			; ウエイト
	CALL	wait
	CLRF	GPIO			; 出力OFF

	CLRF	TIMER			; インデックスを初期化
	CLRF	TMR0			; タイムアウト(2秒)を初期化
	CLRF	TMP0			; ロールオーバー検出をリセット
CHG_TIMER_LOOP				; タイムアウトループ
	CALL	getkey			; キー入力がある場合は、分数をインクリメント
	BTFSS	FLAG,SW
	GOTO	CHG_TIMER_TIMEOUT	; 入力がない場合は、タイムアウト処理
	INCF	TIMER,F
	MOVLW	N_TIMER+1		; タイマの分数設定が最大値を超えたら
	SUBWF	TIMER,W			; (Zフラグがセットされたら)
	MOVLW	1
	BTFSC	STATUS,Z
	MOVWF	TIMER			; 1分に戻す(0分には戻さない)
	MOVLW	B'00000100'		; 確認用LED出力ON
	MOVWF	GPIO
	CALL	keyrel			; キーのリリースを待つ
	CLRF	GPIO			; LED OFF
	CLRF	TMR0			; タイムアウト(2秒)を初期化
	CLRF	TMP0			; ロールオーバー検出をリセット
CHG_TIMER_TIMEOUT			; キー入力待ちのタイムアウト
	MOVF	TMR0,W			; ロールオーバーの検出中にロールしないように
	MOVWF	TMP1			; 先に値をバックアップしておく
	MOVF	TMP0,W			; 2秒のタイムアウトがかかったか?
	SUBWF	TMP1,W			; (TMR0-TMP0がマイナスになったとき(0-255))
	MOVF	TMP1,W			; タイマのバックアップを反映
	MOVWF	TMP0
	BTFSS	STATUS,C		; Cフラグがセットの時、まだ続ける
	GOTO	TIME_LOAD		; Cフラグがクリアの時、分数のロードへ進む
	GOTO	CHG_TIMER_LOOP

TIME_LOAD				; 分数のロード
	MOVF	TIMER,W			; インデックスのロード
	BTFSS	STATUS,Z		; もしインデックスが0の時は、カウントせずスリープ
	GOTO	TIME_LOAD1
	SLEEP

TIME_LOAD1				; ロード
	CALL	get_time
TIME_COUNT				; タイムカウント
	MOVLW	B'10010100'		; プリスケーラの変更
	OPTION				; 1秒タイマ用プリスケーラ、1:32

	MOVF	TIMER,W			; 分数をスイッチで押した数だけバイブ(確認用)
	MOVWF	TMP0
	BTFSC	FLAG,CONTINUE		; ループモードならLEDをつけて知らせる
	BSF	GPIO,LED
	CLRF	TMR0
TIME_COUNT_TIMES_ON
	BSF	GPIO,MOTOR		; モータ出力ON
	BTFSS	TMR0,5			; ウエイト
	GOTO	TIME_COUNT_TIMES_ON
TIME_COUNT_TIMES_OFF1
	BCF	GPIO,MOTOR		; モータ出力OFF 1/4デューティーで回転
	BTFSS	TMR0,6			; ウエイト
	GOTO	TIME_COUNT_TIMES_OFF1
TIME_COUNT_TIMES_OFF2
	BTFSC	TMR0,6			; ウエイト
	GOTO	TIME_COUNT_TIMES_OFF2

	DECFSZ	TMP0,F
	GOTO	TIME_COUNT_TIMES_ON
	BCF	GPIO,LED		; 無条件でLED OFF

	CLRF	TMR0
TIME_COUNT_START			; ループモード時の開始場所
	CLRF	TMP0			; ロールオーバー検出をリセット
	CLRF	TIMER_H			; タイマー初期化
	CLRF	TIMER_L
TIME_COUNT_LOOP				; 1秒ごとのタイマーループ
	MOVF	TMR0,W			; ロールオーバーの検出中にロールしないように
	MOVWF	TMP1			; 先に値をバックアップしておく
	MOVF	TMP0,W			; 1秒のタイムアウトがかかったか?
	SUBWF	TMP1,W			; (TMR0-TMP0がマイナスになったとき(0-255))
	MOVF	TMP1,W			; タイマのバックアップを反映
	MOVWF	TMP0
	BTFSS	STATUS,C		; Cフラグがセットの時、まだループ
	GOTO	TIME_COUNT_CMP		; Cフラグがクリアの時、秒数を比較
	GOTO	TIME_COUNT_LOOP
TIME_COUNT_CMP				; タイマー満了を比較
;	MOVLW	B'00000100'		; 1秒ごとにLED出力ON
;	MOVWF	GPIO
;	MOVLW	1			; ウエイト
;	CALL	wait
;	CLRF	GPIO			; 出力OFF

	MOVLW	1			; INCFではCフラグに影響しない;;
	ADDWF	TIMER_L,F
	BTFSC	STATUS,C		; 桁上がりしたなら、上位もインクリメント
	INCF	TIMER_H,F

	MOVF	TIMER_L,W		; 下位から比較したほうが、条件に一致するものが少ない
	SUBWF	LIMIT_L,W
	BTFSS	STATUS,Z		; 下位が一致したものは、上位もチェック
	GOTO	TIME_COUNT_LOOP		; 一致しなかった時
	MOVF	TIMER_H,W		; 上位の比較
	SUBWF	LIMIT_H,W
	BTFSS	STATUS,Z		; 一致?
	GOTO	TIME_COUNT_LOOP		; 一致しなかった時
TIME_UP					; タイマー満了
	CALL	vibrate			; カウント終了
	BTFSC	FLAG,CONTINUE		; ループモードの時は戻る
	GOTO	TIME_COUNT_START
	CALL	vibrate			; ループしない場合は4秒間バイブする
	SLEEP				; カウント終了

;------------------------------------------------------------------------------
; バイブレーションルーチン
;------------------------------------------------------------------------------
vibrate					; CALLするとVIBRATORで示す周期で2秒間バイブする
	MOVF	VIBRATOR,W		; VIBRATORの値ごとにルーチンを作ってしまう
	ADDWF	PCL,F
	GOTO	vibrate_0
	GOTO	vibrate_1
	GOTO	vibrate_2
	GOTO	vibrate_3

vibrate_0
	MOVLW	2			; 2回変化する
	MOVWF	TMP2
vibrate_0_start
	MOVLW	B'00000001'
	XORWF	GPIO,F			; 出力反転
	CLRF	TMP0
vibrate_0_wait
	MOVF	TMR0,W			; ロールオーバーの検出中にロールしないように
	MOVWF	TMP1			; 先に値をバックアップしておく
	MOVF	TMP0,W			; 1秒のタイムアウトがかかったか?
	SUBWF	TMP1,W			; (TMR0-TMP0がマイナスになったとき(0-255))
	MOVF	TMP1,W			; タイマのバックアップを反映
	MOVWF	TMP0
	BTFSS	STATUS,C		; Cフラグがセットの時、まだループ
	GOTO	vibrate_0_loop		; Cフラグがクリアの時、秒数を比較
	GOTO	vibrate_0_wait
vibrate_0_loop
	DECFSZ	TMP2,F
	GOTO	vibrate_0_start
	RETLW	0

vibrate_1
	MOVLW	4			; 4回変化する
	MOVWF	TMP0
vibrate_1_start
	CLRF	TMR0
	MOVLW	B'00000001'
	XORWF	GPIO,F			; 出力反転
vibrate_1_wait
	BTFSS	TMR0,7			; ウエイト
	GOTO	vibrate_1_wait
	DECFSZ	TMP0,F
	GOTO	vibrate_1_start
	RETLW	0

vibrate_2
	MOVLW	8			; 8回変化する
	MOVWF	TMP0
vibrate_2_start
	CLRF	TMR0
	MOVLW	B'00000001'
	XORWF	GPIO,F			; 出力反転
vibrate_2_wait
	BTFSS	TMR0,6			; ウエイト
	GOTO	vibrate_2_wait
	DECFSZ	TMP0,F
	GOTO	vibrate_2_start
	RETLW	0

vibrate_3
	MOVLW	16			; 16回変化する
	MOVWF	TMP0
vibrate_3_start
	CLRF	TMR0
	MOVLW	B'00000001'
	XORWF	GPIO,F			; 出力反転
vibrate_3_wait
	BTFSS	TMR0,5			; ウエイト
	GOTO	vibrate_3_wait
	DECFSZ	TMP0,F
	GOTO	vibrate_3_start
	RETLW	0

;------------------------------------------------------------------------------
; スイッチ入力ルーチン群
;------------------------------------------------------------------------------
getkey					; スイッチ入力
	BTFSS	GPIO,SW			; 入力はプルアップで負論理入力
	GOTO	keyon
keyoff
	BCF	FLAG,SW			; フラグのビットは正論理で表現
	RETLW	0
keyon					; 入力があるときは、チャタリング処理
	MOVLW	150
	CALL	wait
	BTFSC	GPIO,SW
	GOTO	keyoff
	BSF	FLAG,SW
	RETLW	0

keyrel					; キー離しチェック
	BTFSS	GPIO,SW			; チャタリング処理
	GOTO	keyrel
	MOVLW	100
	CALL	wait
	BTFSS	GPIO,SW
	GOTO	keyrel
	RETLW	0

;------------------------------------------------------------------------------
; ウエイトルーチン
;------------------------------------------------------------------------------
wait					; Wに値をセットしてコール
	MOVWF	TMP3
wait_loop
	DECFSZ	TMP3,F
	GOTO	wait_loop
	RETLW	0

;------------------------------------------------------------------------------
; タイムテーブル
;------------------------------------------------------------------------------
get_time
	MOVF	TIMER,W			; LIMIT_Hロード
	CALL	INDEX_LIMIT_H
	MOVWF	LIMIT_H
	MOVF	TIMER,W			; LIMIT_Lロード
	CALL	INDEX_LIMIT_L
	MOVWF	LIMIT_L
	MOVLW	2			; ループモードの時は、ループ時間の2秒を引く
	BTFSC	FLAG,CONTINUE
	SUBWF	LIMIT_L,F
	RETLW	0

INDEX_LIMIT_H
	ADDWF	PCL,F
	RETLW	0x00			; 0 0000 0分(ダミー)
	RETLW	0x00			; 1 003C 1分
	RETLW	0x00			; 2 0078 2分
	RETLW	0x00			; 3 00B4 3分
	RETLW	0x01			; 4 012C 5分
	RETLW	0x02			; 5 0258 10分
	RETLW	0x03			; 6 0384 15分
	RETLW	0x04			; 7 04B0 20分
	RETLW	0x07			; 8 0708 30分
	RETLW	0x0A			; 9 0A8C 45分
	RETLW	0x0E			; 10 0E10 60分
	RETLW	0x15			; 11 1518 90分

INDEX_LIMIT_L
	ADDWF	PCL,F
	RETLW	0x00			; 0分(ダミー)
	RETLW	0x3C			; 1分
	RETLW	0x78			; 2分
	RETLW	0xB4			; 3分
	RETLW	0x2C			; 5分
	RETLW	0x58			; 10分
	RETLW	0x84			; 15分
	RETLW	0xB0			; 20分
	RETLW	0x08			; 30分
	RETLW	0x8C			; 45分
	RETLW	0x10			; 60分
	RETLW	0x18			; 90分

	END
