;------------------------------------------------------------------------------
; TU-876IR
;------------------------------------------------------------------------------
; 2016/03/17 Ver.0.02
;  オートプレイの待機秒数をEEPROMに書き込んだ任意の値に設定できるようにした。
;
; 2016/03/12 Ver.0.01
;  ボタン6個の操作を実装。
;  電源ON後一定時間経過したらPLAYボタンを押すように機能を加えた。 
;
; 2016/03/12 Ver.0.00
;  基板完成、ドリームライトの赤外線受信ルーチンを流用
;------------------------------------------------------------------------------
; デバイス	PIC12F675
; 動作周波数	INTRC 4MHz 組み込み前にキャリブレーションが合っているか確認すること。
;------------------------------------------------------------------------------
	LIST	P=12F675,R=DEC,N=0
	INCLUDE	"P12F675.INC"
	ERRORLEVEL	0,-302,-306,-307
	__CONFIG	0x21C4		; FOSC	= INTOSC(GP4:I/O)
					; WDT	= Disable
					; PWRTE	= Enable
					; MCLRE	= GP3:I/O
					; BODEN = Enable
					; CP	= Not_Protect
					; CPD	= Not_Protect
					; BG	= 2

;------------------------------------------------------------------------------
; 変数宣言 0x20 - 0x5F
;------------------------------------------------------------------------------
IR_STATE	EQU	0x20		; 遷移状態番号 0=初回割り込み 1=Start/Repeat判定 2=データ受信
IR_FLAG		EQU	0x21
IR_COUNT	EQU	0x22		; 受信ビット数カウンタ
IR_DATA		EQU	0x23		; 受信したデータ
IR_DATA0	EQU	0x24		; CUSTOMER1 受信したデータ
IR_DATA1	EQU	0x25		; CUSTOMER2
IR_DATA2	EQU	0x26		; DATA
IR_DATA3	EQU	0x27		; DATA
IR_DATA4	EQU	0x28		; DATA
KEY		EQU	0x29		; GPIOバッファ
STARTCOUNT	EQU	0x2A		; オートプレイの待機秒数カウンタ
ONESECOND	EQU	0x2B		; オートプレイの1秒カウンタ
STARTDELAY	EQU	0x2C		; オートプレイする場合の待機秒数

EEADR_		EQU	0x2D		; eeread, eewriteに渡すアドレス
TMP00		EQU	0x2E
TMP01		EQU	0x2F
TMP02		EQU	0x30


W_		EQU	0x5C		; 割り込み退避用
STATUS_		EQU	0x5D
PCLATH_		EQU	0x5E
FSR_		EQU	0x5F

;------------------------------------------------------------------------------
; 定数宣言
;------------------------------------------------------------------------------
PLAY		EQU	0x20 + 0	; 4051に出力するパターン
STOP		EQU	0x20 + 1
BEFR		EQU	0x20 + 2
NEXT		EQU	0x20 + 3
MODE		EQU	0x20 + 0x10
REPT		EQU	0x20 + 0x11
INHIBIT		EQU	5		; Inhibitビット

AUTOPLAY	EQU	0		; EEPROMアドレス

VALID		EQU	0		; IR_FLAG IR_DATAに有効なデータが入っている、リピート時に使用
NEWDATA		EQU	1		; IR_FLAG リモコンが操作され有効なデータがIR_DATAに受信された
IDLE		EQU	2		; IR_FLAG 無通信の判定

;------------------------------------------------------------------------------
; プログラム開始
;------------------------------------------------------------------------------
	ORG	0
	BSF	STATUS,RP0		; ◆ RP=1
	CALL	0x3FF			; 0x38

	MOVWF	OSCCAL
	GOTO	POWER_ON

