; 16F876_Solarkettle.asm						2005/04/19 22:59:09

; 					RB7 +10		input L			RC7 上回転	output L
;					RB6 +1		input L			RC6 下回転	output L
; RA5 AN4	analoginput 温度	RB5 7SEG-MSB	output L		RC5 左回転	output L
; RA4 PUMP	output L ポンプ		RB4 7SEG-LSB	output L		RC4 右回転	output L
; RA3 AN3	analoginput 上		RB3 7SEG-D	output			RC3 上Limit SW	input L
; RA2 AN2	analoginput 下		RB2 7SEG-C	output			RC2 下Limit SW	input L
; RA1 AN1	analoginput 左		RB1 7SEG-B	output			RC1 左Limit SW	input L
; RA0 AN0	analoginput 右		RB0 7SEG-A	output			RC0 右Limit SW	input L
; TRISA		b'00101111'		TRISB		b'11000000'		TRISC		b'00001111'

	list		p=PIC16F876
	#include	<P16F876.INC>

	__CONFIG	_CP_OFF & _CPD_OFF & _BODEN_OFF & _DEBUG_OFF & _HS_OSC & _LVP_OFF & _PWRTE_ON & _WDT_OFF & _WRT_ENABLE_ON

	CBLOCK	20H
	F_control		; 2^0 温度制御フラグ 0:制御中(設定温度>測定温度) 1:待機中(設定温度<測定温度)
				; 2^1 テストモード
				; 2^7 +10前回ON 2^6 +1前回ON
	work			; 汎用バッファ for main
	iq_work			; 汎用バッファ for intrqt
	RB_buff			; PORTB 出力用バッファ
	RC_buff			; PORTC 出力用バッファ
	one_conton		; +1連続カウンタ
	ten_conton		; +10連続カウンタ
	sseg_cnt		; MSB LSB 切換カウンタ
	set_LSB			; 温度設定値
	set_MSB
	set_BIN			; 2進数 温度設定値
	tmp_LSB			; 温度表示データ(10進)
	tmp_MSB
	tmp_BIN			; 2進数 温度
	adbuf4			; 温度 A/D変換値
	adbuf3			; 上   A/D変換値
	adbuf2			; 下   A/D変換値
	adbuf1			; 左   A/D変換値
	adbuf0			; 右   A/D変換値
	dipadc			; 表示A/D変換値 for テストモード
	cntdutyUD		; カウンタ for 上下duty
	cntdutyLR		; カウンタ for 左右duty
	cnt20u			; カウンタ for 20μsec
	cntxxm			; カウンタ for xxmsec

	W_temp
	FSR_temp
	STATUS_temp
	pclath_temp
	ENDC

dutyUD	equ	1		; 上下 duty 1/2
dutyLR	equ	1		; 左右 duty 1/1

	org	0
	BANKSEL	ADCON1
	goto	start

	org	4
	movwf	W_temp		; save W
	movf	STATUS,W
	movwf	STATUS_temp	; save STATUS
	movf	FSR,W
	movwf	FSR_temp	; save FSR
	movf	PCLATH,W
	movwf	pclath_temp	; save PCLATH
	call	intrqt
	movf	pclath_temp,W
	movwf	PCLATH		; restore PCLATH
	movf	FSR_temp,W
	movwf	FSR		; restore FSR
	movf	STATUS_temp,W
	movwf	STATUS		; restore STATUS
	swapf	W_temp,F
	swapf	W_temp,W	; restore W
	retfie

start	movlw	b'00000010'	; 左詰め AN4～AN0
	movwf	ADCON1
	movlw	b'00101111'
	movwf	TRISA
	movlw	b'11010111'	; pullup off TMR0CLK=osc/4
	movwf	OPTION_REG	; prescaler=1/256  51.2μsec
	movlw	b'11000000'
	movwf	TRISB
	movlw	b'00001111'
	movwf	TRISC
	BANKSEL	ADCON0
	movlw	b'10000000'	; fosc/32 turn off A/D
	movwf	ADCON0
	movlw	b'11111111'
	movwf	PORTA		; PUMP off
	movwf	PORTB		; 7SEG off
	movwf	PORTC		; motor off
	movlw	F_control
	movwf	FSR
