;;; Mini4WD コントロール 'GPSYS' ソースプログラム 1.0 mini4gp.asm
;;;  for GP-Unit 1.2
;;;  by S.Ogura  1999.1.18 第1版
;;;              1999.3.12 データ設定モード追加

;;; アセンブルはAKI-PICプログラマ付属のPA.EXEで行う

			include	16f84.h
			.osc		hs
			.wdt		off
			.pwrt		off
			.protect	off

E			equ		ra.2		; LCDのE信号
RS			equ		ra.3		; LCDのRS信号
F_SNS		equ		rb.6		; フロントセンサ入力
R_SNS		equ		rb.5		; リヤセンサ入力
SW1			equ		rb.4		; マシン本体スイッチ入力&LED
E_SW1		equ		rb.7		; LCDユニットSW1
E_SW2		equ		ra.4		; LCDユニットSW2
SW_ON		equ		1			; オン状態
SW_OFF		equ		0			; オフ状態
KEY_REP		equ		80			; キーリピート(ms)
REP_WT		equ		4			; リピート開始ウェイト(*100ms)


			org		0ch
res			ds		1			; 結果取得ワーク
wait_cn		ds		1			; ウエイト時間設定領域
wait_cn2	ds		1			; 以下、ワーク
wait_s		ds		1			;
wait_s2		ds		1			;
wait_wk		ds		1			;
f_int_t		ds		1			; フロントセンサ再チェック遅延時間
f_rev_t		ds		1			; 逆転ブレーキ時間(フロントセンサ)
f_brk_t		ds		1			; ブレーキ時間(フロントセンサ)
r_rev_t		ds		1			; 逆転ブレーキ時間(リヤセンサ)
r_brk_t		ds		1			; ブレーキ時間(リヤセンサ)
d4			ds		1			; 液晶writeデータ(4bitモード)
d8			ds		1			;                (8bitモード)
poi			ds		1			; 文字列ポインタ
lcn			ds		1			; 行指定データ
lcdcol		ds		1			; 文字表示カラム位置
tbl_idx		ds		1			; テーブル指定インデックス
param		ds		1			; 設定パラメータワーク
autotp		ds		1			; キーリピートモード

;;------------------------------------------------
;;		パラメータ初期値(EEPROMデータメモリに格納)
;;------------------------------------------------
			eeorg	0
			eedata	2		; Fセンサ:再チェック遅延時間=2ms
			eedata	6		; Fセンサ:逆転ブレーキ時間=6ms
			eedata	6		; Fセンサ:ブレーキ時間=6ms
			eedata	4		; Rセンサ:逆転ブレーキ時間=4ms
			eedata	10		; Rセンサ:ブレーキ時間=10ms

			org		0
			goto	start
			org		4
			goto	start

;;------------------------------------------------
;;		テーブル
;;------------------------------------------------
title_tbl	jmp	pc+w
			retw	'Welcome to GPSYS'
			retw	'* Setting Menu *'
			retw	'[   ms]->[   ms]'
msgtbl_1	jmp pc+w
			retw	'F: Sensor Delay '
			retw	'F: Reverse Brake'
			retw	'F: Brake        '
			retw	'R: Reverse Brake'
			retw	'R: Brake        '
msgtbl_2	jmp	pc+w
			retw	'> Setting OK?   '
			retw	'> Writing...    '
			retw	'> Bye!          '
num_tbl		jmp	pc+w
			retw	'0123456789ABCDEF'

;;------------------------------------------------
;;		初期設定
;;------------------------------------------------
start
			;; FET4,FET3,E,RS = OUT / E_SW1 = IN
			mov		!ra, #00010000b
			;; DB4～7(&FET1,2) = OUT / SW1,F_SNS,R_SNS,E_SW2 = IN
			mov		!rb, #11110000b
			clr		ra
			clr		rb

			;; Bポートは内部プルアップに設定
			setb	rp0
			clrb	rbpu
			clrb	rp0