;------------------------------------------------------------------------------
; 割り込み分岐
;------------------------------------------------------------------------------
	ORG	4			; 割り込み
	MOVWF	W_			; Wセーブ
	SWAPF	STATUS,W		; STATUSセーブ
	MOVWF	STATUS_
	MOVF	PCLATH,W		; PCLATHセーブ
	MOVWF	PCLATH_
	MOVF	FSR,W			; FSRセーブ
	MOVWF	FSR_
	BCF	STATUS,RP0		; ◆RP=0

IR_CHECK				; 割り込み要因はIRの受信?
	BTFSS	INTCON,INTF
	 GOTO	T1_TIMEOUT
IR
	BCF	INTCON,INTF
	BCF	IR_FLAG,IDLE
	CLRF	PCLATH			; ■ PCLATH
	MOVF	IR_STATE,W		; 受信状態によりジャンプ
	ADDWF	PCL,F
	GOTO	SYNC_1			; 0
	GOTO	SYNC_2			; 1
	GOTO	RECEIVE_NEC		; 2

T1_TIMEOUT				; 割り込み要因は無通信でTimter1がオーバーフロー?
	BTFSS	PIR1,TMR1IF
	 GOTO	INT_RETURN
	BCF	PIR1,TMR1IF
	DECFSZ	ONESECOND,F		; スタートアップカウンタの判定
	 GOTO	T1_IDLE			; 約1秒のカウント ロールオーバーで1秒経過
	MOVLW	15			; 15回カウントの補数
	MOVWF	ONESECOND
	MOVF	STARTCOUNT,W
	BTFSC	STATUS,Z		; スタートアップの無効と完了はカウンタを0と定義する
	 GOTO	T1_IDLE
	DECFSZ	STARTCOUNT,F		; カウンタがロールオーバーして0に戻ったらPLAYを押す
	 GOTO	T1_IDLE
	MOVLW	PLAY
	CALL	KEY_ON
	MOVLW	100			; 100ms後に離す
	CALL	wait
	CALL	KEY_OFF
	
T1_IDLE
	MOVLW	B'00000100'		; IDLEビットを反転
	XORWF	IR_FLAG,F
	BTFSC	IR_FLAG,IDLE		; IDLEフラグがリセットされた時(2回目の反転=131.072ms経過)は強制的に遷移をリセット
	 GOTO	INT_RETURN
	CLRF	IR_STATE
	CLRF	IR_FLAG

INT_RETURN
	MOVF	FSR_,W			; FSRリストア
	MOVWF	FSR
	MOVF	PCLATH_,W		; PCLATHリストア
	MOVWF	PCLATH
	SWAPF	STATUS_,W		; STATUSリストア
	MOVWF	STATUS
	SWAPF	W_,F			; Wリストア
	SWAPF	W_,W
	RETFIE
;------------------------------------------------------------------------------
; 割り込み中のリモコン受信ルーチン
;------------------------------------------------------------------------------
SYNC_1					; フレーム同期1、パルス幅カウンタリセット
	CLRF	TMR1L
	CLRF	TMR1H
	INCF	IR_STATE,F
	GOTO	T1_TIMEOUT

SYNC_2					; フレーム同期2、スタートorリピートを検出
	CLRF	TMR1L			; なるべく早いうちにカウンタをリセットする
	MOVF	TMR1H,W			; 荒いTMR1Hのカウンタで幅を検出
	SUBLW	42			;  11.008ms以下を切り捨て
	BTFSC	STATUS,C
	 GOTO	SYNC_ERROR

	MOVF	TMR1H,W
	SUBLW	45			;  11.520ms以下はNECリピート(11.240ms 20T)
	BTFSC	STATUS,C
	 GOTO	REPEAT
	
	MOVF	TMR1H,W
	SUBLW	51			;  13.312ms以下は切り捨て
	BTFSC	STATUS,C
	 GOTO	SYNC_ERROR

	MOVF	TMR1H,W
	SUBLW	54			;  13.824ms以下はNECスタート(13.488ms 24T)
	BTFSC	STATUS,C
	 GOTO	START_NEC