start1	clrf	INDF		; clear memory
	incf	FSR,F
	movlw	pclath_temp+1
	subwf	FSR,W
	btfss	STATUS,Z
	goto	start1

	movlw	d'8'
	movwf	set_MSB		; 設定温度初期化 80℃
	movlw	d'0'
	movwf	set_LSB
	movlw	b'11110000'	; 上下左右motor off
	movwf	RC_buff

	btfsc	PORTB,7		; skip if +10 on
	btfss	PORTB,6		; skip if +1 off
	bsf	F_control,1	; set テストモード

	movlw	d'176'		; set timer value 256-4.096ms/0.0512ms = 176
	movwf	TMR0		; TMR0 = 4.0968ms
	movlw	b'10100000'	; GIE=1,T0IE=1
	movwf	INTCON		; interrupt enable

	btfsc	F_control,1	; skip if not テストモード
	goto	m_test
main	movf	set_BIN,W
	movwf	work
	btfsc	F_control,0	; skip if 制御中
	decf	work,F		; 設定値-1
	movf	tmp_BIN,W
	subwf	work,W		; 設定値-測定値 or (設定値-1)<測定値
	btfsc	STATUS,C	; skip if 設定値<測定値 or (設定値-1)<測定値
	goto	main2

	bsf	F_control,0	; set 待機中
	bsf	PORTA,4		; PUMP off
	movlw	b'00110000'
	iorwf	RC_buff,F	; 左右motor off
	btfsc	PORTC,2		; skip if 下LimitSW on
	goto	main1
	movlw	b'11110000'	; 上下左右motor off
	movwf	RC_buff
	goto	main

main1	call	d_drive		; motor 下on
	goto	main

main2	bcf	F_control,0	; set 制御中
	bcf	PORTA,4		; PUMP on
	movf	adbuf0,W
	subwf	adbuf1,W	; 左-右
	btfsc	STATUS,C	; skip if 左光センサー<右光センサー(右側が明るい)
	goto	main3

	btfss	PORTC,0		; skip if 右LimitSW off
	goto	main4
	xorlw	h'FF'
	addlw	d'1'		; 絶対値化
	movwf	work
	movlw	b'11001111'
	iorwf	RC_buff,W
	xorlw	h'FF'
	movlw	h'FC'		; 左右motor off時は下位2Bitは無視する
	btfss	STATUS,Z	; skip if 左右motor off
	movlw	h'FE'		; 左右motor on時は下位1Bitは無視する
	andwf	work,W
	btfsc	STATUS,Z	; skip if 右側が明るい(右-左>1 or 3)
	goto	main4
	call	r_drive		; motor 右on
	goto	main5

main3	btfss	PORTC,1		; skip if 左LimitSW off
	goto	main4
	movwf	work
	movlw	b'11001111'
	iorwf	RC_buff,W
	xorlw	h'FF'
	movlw	h'FC'		; 左右motor off時は下位2Bitは無視する
	btfss	STATUS,Z	; skip if 左右motor off
	movlw	h'FE'		; 左右motor on時は下位1Bitは無視する
	andwf	work,W
	btfsc	STATUS,Z	; skip if 左側が明るい(左-右1 or 3)
	goto	main4
	call	l_drive		; motor 左on
	goto	main5

main4	movlw	b'00110000'
	iorwf	RC_buff,F	; 左右motor off