memread
			; パラメータをEEPROMから読み出す
			clr		eeadr
			call	eeprom_read
			mov		f_int_t, eedata
			inc		eeadr
			call	eeprom_read
			mov		f_rev_t, eedata
			inc		eeadr
			call	eeprom_read
			mov		f_brk_t, eedata
			inc		eeadr
			call	eeprom_read
			mov		r_rev_t, eedata
			inc		eeadr
			call	eeprom_read
			mov		r_brk_t, eedata

init		;; モーターを停止状態にする
			;; 注意！FET1,2はPチャネルFETなのでOFF状態は'1'である
			mov		rb, #00001010b
			mov		ra, #00000000b

;;------------------------------------------------
;;		モード切り替え
;;------------------------------------------------
main0
			;; SW1オンで走行モードへ
			call	chk_sw1
			cje		res, #SW_ON, main1		; if SW1==ON goto main1

			;; R_SNSオンでデモモードへ
			call	chk_rsns
			cje		res, #SW_ON, demo		; if R_SNS==ON goto demo

			;; E_SW1オンでデータ設定モードへ
			call	chk_esw1
			cje		res, #SW_ON, menu	; if E_SW1==ON goto menu

			goto	main0


;;------------------------------------------------
;;		走行モード
;;------------------------------------------------
main1
			;; 前進
			mov		rb, #00001000b		; rb1=0,rb3=1 (FET1 ON)
			mov		ra, #00000001b		; ra0=1,ra1=0 (FET4 ON)
mainloop
			call	proc_fsns			; フロントセンサ処理
			call	proc_rsns			; リヤセンサ処理
			call	chk_sw1				; SW1チェック
			cje		res, #SW_ON, init	; if SW1==ON goto init
			goto	mainloop

;;------------------------------------------------
;;		デモモード
;;------------------------------------------------
demo
			;; PWM前進
			mov		wait_s, #4
			mov		wait_s2, #1
			mov		wait_wk, #150
			mov		rb, #00001000b		; FET1 ON

			;; (1)徐々に最高速までスピードアップ:約3秒
pwm0
			mov		ra, #00000001b		; FET4 ON
			mov		wait_cn, wait_s2
			call	wait_ms
			mov		ra, #00000000b		; FET4 OFF
			mov		wait_cn, wait_s
			call	wait_ms
;			call	proc_fsns			; フロントセンサ処理
;			call	proc_rsns			; リヤセンサ処理
			call	chk_sw1				; SW1チェック
			cje		res, #SW_ON, init	; if SW1==ON goto init
			djnz	wait_wk, pwm0
			djnz	wait_s, pwm1
			goto	demo1
pwm1
			inc		wait_s2
			mov		wait_wk, #150
			goto	pwm0
demo1
			;; (2)ブレーキをかける
			mov		rb, #00001010b
			mov		ra, #00000000b
			mov		rb, #00001010b
			mov		ra, #00000011b

			;; (3)LED点滅:5回
			mov		!rb, #11100000b		; SW1(LED)=OUT
			mov		wait_wk, #5
stop1
			or		rb, #00010000b		; LED点灯
			mov		wait_cn, #5
			call	wait_sec
			and		rb, #11101111b		; LED消灯
			mov		wait_cn, #5
			call	wait_sec
			djnz	wait_wk, stop1
			mov		!rb, #11110000b		; SW1(LED)=IN

			;; (4)全速前進:2.5秒
			mov		rb, #00001000b		; FET1 ON
			mov		ra, #00000001b		; FET4 ON
			mov		wait_cn, #25
			call	wait_sec
			call	chk_sw1				; SW1チェック
			cje		res, #SW_ON, init	; if SW1==ON goto init

			;; (5)ブレーキ+2秒停止
			mov		rb, #00001010b
			mov		ra, #00000000b
			mov		rb, #00001010b
			mov		ra, #00000011b
			mov		wait_cn, #20
			call	wait_sec
			call	chk_sw1				; SW1チェック
			cje		res, #SW_ON, init	; if SW1==ON goto init