SYNC_ERROR
	CLRF	IR_STATE		; 同期エラー(IR_STATE=0)
	CLRF	IR_FLAG
	GOTO	T1_TIMEOUT

START_NEC				; NECスタート受信
	CLRF	TMR1H
	MOVLW	2
	MOVWF	IR_STATE
	CLRF	IR_FLAG
	MOVLW	32			; 受信するビット数
	MOVWF	IR_COUNT
	GOTO	T1_TIMEOUT

REPEAT					; リピート受信
	CLRF	IR_STATE		; これ以上遷移しないので同期に戻る IR_STATE=0
	BCF	IR_FLAG,NEWDATA
	BTFSC	IR_FLAG,VALID		; 前回正常な値を受信している場合は、新データとして有効化する。
	 BSF	IR_FLAG,NEWDATA
	GOTO	T1_TIMEOUT

RECEIVE_NEC				; NECフレーム受信
	CLRF	TMR1L			; なるべく早いうちにカウンタをリセットする
	MOVF	TMR1H,W
	SUBLW	3			; 1.024ms以下を切り捨て
	BTFSC	STATUS,C
	 GOTO	SYNC_ERROR		; 同期エラーと同じ処理

	MOVF	TMR1H,W
	SUBLW	5			; 1.280ms以下は0(1.124ms 2T)
	BTFSC	STATUS,C
	 GOTO	NEC_RX0
	
	MOVF	TMR1H,W
	SUBLW	7			; 2.048ms以下は切り捨て
	BTFSC	STATUS,C
	 GOTO	SYNC_ERROR		; 同期エラーと同じ処理

	MOVF	TMR1H,W
	SUBLW	10			; 2.560ms以下は1(2.248ms 4T)
	BTFSC	STATUS,C
	 GOTO	NEC_RX1
	GOTO	SYNC_ERROR		; それ以上は同期エラーと同じ処理

NEC_RX0
	BCF	STATUS,C
	GOTO	NEC_RXSHIFT
NEC_RX1
	BSF	STATUS,C
NEC_RXSHIFT
	CLRF	TMR1H
	RRF	IR_DATA3,F
	RRF	IR_DATA2,F
	RRF	IR_DATA1,F
	RRF	IR_DATA0,F
	DECFSZ	IR_COUNT,F
	 GOTO	T1_TIMEOUT
NEC_VALIDATE				; カスタマーコードの検証
	MOVLW	0x08			; CC#1
	SUBWF	IR_DATA0,W
	BTFSS	STATUS,Z
	 GOTO	SYNC_ERROR		; 同期エラーと同じ処理
	MOVLW	0xF7			; CC#2
	SUBWF	IR_DATA1,W
	BTFSS	STATUS,Z
	 GOTO	SYNC_ERROR		; 同期エラーと同じ処理
	
	COMF	IR_DATA2,W		; データの検証
	XORWF	IR_DATA3,W		; 反転されたデータとXORを取り0になったら一致していると判断。
	BTFSS	STATUS,Z
	 GOTO	SYNC_ERROR		; 同期エラーと同じ処理
	MOVF	IR_DATA2,W
	MOVWF	IR_DATA
	CLRF	IR_STATE
	BSF	IR_FLAG,VALID
	BSF	IR_FLAG,NEWDATA
	GOTO	T1_TIMEOUT