main5	movf	adbuf2,W
	subwf	adbuf3,W	; 上-下
	btfsc	STATUS,C	; skip if 上光センサー<下光センサー(下側が明るい)
	goto	main6

	btfss	PORTC,2		; skip if 下LimitSW off
	goto	main7
	xorlw	h'FF'
	addlw	d'1'		; 絶対値化
	movwf	work
	movlw	b'00111111'
	iorwf	RC_buff,W
	xorlw	h'FF'
	movlw	h'FC'		; 上下motor off時は下位2Bitは無視する
	btfss	STATUS,Z	; skip if 上下motor off
	movlw	h'FE'		; 上下motor on時は下位1Bitは無視する
	andwf	work,W
	btfsc	STATUS,Z	; skip if 下側が明るい(下-上>1 or 3)
	goto	main7
	call	d_drive		; motor 下on
	goto	main

main6	btfss	PORTC,3		; skip if 上LimitSW off
	goto	main7
	movwf	work
	movlw	b'00111111'
	iorwf	RC_buff,W
	xorlw	h'FF'
	movlw	h'FC'		; 上下motor off時は下位2Bitは無視する
	btfss	STATUS,Z	; skip if 上下motor off
	movlw	h'FE'		; 上下motor on時は下位1Bitは無視する
	andwf	work,W
	btfsc	STATUS,Z	; skip if 上側が明るい(上-下>1 or 3)
	goto	main7
	call	u_drive		; motor 上on
	goto	main

main7	movlw	b'11000000'
	iorwf	RC_buff,F	; 上下motor off
	goto	main

; -------------------------------テストモード--------------------------------

m_test	btfsc	PORTB,7		; skip if +10 on
	btfss	PORTB,6		; skip if +1 off
	goto	m_test

m_test1	btfsc	PORTB,7		; skip if +10 on
	goto	m_test5
	btfss	PORTC,0		; skip if 右LimitSW off
	goto	m_test2
	movlw	adbuf0
	movwf	dipadc
	call	r_drive		; motor 右on
	goto	m_test1

m_test2	movlw	b'11110000'
	iorwf	RC_buff,F	; 左右motor off

m_test3	btfsc	PORTB,7		; skip if +10 on
	goto	m_test5
	btfss	PORTC,1		; skip if 左LimitSW off
	goto	m_test4
	movlw	adbuf1
	movwf	dipadc
	call	l_drive		; motor 左on
	goto	m_test3

m_test4	movlw	b'11110000'
	iorwf	RC_buff,F	; 左右motor off
	goto	m_test1

m_test5	movlw	b'11110000'
	iorwf	RC_buff,F	; 左右motor off

m_test6	btfsc	PORTB,6		; skip if +1 on
	goto	m_testA
	btfss	PORTC,3		; skip if 上LimitSW off
	goto	m_test7
	movlw	adbuf3
	movwf	dipadc
	call	u_drive		; motor 上on
	goto	m_test6

m_test7	movlw	b'11110000'
	iorwf	RC_buff,F	; 上下motor off

m_test8	btfsc	PORTB,6		; skip if +1 on
	goto	m_testA
	btfss	PORTC,2		; skip if 下LimitSW off
	goto	m_test9
	movlw	adbuf2
	movwf	dipadc
	call	d_drive		; motor 下on
	goto	m_test8

m_test9	movlw	b'11110000'
	iorwf	RC_buff,F	; 上下motor off
	goto	m_test6

m_testA	movlw	b'11110000'
	iorwf	RC_buff,F	; 上下motor off
	goto	m_test1

; -------------------------------interrupt routine--------------------------------

intrqt	btfss	INTCON,T0IF	; time out interruption ?
	return			; return at illegal interrupt
	movlw	d'176'		; set timer value 256-4.096ms/0.0512ms = 176
	movwf	TMR0		; TMR0 = 4.0968ms
	bcf	INTCON,T0IF	; clear timer int flag
	call	ad_conv		; A/D変換
	call	exDtmp		; 測定温度変換 for S8100B 2進→10進
	movf	cntxxm,F
	btfss	STATUS,Z	; skip if xxmsec up
	decf	cntxxm,F
	call	S_seg

;	上下motor 出力

	movf	RC_buff,W
	iorlw	b'00111111'
	xorlw	h'FF'
	btfss	STATUS,Z	; skip if 上下motor off
	goto	intrqt1
	bsf	PORTC,7		; 上下motor off
	nop
	nop
	bsf	PORTC,6
	goto	intrqt5