demo2
			;; (6)微速バック
			mov		wait_s, #9
			mov		wait_s2, #3
			mov		wait_wk, #250
			mov		rb, #00000010b		; FET2 ON
pwm2
			mov		ra, #00000010b		; FET3 ON
			mov		wait_cn, wait_s2
			call	wait_ms
			mov		ra, #00000000b		; FET3 OFF
			mov		wait_cn, wait_s
			call	wait_ms
			call	chk_sw1				; SW1チェック
			cje		res, #SW_ON, init	; if SW1==ON goto init
			djnz	wait_wk, pwm2

			mov		wait_cn, #30
			call	wait_sec
			goto	demo

;;------------------------------------------------
;;		データ設定モード
;;------------------------------------------------
menu
			clr		ra
			clr		rb

			call	init_lcd
			;; タイトル表示
			clr		tbl_idx
			clr		poi
			mov		lcn, #10000000b
			call	write_1
			mov		lcn, #11000000b
			call	write_1
menu_0
			call	chk_esw1
			cje		res, #SW_ON, setting		; if E_SW1==ON goto setting
			call	chk_sw1
			cje		res, #SW_ON, exit_menu		; if SW1==ON goto exit_menu
			goto	menu_0

setting		;; セッティング開始
			call	clr_lcd
			clr		tbl_idx
			mov		poi, #32
			mov		lcn, #11000000b
			call	write_1						; 2行目に [ ms]表示

			mov		tbl_idx, #1

			mov		lcn, #10000000b				; Fセンサ:再チェック遅延時間の設定
			clr		poi
			call	write_1						; メッセージ表示
			mov		param, f_int_t				; 現在の設定値
			call	get_param					; 新規パラメータ値取得
			cje		param, #0ffh, exit_menu		; 中止?
			mov		f_int_t, param				; パラメータ設定

			mov		lcn, #10000000b				; Fセンサ:逆転ブレーキ時間の設定
			mov		poi, #16
			call	write_1
			mov		param, f_rev_t
			call	get_param
			cje		param, #0ffh, exit_menu
			mov		f_rev_t, param

			mov		lcn, #10000000b				; Fセンサ:ブレーキ時間の設定
			mov		poi, #32
			call	write_1
			mov		param, f_brk_t
			call	get_param
			cje		param, #0ffh, exit_menu
			mov		f_brk_t, param

			mov		lcn, #10000000b				; Rセンサ:逆転ブレーキ時間の設定
			mov		poi, #48
			call	write_1
			mov		param, r_rev_t
			call	get_param
			cje		param, #0ffh, exit_menu
			mov		r_rev_t, param

			mov		lcn, #10000000b				; Rセンサ:ブレーキ時間の設定
			mov		poi, #64
			call	write_1
			mov		param, r_brk_t
			call	get_param
			cje		param, #0ffh, exit_menu
			mov		r_brk_t, param

			call	clr_lcd
			mov		tbl_idx, #2
			clr		poi
			mov		lcn, #10000000b
			call	write_1						; Setting OK?
menu_1
			call	chk_esw1
			cje		res, #SW_ON, write_0		; if E_SW1==ON(YES) goto write_0
			call	chk_esw2
			cje		res, #SW_ON, setting		; if E_SW2==ON(NO) goto setting
			goto	menu_1

write_0		;; パラメータのEEPROM書き込み
			mov		tbl_idx, #2
			mov		poi, #16
			mov		lcn, #10000000b
			call	write_1						; Writing..
			clr		eeadr
			mov		eedata, f_int_t
			call	eeprom_write
			inc		eeadr
			mov		eedata, f_rev_t
			call	eeprom_write
			inc		eeadr
			mov		eedata, f_brk_t
			call	eeprom_write
			inc		eeadr
			mov		eedata, r_rev_t
			call	eeprom_write
			inc		eeadr
			mov		eedata, r_brk_t
			call	eeprom_write
			mov		wait_cn, #20
			call	wait_sec

