; ms_v03.asm
; Updated: June 26, 2006, PTB.
;
; PIC16F84A-20 with a 14.3MHz crystal.
;	Actually a -04 part runs with a 14.3MHz xtal, weird...
;
; For: Micro_sumo with the "Solarbotics pager motor" gearmotors.
; "Pushy"
;
	LIST    p=16F84A
	include "p16f84a.inc"
	__config _cp_off & _wdt_off & _pwrte_on & _hs_osc
	__idlocs 0x143D
	errorlevel -302, -206
;
version	set	0	; 1= use eeprom area, 0= don't.
;
_opt256	equ	b'00000111'	; timer 1:256, PU, falling RB0
_opt128	equ	b'00000110'	; timer 1:128, PU, falling RB0
_opt64	equ	b'00000101'	; timer 1:64,  PU, falling RB0
_opt32	equ	b'00000100'	; timer 1:32,  PU, falling RB0 <<<==
_opt16	equ	b'00000011'	; timer 1:16,  PU, falling RB0
_opt2	equ	b'00000000'	; timer 1:2,   PU, falling RB0
;                 ||||||||
;                 ||||||||____ pre-scaler bits
;                 |||||||_____ pre-scaler bits
;                 ||||||______ pre-scaler bits
;                 |||||
;                 |||||_______ 0=NO_WDT, 1=WDT.
;                 ||||________ 0=lo2hi, 1=hi2lo edge/tocki.
;                 |||_________ 0=internal TMR0 clk, 1=external clk.
;                 ||__________ 0=falling edge RB0/INT, 1=rising edge.
;                 |___________ 0=pullups, 1=no_pullups.
;
; ###################################################
;
;   7     6     5     4     3     2     1     0
; gie, eeie, t0ie, inte, rbie, t0if, intf, rbif
;
_inton	equ	b'10011000'
_int	equ	b'00000000'
;                 ||||||||
;                 ||||||||____ RBIF - RB[4..7] change flag
;                 |||||||_____ INTF - RB0/INT flag
;                 ||||||______ T0IF - TMNR0 overflow flag
;                 |||||
;                 |||||_______ RBIE - RB port change int ena
;                 ||||________ INTE - RB0/INT int ena
;                 |||
;                 |||_________ T0IE - TMR0 overflow int ena
;                 ||__________ EEIE - EEPROM int ena
;                 |
;                 |___________ GIE  - Global int ena
;
; ###################################################
;
; Motor Driver Port:
; Using: 74AC245 wired as motor drivers.
; 0xx01, 0xx10, 001xx, 010xx = motor rotation polarity outputs
;
;                 43210
a_pins	equ	b'11111'
a_tris	equ	b'00000' ; inputs =1, outputs =0
;                 |||||
;                 |||||____ m1p1 - rite mtr phase 1
;                 ||||_____ m1p2 - rite mtr phase 2
;                 |||______ m2p1 - left mtr phase 1
;                 ||_______ m2p2 - left mtr phase 2
;                 |
;                 |________ ena245=0
;
; ###################################################
;
;             76543210
b_pins	equ b'11111111' ; 
b_tris	equ b'11111111' ; inputs =1, outputs =0
;             ||||||||
;             ||||||||____ push_me=0, head2head pushing?
;             |||||||
;             |||||||_____ spare
;             ||||||______ spare
;             |||||_______ spare
;             ||||
;             ||||________ left-front IR-sensor, 0=active
;             |||_________ rite-front IR-sensor, 0=active
;             ||
;             ||__________ left edge detector 0=active
;             |___________ rite edge detector 0=active

bit0	equ	0
bit1	equ	1
bit2	equ	2
bit3	equ	3
bit4	equ	4
bit5	equ	5
bit6	equ	6
bit7	equ	7

#define	bank0	status,rp0
#define	bank1	status,rp0
#define	z_flag	status,z
#define	carry	status,c

#define	motors		porta
#define leftp1		porta,bit0
#define	leftp2		porta,bit1
#define ritep1		porta,bit2
#define	ritep2		porta,bit3
#define ena245		porta,bit4