intrqt1	movf	cntdutyUD,F
	btfss	STATUS,Z	; skip if on duty
	goto	intrqt3
	btfsc	RC_buff,7	; skip if 上方向 on
	goto	intrqt2
	bsf	PORTC,6
	nop
	nop
	bcf	PORTC,7		; 上方向 on
	goto	intrqt4

intrqt2	btfsc	RC_buff,6	; skip if 下方向 on
	goto	intrqt3
	bsf	PORTC,7
	nop
	nop
	bcf	PORTC,6		; 下方向 on
	goto	intrqt4

intrqt3	bsf	PORTC,7		; 上下motor off
	nop
	nop
	bsf	PORTC,6
intrqt4	incf	cntdutyUD,F
	movlw	dutyUD
	subwf	cntdutyUD,W
	btfsc	STATUS,C	; skip if not one cycle
intrqt5	clrf	cntdutyUD	; 初期化

;	左右motor 出力

	movf	RC_buff,W
	iorlw	b'11001111'
	xorlw	h'FF'
	btfss	STATUS,Z	; skip if 左右motor off
	goto	intrqt6
	bsf	PORTC,5		; 左右motor off
	nop
	nop
	bsf	PORTC,4
	goto	intrqtA

intrqt6	movf	cntdutyLR,F
	btfss	STATUS,Z	; skip if on duty
	goto	intrqt8
	btfsc	RC_buff,5	; skip if 左方向 on
	goto	intrqt7
	bsf	PORTC,4
	nop
	nop
	bcf	PORTC,5		; 左方向 on
	goto	intrqt9

intrqt7	btfsc	RC_buff,4	; skip if 右方向 on
	goto	intrqt8
	bsf	PORTC,5
	nop
	nop
	bcf	PORTC,4		; 右方向 on
	goto	intrqt9

intrqt8	bsf	PORTC,5		; 左右motor off
	nop
	nop
	bsf	PORTC,4
intrqt9	incf	cntdutyLR,F
	movlw	dutyLR
	subwf	cntdutyLR,W
	btfsc	STATUS,C	; skip if not one cycle
intrqtA	clrf	cntdutyLR	; 初期化

	btfsc	F_control,1	; skip if not テストモード
	goto	testadc

;	+1key入力

	movf	one_conton,F
	btfsc	STATUS,Z	; skip if +1連続on中
	goto	intrqtE
	decf	one_conton,F	; +1連続カウンタ カウント
	btfsc	F_control,6	; skip if +1前回OFF
	goto	intrqtB
	btfsc	PORTB,6		; skip if +1 on
	goto	intrqtF
	bsf	F_control,6	; 前回ONフラグセット
	goto	intrqtC

intrqtB	btfsc	PORTB,6		; skip if +1 on
	goto	intrqtD
	bsf	F_control,6	; 前回ONフラグセット
	movf	one_conton,F
	btfss	STATUS,Z	; skip if +1連続カウンタ up
	goto	intrqtG
intrqtC	incf	set_LSB,F
	movlw	d'10'
	subwf	set_LSB,W
	btfsc	STATUS,C	; skip if set_LSB<10
	clrf	set_LSB		; 初期化 0
	movlw	d'98'		; 4.0968msec*98=401msec
	movwf	one_conton
	goto	intrqtG

intrqtD	bcf	F_control,6	; 前回ONフラグリセット
	movlw	d'244'		; 4.0968msec*244=999msec
	movwf	one_conton
	goto	intrqtG

intrqtE	btfsc	PORTB,6		; skip if +1 on
	goto	intrqtF
	bsf	F_control,6	; 前回ONフラグセット
	movlw	d'244'		; 4.0968msec*244=999msec
	movwf	one_conton
	goto	intrqtG

intrqtF	bcf	F_control,6	; 前回ONフラグリセット

;	+10key入力