;------------------------------------------------------------------------------
; 電源投入時の初期化
;------------------------------------------------------------------------------
POWER_ON				; 電源ON
	BCF	STATUS,RP0		; ◆ RP=0
	MOVLW	B'00100000'		; 5=Inhibit, 410:CBA 2:/IR_INT
	MOVWF	GPIO
	MOVLW	0x07			; コンパレータOFF
	MOVWF	CMCON
	CLRF	TMR1L
	CLRF	TMR1H
	MOVLW	B'00000001'		; IRのパルス幅計測タイマー
	MOVWF	T1CON

	BSF	STATUS,RP0		; ◆ RP=1
	MOVLW	B'00111111'		; GPIOプルアップ,立下げ割り込み
	MOVWF	OPTION_REG		; bit3:FPS = 0:61Hz 1:122Hz
	CLRF	ANSEL			; A/D OFF ※12F629を使うときは不要
	MOVLW	B'00001100'
	MOVWF	TRISIO			; 5=Inhibit, 410:CBA 2:/IR_INT
	MOVLW	B'00000001'
	MOVWF	PIE1			; Timer1割り込み
	
	BCF	STATUS,RP0		; ◆ RP=0
	CLRF	IR_STATE
	CLRF	IR_FLAG
	CLRF	KEY

	MOVLW	AUTOPLAY		; オートプレイの設定値をロードする
	MOVWF	EEADR_			; OFF=0
	CALL	eeread			; ON =希望する秒数
	MOVWF	STARTCOUNT
	MOVLW	15
	MOVWF	ONESECOND		; 65.536ms * 15 = 983ms

	INCF	EEADR_,F		; オートプレイの規定値をロードする
	CALL	eeread
	MOVWF	STARTDELAY
BEFORE_LOOP
	MOVLW	B'11010000'		; GIE,PEIE,T0IE,INTE
	MOVWF	INTCON
;------------------------------------------------------------------------------
; メインループ
;------------------------------------------------------------------------------
MAINLOOP
	BTFSS	IR_FLAG,VALID		; リピートが無効になる時間を経過してデータが無効になったらInhibitさせる
	 CALL	KEY_OFF
	BTFSS	IR_FLAG,NEWDATA		; リモコン入力があるまで待機
	 GOTO	MAINLOOP
	BCF	IR_FLAG,NEWDATA
	CLRF	STARTCOUNT		; オートプレイ前にキーが操作された時、自動でPLAYが押されないように機能を止める。
	MOVF	IR_DATA,W
	MOVWF	TMP00
;---- sparkfun COM-11759
B_POWER
	MOVLW	0x1B
	SUBWF	TMP00,W
	BTFSS	STATUS,Z
	 GOTO	B_A
	;B_POWER
	MOVLW	PLAY		; PLAY
	CALL	KEY_ON
	GOTO	MAINLOOP
B_A
	MOVLW	0x1F
	SUBWF	TMP00,W
	BTFSS	STATUS,Z
	 GOTO	B_B
	;B_A
	MOVLW	BEFR		; BEFR
	CALL	KEY_ON
	GOTO	MAINLOOP
B_B
	MOVLW	0x1E
	SUBWF	TMP00,W
	BTFSS	STATUS,Z
	 GOTO	B_C
	;B_B
	MOVLW	STOP		; STOP
	CALL	KEY_ON
	GOTO	MAINLOOP
B_C
	MOVLW	0x1A
	SUBWF	TMP00,W
	BTFSS	STATUS,Z
	 GOTO	B_UP
	;B_C
	MOVLW	NEXT		; NEXT
	CALL	KEY_ON
	GOTO	MAINLOOP
B_UP
	MOVLW	0x05
	SUBWF	TMP00,W
	BTFSS	STATUS,Z
	 GOTO	B_RIGHT
	;B_UP
	MOVLW	MODE		; MODE
	CALL	KEY_ON
	GOTO	MAINLOOP
B_RIGHT
	MOVLW	0x01
	SUBWF	TMP00,W
	BTFSS	STATUS,Z
	 GOTO	B_DOWN
	;B_RIGHT
	MOVLW	AUTOPLAY	; オートプレイON
	MOVWF	EEADR_
	CALL	eeread
	SUBWF	STARTDELAY,W
	BTFSC	STATUS,Z
	 GOTO	MAINLOOP
	MOVF	STARTDELAY,W
	CALL	eewrite
	MOVLW	PLAY		; PLAY
	CALL	KEY_ON		; 結果が分かるようにボタンを操作する
	GOTO	MAINLOOP