exit_menu
			call	clr_lcd
			mov		tbl_idx, #2
			mov		poi, #32
			mov		lcn, #10000000b
			call	write_1						; Bye!
			goto	memread


;; パラメータ表示＆設定値取得サブルーチン
get_param
			clr		autotp
			mov		poi, #2						; 現在値表示
			call	disp_param
			mov		poi, #11					; 設定値表示
			call	disp_param
getloop
			call	chk_esw1
			cje		res, #SW_ON, get_0		; if E_SW1==ON(OK) goto get_0
			call	chk_sw1
			cje		res, #SW_ON, get_1		; if SW1==ON(EXIT) goto get_1
			jnb		E_SW2, para_inc			; if E_SW2==ON goto para_inc
			clr		autotp					; 何も押されていない->リピートモードOFF
			goto	getloop

para_inc	;; 設定値UP処理
			cjae	param, #100, para_rst	; MAX=100(ms)とする
			inc		param
			goto	para_2
para_rst
			clr		param
para_2
			mov		poi, #11				; 設定値表示
			call	disp_param
			mov		wait_cn, #KEY_REP		; キーリピート時間ウエイト
			call	wait_ms
			cje		autotp, #1, getloop		; リピートモードならgetloopへ
			mov		wait_cn, #REP_WT		; リピート開始を待つ
			call	wait_sec
			mov		autotp, #1				; リピートモードON
			goto	getloop
get_1
			mov		param, #0ffh			; 中止の場合
get_0
			ret

;; 液晶にparam値(hex)を表示する
disp_param
			clrb	RS
			mov		d4, poi
			or		d4, #11000000b
			call	write_lcd4				; カーソル位置セット
			setb	RS
			mov		res, param
			swap	res
			and		res, #00001111b
			mov		w, res
			call	num_tbl
			mov		d4, w
			call	write_lcd4				; 1桁目を表示
			mov		res, param
			and		res, #00001111b
			mov		w, res
			call	num_tbl
			mov		d4, w
			call	write_lcd4				; 2桁目を表示
			ret


;;------------------------------------------------
;;		EEPROM R/W
;;------------------------------------------------
eeprom_read
			bsf		rp0
			bsf		eecon1.0
			bcf		rp0
			ret

eeprom_write
			bsf		rp0
			bsf		eecon1.2
			mov		eecon2, #55h
			mov		eecon2, #0aah
			bsf		eecon1.1
write100	btfsc	eecon1.1
			goto	write100
			bcf		rp0
			ret


;;------------------------------------------------
;;		フロントセンサ処理
;;------------------------------------------------
proc_fsns
			jnb		F_SNS, f_brk		; F_SNS=ONならブレーキ処理へ
			ret
f_brk
			cje		f_int_t, #0, fbrk1
			mov		wait_cn, f_int_t	; 遅延時間分のウエイト
			call	wait_ms
			jnb		F_SNS, fbrk1		; センサ入力を再チェックする
			ret							; F_SNS=OFFなら何もしないで戻る
fbrk1
			cje		f_rev_t, #0, fbrk2	; 逆転時間=0ならfbrk2へ
			mov		rb, #00001010b		; stop
			mov		ra, #00000000b
			;; モーター逆転
			mov		rb, #00000010b		; rb1=1,rb3=0 (FET2 ON)
			mov		ra, #00000010b		; ra0=0,ra1=1 (FET3 ON)
			mov		wait_cn, f_rev_t	; 逆転時間分ウエイト
			call	wait_ms