intrqtG	movf	ten_conton,F
	btfsc	STATUS,Z	; skip if +10連続on中
	goto	intrqtL
	decf	ten_conton,F	; +10連続カウンタ カウント
	btfsc	F_control,7	; skip if +10前回OFF
	goto	intrqtH
	btfsc	PORTB,7		; skip if +10 on
	goto	intrqtM
	bsf	F_control,7	; 前回ONフラグセット
	goto	intrqtJ

intrqtH	btfsc	PORTB,7		; skip if +10 on
	goto	intrqtK
	bsf	F_control,7	; 前回ONフラグセット
	movf	ten_conton,F
	btfss	STATUS,Z	; skip if +10連続カウンタ up
	goto	intrqtN
intrqtJ	incf	set_MSB,F
	movlw	d'10'
	subwf	set_MSB,W
	movlw	d'3'
	btfsc	STATUS,C	; skip if set_LSB<10
	movwf	set_MSB		; 初期化 3
	movlw	d'98'		; 4.0968msec*98=401msec
	movwf	ten_conton
	goto	intrqtN

intrqtK	bcf	F_control,7	; 前回ONフラグリセット
	movlw	d'244'		; 4.0968msec*244=999msec
	movwf	ten_conton
	goto	intrqtN

intrqtL	btfsc	PORTB,7		; skip if +10 on
	goto	intrqtM
	bsf	F_control,7	; 前回ONフラグセット
	movlw	d'244'		; 4.0968msec*244=999msec
	movwf	ten_conton
	goto	intrqtN

intrqtM	bcf	F_control,7	; 前回ONフラグリセット

intrqtN	call	exBin		; 設定値2進数化
	return

testadc	decfsz	one_conton,F	; skip if time up
	return
	movf	dipadc,W
	movwf	FSR
	movf	INDF,W
	andlw	h'0F'
	movwf	set_LSB
	swapf	INDF,W
	andlw	h'0F'
	movwf	set_MSB
	movlw	d'49'		; 4.0968msec*49=200msec
	movwf	one_conton
	return

; -------------------------------sub routine--------------------------------

;	7SEG制御

S_seg	incf	sseg_cnt,F	; 7SEGカウンタ +1
	movlw	b'00110000'
	movwf	RB_buff
	movlw	b'11111111'
	movwf	PORTB		; 7SEG off
	movf	one_conton,F
	btfss	STATUS,Z	; skip if +1 off
	goto	S_seg1
	movf	ten_conton,F
	btfss	STATUS,Z	; skip if +10 off
	goto	S_seg1
	movlw	tmp_LSB
	goto	S_seg2

S_seg1	movlw	set_LSB
S_seg2	movwf	FSR
	btfsc	sseg_cnt,0	; skip if 7SEG=1桁目?
	goto	S_seg3
	bcf	RB_buff,4	; 7SEG LSB on
	goto	S_seg4

S_seg3	incf	FSR,F
	bcf	RB_buff,5	; 7SEG MSB on
S_seg4	movf	INDF,W
	andlw	b'00001111'
	iorwf	RB_buff,W
	movwf	PORTB		; 7SEG on
	return

;	上回転

u_drive	btfsc	RC_buff,6	; skip if 下回転中
	goto	u_drv1
	bsf	RC_buff,6	; motor off
	call	wait100		; 100msec wait
u_drv1	bcf	RC_buff,7	; motor 上on
	return

;	下回転

d_drive	btfsc	RC_buff,7	; skip if 上回転中
	goto	d_drv1
	bsf	RC_buff,7	; motor off
	call	wait100		; 100msec wait
d_drv1	bcf	RC_buff,6	; motor 下on
	return

;	左回転

l_drive	btfsc	RC_buff,4	; skip if 右回転中
	goto	l_drv1
	bsf	RC_buff,4	; motor off
	call	wait100		; 100msec wait
l_drv1	bcf	RC_buff,5	; motor 左on
	return

;	右回転

r_drive	btfsc	RC_buff,5	; skip if 左回転中
	goto	r_drv1
	bsf	RC_buff,5	; motor off
	call	wait100		; 100msec wait