B_DOWN
	MOVLW	0x00
	SUBWF	TMP00,W
	BTFSS	STATUS,Z
	 GOTO	B_LEFT
	;B_DOWN
	GOTO	MAINLOOP
B_LEFT
	MOVLW	0x08
	SUBWF	TMP00,W
	BTFSS	STATUS,Z
	 GOTO	B_CENTER
	;B_LEFT
	MOVLW	AUTOPLAY	; オートプレイOFF
	MOVWF	EEADR_		; キーリピートで何度も書き込まれないように、
	CALL	eeread		; 値をテストしてから書き込みを行う。
	MOVLW	0
	BTFSC	STATUS,Z
	 GOTO	MAINLOOP
	CALL	eewrite
	MOVLW	STOP		; STOP
	CALL	KEY_ON		; 結果が分かるようにボタンを操作する
	GOTO	MAINLOOP
B_CENTER
	MOVLW	0x04
	SUBWF	TMP00,W
	BTFSS	STATUS,Z
	 GOTO	MAINLOOP
	;B_CENTER
	MOVLW	REPT		; REPT
	CALL	KEY_ON
	GOTO	MAINLOOP

KEY_ON
	MOVWF	KEY
	BCF	KEY,INHIBIT
OUTPUT
	MOVF	KEY,W
	MOVWF	GPIO
	RETURN

KEY_OFF
	BSF	KEY,INHIBIT
	GOTO	OUTPUT

;------------------------------------------------------------------------------
; EEPROMアクセスルーチン
;  eeread	内蔵EEPROMのアドレスEEADR_から読み出してデータをWに入れる
;------------------------------------------------------------------------------
eeread
	BSF	STATUS,RP0		; ◆ RP=1
	MOVF	EEADR_,W
	MOVWF	EEADR
	BSF	EECON1,RD
	MOVF	EEDATA,W
	BCF	STATUS,RP0		; ◆ RP=0
	RETURN

;------------------------------------------------------------------------------
; eewrite	データWを内蔵EEPROMのアドレスEEADR_へ書き込む
;------------------------------------------------------------------------------
eewrite
	BSF	STATUS,RP0		; ◆ RP=1
	MOVWF	EEDATA
EEWRITEPOLL
	BTFSC	EECON1,WR		; 前回の書き込みが終わるまでループ
	 GOTO	EEWRITEPOLL
	MOVF	EEADR_,W
	MOVWF	EEADR
	BCF	INTCON,GIE		; 割り込み禁止
	BSF	EECON1,WREN
	MOVLW	0x55			; 書き込みパターン
	MOVWF	EECON2
	MOVLW	0xAA
	MOVWF	EECON2
	BSF	EECON1,WR		; 書き込み
	BSF	INTCON,GIE		; 割り込み許可
	BCF	EECON1,WREN		; 書き込み保護
	BCF	STATUS,RP0		; ◆ RP=0
	RETURN

;------------------------------------------------------------------------------
; ウエイトルーチン群
;------------------------------------------------------------------------------
lwait					; 長時間ウエイト
	MOVWF	TMP02
lwait1
	MOVLW	255
	CALL	wait
	DECFSZ	TMP02,F
	GOTO	lwait1
	RETURN

wait					; ミリ秒ウエイト
	MOVWF	TMP01			; Wにループ回数をセット後CALL
wait1
	MOVLW	255
	MOVWF	TMP00
wait2
	NOP
	DECFSZ	TMP00,F
	GOTO	wait2
	DECFSZ	TMP01,F
	GOTO	wait1
	RETURN

;------------------------------------------------------------------------------
; EEPROMの初期値
;------------------------------------------------------------------------------
	ORG	0x2100	
	DA	0	; AUTOSTARTの設定値
	DA	20	; STARTDELAYにロードされる
	END