; ena245, m2p2, m2p1, m1p2, m1p1
#define	m1cw	b'00001' ; turn left  w/ rite motor
#define	m1ccw	b'00010' ; turn right w/ rite motor
#define	m2cw	b'00100' ; turn right w/ left motor
#define	m2ccw	b'01000' ; turn left  w/ left motor

#define	allcw	b'00101' ; all forward
#define allccw	b'01010' ; all backup

#define rotcw	b'00110' ; rotate/turn right in place
#define rotccw	b'01001' ; rotate/turn left  in place

#define	brakes	b'00000' ; set them
#define	floats	b'11111' ; no driving of wheels

#define	sensors		portb
; interrupt bit:
#define	push_me		portb,bit0
;#define		portb,bit1 ; unused
;#define		portb,bit2 ; unused
;#define		portb,bit3 ; unused
; edge change bits:
#define	l_front		portb,bit4 ; IR sensor, 0= active
#define	r_front		portb,bit5 ; IR sensor, 0= active
#define	lt_edge		portb,bit6 ; edge sensor, 0= active
#define	rt_edge		portb,bit7 ; edge sensor, 0= active

; _snsbits, copy of PortB:
#define	push_m		_snsbits,bit0 ; push_me
;#define		_snsbits,bit1 ; unused
;#define		_snsbits,bit2 ; unused
;#define		_snsbits,bit3 ; unused
#define	l_frnt		_snsbits,bit4 ; IR sensor, 0= active
#define	r_frnt		_snsbits,bit5 ; IR sensor, 0= active
#define	l_edge		_snsbits,bit6 ; edge sensor, 0= active
#define	r_edge		_snsbits,bit7 ; edge sensor, 0= active
;
#define	_eeif	eecon1,bit5
#define	_wrerr	eecon1,bit4
#define	_wren	eecon1,bit3
#define	_wr	eecon1,bit1
#define	_rd	eecon1,bit0
;
#define	_gie	intcon,gie
#define	_inte	intcon,inte
#define	_t0ie	intcon,t0ie
#define	_rbie	intcon,rbie
#define	_intf	intcon,intf	; RBO/INT flag
#define	_t0if	intcon,t0if	; TMR0 overflow flag
#define	_rbif	intcon,rbif	; PortB pin change flag

#define	morelps		.30		; part of the 5 seconds timer, DON'T TOUCH!
#define	pwmon		.0		; max

; Values that eventually put into upcounter TMR0:
#define	pwmoff50	.255-.0		;  50% (min)
#define	pwmoff51	.255-.1		;  51%
#define	pwmoff57	.255-.32	;  57%
#define	pwmoff64	.255-.64	;  64%
#define	pwmoff70	.255-.96	;  70%
#define	pwmoff75	.255-.128	;  75%
#define	pwmoff81	.255-.160	;  81%
#define	pwmoff88	.255-.192	;  88%
#define	pwmoff93	.255-.224	;  92%
#define	pwmoff99	.255-.254	;  99%
#define	pwmoff100	.0		; 100% (max)
;
; RAM RAM RAM RAM RAM RAM RAM RAM RAM
;
	CBLOCK	0x0C	; to 0x4F inclusive
	 _status, _wtemp
	 _sec5, _loops, _counts, _snsbits
	 _offtime
	 _eeadr, _eedata, _eeloop
	 _local		; reserves and uses .11 bytes here...
	ENDC

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;     @@@@
;    @   .@
;    @  . @
;    @ .  @
;    @.   @
;     @@@@
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
	org	0

	b	Cold
	b	Cold
	b	Cold
	b	Cold
;
;44444444444444444444444444444444
;         4
;    4    4
;    4    4
;    444444
;         4
;         4
;44444444444444444444444444444444
;
	org	4

	movwf	_wtemp		; save W
	swapf	status,w	; move status to W (nibbles)
	movwf	_status		; save status register
;
; "W & Status Registers" saved...
; Does the motor driver need to be disabled
; during interrupts???
;
	bsf	ena245		; disable motor drivers
	btfsc	_rbif		; did an edge occur?
	b	doedges		; 1= yes, go do it.
	btfss	_intf		; push_me = sumo?
	b	MtrOn		; 0= default, no ints found, false hit.
