;***** ElectDice.asm ******************************************************
;
;	赤い電子サイコロ（Electronic Dice）
;
;	origin:  電子マスカット (http://www.zea.jp/audio) by yasuyuki-ishizuka
;
;     ( coding:  Ver. 0.00   2006/01/02  by M.Yamamoto )
;	coding:  Ver. 1.00   2006/01/03  初期バージョン
;	update:  Ver. 1.10   2006/01/04  ハードウェアの変更
;	bugfix:  Ver. x.xx
;
;******************************************************* PicAsm 0201 ******

;	オリジナルとの主な相違点

;		ハードウェアの変更
;		・LED の各群のポート割付を変更。
;		・LED の各群の接続を並列から直列に変更。
;		・LED を青色から安価な赤色に変更。
;		・音量設定用ボリュームを付加。

;	PIC12F629 のピンと用途

;		① Vdd	電源 +4.5V DC		⑧ Vss	電源 GND
;		② GP5	OUT ブザー出力		⑦ GP0	OUT LED_A 群
;		③ GP4	OUT LED_D 群	　	⑥ GP1	OUT LED_B 群
;		④ GP3	IN  スタートスイッチ	⑤ GP2	OUT LED_C 群

;==========================================================================
;	環境設定
;==========================================================================

; PIC12F629 では、固体ごとに異なっていて工場出荷時に書き込まれている、以下の
; 2つのキャリブレーション情報を考慮する必要がある

; BANDGAP 値:  CONFIGURATION WORD (ADDRESS: 2007h) の bit13,12 に記録
;              ブラウンアウトリセット、パワーオンリセット等で使う電圧の敷居値
;              を校正する値

BandGapVal	equ		h'11FF'		;固体ごとに異なる

; OSCCAL 値:   プログラムエリアの最終番地 3FFh に記録
;              内部発振回路を使うときの発振周波数を校正する値			

OscCalVal	equ		h'34D8'		;固体ごとに異なる

		list		P=PIC12F629	;デバイス情報
		include        "P12F629.INC"	;インクルードファイル
		errorlevel	-302		;Eliminate bank warning

		__config	BandGapVal & _CPD_OFF & _CP_OFF & _BODEN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

;==========================================================================
;	変数の定義とレジスタ割付け
;==========================================================================

		cblock	h'20'
beept					;ブザー音の周期を決めるレジスタ
time1					;タイムディレイに使う
time2					;タイムディレイに使う
time3					;タイムディレイに使う
count1					;1～12まで変化するカウンタ（乱数として使用）
count2					;スリープへ移行するまでのカウンタ
count3					;スリープへ移行するまでのカウンタ
count4					;スリープへ移行するまでのカウンタ
saime					;サイコロの目
slowcnt					;低速回転数
		endc

;==========================================================================
;	プログラム開始
;==========================================================================

		org	h'0000'		;Reset Vector
		goto	initset
		org	h'0004'		;Interrupt Vector
		goto	initset

;==========================================================================
;	初期化処理
;==========================================================================

initset
		bsf	STATUS,RP0	;バンク 1
		call	h'03ff'		;内部発振周波数校正値の読み込み
		movwf	OSCCAL		;OSCCAL に校正値を保存
		movlw	b'00001000'	;GP3 のみ入力、その他を出力端子に設定
		movwf	TRISIO
		movlw	b'00000000'	;オプション設定（念のため設定）
		movwf	OPTION_REG
		movlw	b'00001000'	;GP3 を状態変化として使用
		movwf	IOC
		bcf	STATUS,RP0	;バンク 0
		clrf	GPIO
		movlw	b'00000111'	;GP2-0 を Digital I/O
		movwf	CMCON		;CMCON の設定
		movlw	b'00001000'	;GPIO 変化割り込み有効
		movwf	INTCON		;SLEEP からの wake-up のみで使用のため GIE は立てない

		movlw	d'6'
		movwf	saime		;saime レジスタの初期設定

;==========================================================================
;	メイン・ルーチン
;==========================================================================

start
		call	led_all_on	;LED 全点灯
		call	t100ms
		clrf	GPIO		;LED 全消灯

		call	t10ms
		call	led_all_on	;LED 全点灯
		call	beep		;beep音
		call	t10ms
		clrf	GPIO		;LED 全消灯

		call	t10ms
		call	led_all_on	;LED 全点灯
		call	beep		;beep音
		call	t10ms
		clrf	GPIO		;LED 全消灯

		call	t10ms
		call	led_all_on	;LED 全点灯
		call	beep

		; ゲーム開始
game					;実ゲーム前にスイッチが離れていることを確認
		btfss	GPIO,3		;キーが離されるのを待つ
		goto	game

		call	t50ms

		; スタートスイッチの押下待ち (一定時間経過でスリープに移行)
game1
		movlw	d'30'		;スリープへ移行する初期値（1の増減で約1秒変化する）:初期値は約30秒
		movwf	count2

game1a		movlw	d'100'		;スリープへ移行する初期値
		movwf	count3

game1b		movlw	d'155'		;スリープへ移行する初期値
		movwf	count4

game1c		movlw	d'12'		;スタートスイッチが押下されるまでにcount1レジスタは1～12まで高速に変化する
		movwf	count1		;これを乱数とみなして最後の低速回転数を決める

game1d		btfss	GPIO,3		;スタートスイッチが押下されている か?
		goto	game2		;Yes

		decfsz	count1,f
		goto	game1d
		decfsz	count4,f
		goto	game1c
		decfsz	count3,f
		goto	game1b
		decfsz	count2,f
		goto	game1a

		call	beep		;SLEEP へ移行する手順へ
		call	t20ms
		call	beep
		clrf	GPIO		;SLEEP へ移行する前に全消灯させる
		bcf	INTCON,GPIF	;SLEEP 寸前に GPIF ビットをクリア
		sleep			;ここでスリープ
		nop
		goto	start		;Wake-UP

		; 低速回転数確定部
game2
		movlw	d'6'		;最低 6回 転がす
		addwf	count1,f

game2a		movf	count1,w	;count1 レジスタを slowcnt レジスタに転送
		movwf	slowcnt

		; 高速回転ルーチン
game3
		call	led_disp
		call	t5ms
		btfsc	GPIO,3		;スタートスイッチが離された か?
		goto	game4		;Yes
		goto	game3

		; 低速回転ルーチン
game4
		call	led_disp
		call	t50ms
		btfss	GPIO,3		;低速回転中にスタートスイッチが押下された か?
		goto	game2a		;Yes

		decfsz	slowcnt,f	;算出した低速回転数を回して確定される
		goto	game4

		call	t300ms
		call	beep5		;ブザーを 5回 鳴らしてゲーム開始へ
		goto	game

;==========================================================================
;	LED 表示ルーチン（呼び出される毎に表示をカウントダウン）
;==========================================================================

led_disp
		movf	saime,w
		call	digit			;saime カウンタの数字に該当するビット情報に変換
		movwf	GPIO			;ビット情報を出力
		call	beep			;ブザー音
		decfsz	saime,f			;saime カウンタを1つ減算
		return

		movlw	d'6'			;saime カウンタが 0 だったら 6 に設定
		movwf	saime
		return

;		① Vdd	電源 +4.5V DC		⑧ Vss	電源 GND
;		② GP5	OUT ブザー出力		⑦ GP0	OUT LED_A 群
;		③ GP4	OUT LED_D 群	　	⑥ GP1	OUT LED_B 群
;		④ GP3	IN  スタートスイッチ	⑤ GP2	OUT LED_C 群

;		Ｃ　Ｂ		1 の目の表示 = Ａ	4 の目の表示 = Ｂ+Ｃ
;		ＤＡＤ		2 の目の表示 = Ｂ	5 の目の表示 = Ａ+Ｂ+Ｃ
;		Ｂ　Ｃ		3 の目の表示 = Ａ+Ｂ	6 の目の表示 = Ｂ+Ｃ+Ｄ

		; 数字に該当するビット情報に変換
digit
		addwf	PCL,f
		retlw	b'00011111'		;0: ダミー (使われない)
		retlw	b'00001001'		;1: 1 の目を表示するときのビット状態
		retlw	b'00001010'		;2: 2 の目を表示するときのビット状態
		retlw	b'00001011'		;3: 3 の目を表示するときのビット状態
		retlw	b'00001110'		;4: 4 の目を表示するときのビット状態
		retlw	b'00001111'		;5: 5 の目を表示するときのビット状態
		retlw	b'00011110'		;6: 6 の目を表示するときのビット状態

		; LED 全点灯
led_all_on
		movlw	b'00010111'		;全点灯
		movwf	GPIO
		return

;==========================================================================
;	beep サウンド
;==========================================================================

beep
		movlw	d'48'
		movwf	beept

beep1		bsf	GPIO,5
		call	t50us
		bcf	GPIO,5
		call	t50us
		decfsz	beept,f
		goto	beep1
		return

		; beep を 5 回発生
beep5
		call	beep
		call	t20ms
		call	beep
		call	t20ms
		call	beep
		call	t20ms
		call	beep
		call	t20ms
		call	beep
		return

;==========================================================================
;	タイムディレイライブラリ（時間はおおよその値）
;==========================================================================

		; 50 μs ディレイ
t50us
		movlw	d'48'
		movwf	time1

t50us1		decfsz	time1,f
		goto	t50us1
		return

		; 1 ms ディレイ
t1ms
		movlw	d'8'
		movwf	time2

t1ms1		movlw	d'125'
		movwf	time3

t1ms2		decfsz	time3,f
		goto	t1ms2			

		decfsz	time2,f
		goto	t1ms1
		return

		; 5 ms ディレイ
t5ms
		call	t1ms
		call	t1ms
		call	t1ms
		call	t1ms
		call	t1ms
		return

		; 10 ms ディレイ
t10ms
		call	t5ms
		call	t5ms
		return

		; 20 ms ディレイ
t20ms
		call	t10ms
		call	t10ms
		return

		; 50 ms ディレイ
t50ms
		call	t10ms
		call	t20ms
		call	t20ms
		return

		; 100 ms ディレイ
t100ms
		call	t50ms
		call	t50ms
		return

		; 300 ms ディレイ
t300ms
		call	t100ms
		call	t100ms
		call	t100ms
		return

;==========================================================================
;	発振周波数校正値呼び出しルーチン
;==========================================================================

		org		h'03ff'		;最終番地
		retlw		low OscCalVal	;内部発振では必要

		end		