fbrk2
			cje		f_brk_t, #0, fbrk3	; ブレーキ時間=0ならfbrk3へ
			mov		rb, #00001010b		;stop
			mov		ra, #00000000b
			;; ブレーキ
			mov		rb, #00001010b		; rb1=1,rb3=1 (FET1,2 OFF)
			mov		ra, #00000011b		; ra0=1,ra1=1 (FET3,4 ON)
			mov		wait_cn, f_brk_t	; ブレーキ時間分ウエイト
			call	wait_ms
fbrk3
			;; 前進
			mov		rb, #00001010b
			mov		ra, #00000000b
			mov		rb, #00001000b
			mov		ra, #00000001b
fbrk4
			jnb		SW1, fbrk5			; ループ中のSW1チェック
			jnb		F_SNS, fbrk4		; F_SNS=ONの間は前進
fbrk5
			mov		wait_cn, #20		; 
			call	wait_ms				; 20ms待ち
			ret							; F_SNS=OFFになったら戻る

;;------------------------------------------------
;;		リヤセンサ処理
;;------------------------------------------------
proc_rsns
			jnb		R_SNS, r_brk		; R_SNS=ONならブレーキ処理へ
			ret
r_brk
			cje		r_rev_t, #0, rbrk1
			mov		rb, #00001010b		;stop
			mov		ra, #00000000b
			;; モーター逆転
			mov		rb, #00000010b		; rb1=1,rb3=0 (FET2 ON)
			mov		ra, #00000010b		; ra0=0,ra1=1 (FET3 ON)
			mov		wait_cn, r_rev_t	; 逆転時間分ウエイト
			call	wait_ms
rbrk1
			cje		r_brk_t, #0, rbrk2
			mov		rb, #00001010b		;stop
			mov		ra, #00000000b
			;; ブレーキ
			mov		rb, #00001010b		; rb1=1,rb3=1 (FET1,2 OFF)
			mov		ra, #00000011b		; ra0=1,ra1=1 (FET3,4 ON)
			mov		wait_cn, r_brk_t	; ブレーキ時間分ウエイト
			call	wait_ms
rbrk2
			;; 前進
			mov		rb, #00001010b
			mov		ra, #00000000b
			mov		rb, #00001000b
			mov		ra, #00000001b
rbrk3
			jnb		R_SNS, rbrk3		; R_SNS=ONの間は前進
			mov		wait_cn, #20		; チャタリング対策
			call	wait_ms				; 20ms待ち
			ret							; R_SNS=OFFになったら戻る

;;------------------------------------------------
;;		スイッチ、センサ処理
;;------------------------------------------------
;; SW1押下チェック(ret = SW_ON / SW_OFF)
chk_sw1
			jnb		SW1, sw1_on			; if SW1==0 goto sw1_on
			mov		res, #SW_OFF
			ret
sw1_on
			mov		wait_cn, #50		; チャタリング対策
			call	wait_ms				; 50ms待ち、offになるまでループ
			jnb		SW1, sw1_on			; if SW1==0 goto sw1_on
			mov		wait_cn, #50		; チャタリング対策
			call	wait_ms				; 50ms待ち
			mov		res, #SW_ON
			ret

;; R_SNS押下チェック(ret = SW_ON / SW_OFF)
chk_rsns
			jnb		R_SNS, rsns_on		; if R_SNS==0 goto rsns_on
			mov		res, #SW_OFF
			ret
rsns_on
			mov		wait_cn, #50		; チャタリング対策
			call	wait_ms				; 50ms待ち、offになるまでループ
			jnb		R_SNS, rsns_on		; if R_SNS==0 goto rsns_on
			mov		wait_cn, #50		; チャタリング対策
			call	wait_ms				; 50ms待ち
			mov		res, #SW_ON
			ret

;; E_SW1押下チェック(ret = SW_ON / SW_OFF)
chk_esw1
			jnb		E_SW1, esw1_on		; if E_SW1==0 goto esw1_on
			mov		res, #SW_OFF
			ret