;
dosumo	bcf	_intf		; clear int reason
	movlw	.50		; change the length of run-time
	movwf	_counts		; ../
	movlw	pwmoff100	; PWM run time in %
	movwf	_offtime	; change it
	movlw	allcw		; go forward & enabled
	movwf	motors		; motors now running
	b	Ixit		; default exit, restart motors.
;
; Interrupt Return:
;
MtrOn	bcf	ena245		; re-enable motor drivers
Ixit	swapf	_status,w	; restore status register (nibbles)
	movwf	status		; restores bank, etc.
	swapf	_wtemp,f	; restore W (nibbles)
	swapf	_wtemp,w	; without changing "status" bits.
	retfie
;
; Found any edge, now process it:
;
doedges	movfw	sensors		; make a copy of sensors, PortB
	movwf	_snsbits	; ../
	bcf	_rbif		; clear reason while write finishes
; 2 EDGES:
	btfss	r_edge		; _snsbits, 0= active rite_edge
	b	dorite
	btfss	l_edge		; _snsbits, 0= active left_edge
	b	doleft
; 2 IR:
	btfss	r_frnt		; _snsbits, 0= active push_me
	b	riteturn	; go that way
	btfss	l_frnt		; _snsbits, 0= active push_me
	b	leftturn	; go that way
	b	MtrOn		; default, no edges found, restart motors.
;
; Routines to move "NOW"!
;
dorite	movlw	m1ccw		; rotate ccw with rite motor
	movwf	motors
	movlw	.10		; change the length of run-time
	movwf	_counts		; ../
	movlw	pwmoff51	; PWM offtime
	movwf	_offtime	; normalize it
	b	Ixit
;
doleft	movlw	m2ccw		; rotate cw with left motor
	movwf	motors
	movlw	.10		; change the length of run-time
	movwf	_counts		; ../
	movlw	pwmoff51	; PWM offtime
	movwf	_offtime	; normalize it
	b	Ixit
;
riteturn
	movlw	rotcw		; turn right, top view
	movwf	motors
	movlw	.50		; change the length of run-time
	movwf	_counts		; ../
	movlw	pwmoff51	; PWM offtime
	movwf	_offtime	; normalize it
	b	Ixit
;
leftturn
	movlw	rotccw		; turn left, top view
	movwf	motors
	movlw	.50		; change the length of run-time
	movwf	_counts		; ../
	movlw	pwmoff51	; PWM offtime
	movwf	_offtime	; normalize it
	b	Ixit
;
; ###############################
;
Cold	clrf	intcon		; no interrupts used at all
	clrf	tmr0		; start timer after 2 cycles
	movlw	pwmoff64	; normal PWM run time in %
	movwf	_offtime	; stuff the variable
	movlw	a_pins		; motors off
	movwf	porta
	movlw	b_pins
	movwf	portb
	bsf	bank1		; yup, continue
	movlw	_opt32		; setup prescaler amount
	movwf	option_reg
	movlw	a_tris		; setup external pin directions
	movwf	trisa
	movlw	b_tris
	movwf	trisb
	bcf	bank0
	nop
	nop
;
; ###############################
;
; Hold push_me in while powering up or pushing RESET,
; Then release to start 5 seconds timer.
; Else it skips over this stuff and runs immediately.
;   This ~works at 14.3MHz
;
wait5secs
	btfsc	push_me		; is wait-5-seconds enabled?
	b	human		; no, skip for now
	call	pauze		; yes, debounce timer
;
; skip over this if push_me not activated...
;
w5s1	btfss	push_me		; hang until switch
	b	w5s1		; is released...
;
; part of the 5 seconds timer, DON'T TOUCH!
;
	movlw	.75		; outer loop
	movwf	_sec5		; a guess...

w5s2	call	pauze		; this long
	decfsz	_sec5,1		; when =0 then quit
	b	w5s2		; else run timer
	b	IntsOn		; done with timer=5secs...
;
; ###############################
; Alternate entry point...
;
pauz4	movlw	.60		; testing each wheel during power-up.
	b	pauz2
;
; Entry Point for timer...
; part of the 5 seconds timer, DON'T TOUCH!
;
pauze	movlw	morelps
pauz2	movwf	_loops
	bcf	_t0if