r_drv1	bcf	RC_buff,4	; motor 右on
	return

;	設定温度変換 10進→2進

exBin	bcf	STATUS,C
	movf	set_MSB,W
	movwf	set_BIN		; *2^1
	rlf	set_BIN,F
	movf	set_BIN,W
	rlf	set_BIN,F
	rlf	set_BIN,F	; *2^3
	addwf	set_BIN,F	; 2^3+2^1=10倍
	movf	set_LSB,W
	addwf	set_BIN,F	; LSB+MSB*10
	return

;	測定温度変換 for S8100B 2進→10進

exDtmp	clrf	tmp_BIN		; 2進数 温度 0℃以下は0
	clrf	tmp_MSB
	movf	adbuf4,W	; adbuf4 読込
	sublw	d'230'
	movwf	tmp_LSB
	btfsc	STATUS,C	; skip if 0℃以下?
	goto	exDtmp3
	xorlw	d'255'
	addlw	d'1'
	movwf	tmp_LSB
	sublw	d'9'
	btfss	STATUS,C	; skip if -10℃以上?
	goto	exDtmp2
exDtmp1	movlw	d'100'		; ⊂記号(-1～-9℃)
	addwf	tmp_LSB,F
	goto	exDtmp4

exDtmp2	movlw	d'109'		; ⊂9(-9℃以下)
	movwf	tmp_LSB
	goto	exDtmp4

exDtmp3	movwf	tmp_BIN		; 2進数 温度
	sublw	d'99'
	btfsc	STATUS,C	; skip if 100℃以上?
	goto	exDtmp4
	movlw	d'99'		; 99
	movwf	tmp_LSB

exDtmp4	movlw	d'10'
	subwf	tmp_LSB,W
	btfss	STATUS,C	; skip if temp=>10?
	return
	movwf	tmp_LSB
	incf	tmp_MSB,F	; 10位+1
	goto	exDtmp4

;	A/D変換

ad_conv	movlw	b'10000001'	; select AN0
	call	s_ad_cv
	movwf	adbuf0		; A/D -> adbuf0
	call	wait2u		; 19.6+0.4μsec wait
	movlw	b'10001001'	; select AN1
	call	s_ad_cv
	movwf	adbuf1		; A/D -> adbuf1
	call	wait2u		; 19.6+0.4μsec wait
	movlw	b'10010001'	; select AN2
	call	s_ad_cv
	movwf	adbuf2		; A/D -> adbuf2
	call	wait2u		; 19.6+0.4μsec wait
	movlw	b'10011001'	; select AN3
	call	s_ad_cv
	movwf	adbuf3		; A/D -> adbuf3
	call	wait2u		; 19.6+0.4μsec wait
	movlw	b'10100001'	; select AN4
	call	s_ad_cv
	movwf	adbuf4		; A/D -> adbuf4
	movlw	b'10000000'	; turn off A/D
	movwf	ADCON0
	return

s_ad_cv	movwf	ADCON0		; select ANx
	call	wait2u		; 19.6+0.4μsec wait
	bsf	ADCON0,GO	; A/D start
adloop	btfsc	ADCON0,GO	; jump if A/D done?
	goto	adloop
	movf	ADRESH,W	; get A/D data
	return

;	20μsec wait

wait2u	movlw	d'23'		; 1 (4n+6)*1サイクル時間(4/fosc)
	movwf	cnt20u		; 1		20MHz 4/8=0.2μsec
wloop	nop			; 1*n		19.6μsec
	decfsz	cnt20u,F	; 1*(n-1)+2
	goto	wloop		; 2*(n-1)
	nop			; 1
	nop			; 1
	nop			; 1
	return			; 2

;	100msec wait

wait100	movlw	d'25'		; 100msec wait
waitxx	movwf	cntxxm		; x x= n*4.0968msec
waitx1	movf	cntxxm,F
	btfss	STATUS,Z	; skip if xxmsec up
	goto	waitx1
	return

	end