esw1_on
			mov		wait_cn, #50		; チャタリング対策
			call	wait_ms				; 50ms待ち、offになるまでループ
			jnb		E_SW1, esw1_on		; if E_SW1==0 goto sw1_on
			mov		wait_cn, #50		; チャタリング対策
			call	wait_ms				; 50ms待ち
			mov		res, #SW_ON
			ret

;; E_SW2押下チェック(ret = SW_ON / SW_OFF)
chk_esw2
			jnb		E_SW2, esw2_on		; if E_SW2==0 goto esw2_on
			mov		res, #SW_OFF
			ret
esw2_on
			mov		wait_cn, #50		; チャタリング対策
			call	wait_ms				; 50ms待ち、offになるまでループ
			jnb		E_SW2, esw2_on		; if E_SW1==0 goto sw1_on
			mov		wait_cn, #50		; チャタリング対策
			call	wait_ms				; 50ms待ち
			mov		res, #SW_ON
			ret



;;------------------------------------------------
;;		LCD初期化
;;------------------------------------------------
init_lcd
			mov		wait_cn, #15
			call	wait_ms
			clrb	RS
			mov		d8, #00110000b
			call	write_lcd8
			mov		wait_cn, #5
			call	wait_ms
			mov		d8, #00110000b
			call	write_lcd8
			mov		wait_cn, #100
			call	wait_us
			mov		d8, #00110000b
			call	write_lcd8
			mov		d8, #00100000b
			call	write_lcd8
			mov		d4, #00101000b
			call	write_lcd4
			mov		d4, #00000001b
			call	write_lcd4
			mov		wait_cn, #2
			call	wait_ms
			mov		d4, #00000110b
			call	write_lcd4
;			mov		d4, #00001110b
			mov		d4, #00001100b	; cursor off
			call	write_lcd4
			ret

;;------------------------------------------------
;;		LCDコマンド
;;------------------------------------------------
;; LCDクリア
clr_lcd
			clrb	RS
			mov		d4, #00000001b
			call	write_lcd4
			mov		wait_cn, #2
			call	wait_ms
			ret

;; LCD 1行(16文字)表示
write_1
			clrb	RS
			mov		d4, lcn
			call	write_lcd4
			call	putchar
			ret


;; LCD 文字表示
putchar
			mov		lcn, #16
			setb	RS
putchar0
			cjne	tbl_idx, #0, tbset1
			mov		w, poi
			call	title_tbl
			goto	putchar1
tbset1
			cjne	tbl_idx, #1, tbset2
			mov		w, poi
			call	msgtbl_1
			goto	putchar1
tbset2
			mov		w, poi
			call	msgtbl_2
putchar1
			mov		d4, w
			call	write_lcd4
			inc		poi
			djnz	lcn, putchar0
			ret

;;------------------------------------------------
;;		8/4ビットモード液晶ライトルーチン
;;------------------------------------------------
write_lcd8
			swap	d8
			and		rb, #11110000b
			and		d8, #00001111b
			or		rb, d8
			nop
			setb	E
			nop
			clrb	E
			mov		wait_cn, #40
			call	wait_us
			ret

write_lcd4
			mov		d8, d4
			call	write_lcd8
			mov		d8, d4
			swap	d8
			call	write_lcd8
			ret

;;------------------------------------------------
;;		ウエイトルーチン
;;------------------------------------------------
;; ------ 1/10sec ウエイト -----
wait_sec
			mov		wait_s, wait_cn
wait_s0
			mov		wait_cn, #100
			call	wait_ms
			djnz	wait_s, wait_s0
			ret

;; ------ msウエイト------
wait_ms
wait_ms0
			mov		wait_cn2, #0
wait_ms1
			nop
			nop
			nop
			nop
			nop
			nop
			nop
			djnz	wait_cn2, wait_ms1
			djnz	wait_cn, wait_ms0
			ret

;; ------ usウェイト ------
wait_us
wait_us0
			djnz	wait_cn, wait_us0
			ret



;;; EOF