pz3	clrf	tmr0
pz2	btfss	_t0if		; spin until TMR0 overflows
	b	pz2
	bcf	_t0if		; then clear TMR0 overflow flag
	nop
	decfsz	_loops,1	; outer (TMR0) loop
	b	pz3		; not =0 yet...
	return			; when _loops =0
;
; ###############################
;
; These two routines
;   can be eliminated later...
;
human	movlw	m1cw		; rite motor moves forward
	movwf	motors
	call	pauz4

	movlw	m2cw		; left motor moves forward
	movwf	motors
	call	pauz4
;
; ###############################
;
; Now enable interrupts
; For _rbif & _intf...
;
IntsOn
 if version == 1
	call	Times	; load up on EEPROM-->>RAM data bytes.
 endif
	movlw	_inton	; gie, inte, rbie, no t0ie!
	movwf	intcon	; go!
;
; ###############################
;
; Run Time:
;
; How this works...
;	Run forward for .xxx ( _counts ) times.
;	  [And expect interrupts to change direction.]
;	Run for that time then change back to going forward...
;	...when _counts runs out or
;	...when direction changes from interrupt time.
;	So, if rite-edge goes active,
;	_rbif goes active(1) and interrupt happens.
;	software changes the motor direction, PWM_offtime and _counts amount.
;	This moves the sumo in a different direction...
;	until another interrupt or _counts runs out.
;	Then motor direction, PWM_offtime and _counts gets reset to forward.
; -------------------------------------------------------------
; PWM on time:
;
Main	movlw	.50		; testing this # ...
	movwf	_counts		; update direction counter
	movlw	pwmoff64	; normal forward speed in %
	movwf	_offtime	; stuff the variable
	movlw	allcw		; now go forward
	movwf	motors		; turn motors on
	b	Run2
;
; PWM on Time:
;	Always full TMR0 amount.
;	With motors enabled.
;
Running	bcf	ena245		; turn motors on
Run2	bcf	_t0if		; clear TMR0 done flag
	clrf	tmr0		; reset TMR0 itself (or for the first time)

RT2	btfss	_t0if		; if TMR0 not overflowed,
	b	RT2		; then continue
;
; PWM off time:
;
;	TMR0 is an upcounter (to overflow)
;	_offtime is adjustable from .255 (one tick) to .0 (255 ticks).
;	on time is fixed to 256 while _offtime can be adjusted
;	with .255-.###. It gives the ### that is needed to count up to overflow.
;
; For instance: 254 written to TMR0 and starts to count UP,
; TMR0 counts from 254, 255, 0 at this "255 to 0" the overflow flag hits.
; This is two TMR0 "ticks".  "~" means "approximate".
;
; Or: Using .255-.254 = .1
; thus TMR0 now counts up from .1, .2, .3, etc. this gives 254 "ticks".
;
;	.0		gives total time = ~50% speed (255 TMR0 ticks)
;	.255-.254	gives total time = ~51% speed (254 TMR0 ticks)
;	.255-.192	gives total time = ~64% speed (192 TMR0 ticks)
;	.255-.128	gives total time = ~75% speed (128 TMR0 ticks)
;	.255-.64	gives total time = ~88% speed ( 64 TMR0 ticks)
;	.255-.1		gives total time = ~98% speed (  2 TMR0 ticks)
;	.255		gives total time = ~99% speed (  1 TMR0 tick)
;
	bsf	ena245		; PWM motors off
	movfw	_offtime	; can be changed shorter until _counts resets
	movwf	tmr0		; normal PWM off time =1/2
	bcf	_t0if		; clear before using...
	nop			; wait for write to finish...
	nop			; .../
	nop			; ../
Pot3	btfss	_t0if		; if tmr0 not done then loop
	b	Pot3
	bcf	_t0if		; else done
;
; TMR0 has now overflowed,
; Now check for going forward again,
; Or staying in current direction & timing.
;
	decfsz	_counts,1	; update TMR0's outer loop
	b	Running		; no change in direction
	b	Main		; yes, change direction
;
 if version == 1
	include	"eeprom.inc"
 endif
;
;--------------------------------
;
	END
