' PROGRAM: tuner_code.bs2		Revision 6/25/01 
' written by Jim Garland W8ZR 

'	 {$stamp BS2sx}			'Required statement - specifies Stamp version
' ==============================================================
'	Program controls automatic antenna tuner. This version uses a rotary solenoid to turn a 12 position
'	bandswitch, and stepper motors to control two variable capacitors. In auto mode, tuner measures TX frequency, looks up corresponding
'	settings in memory, and moves steppers and solenoid to the settings. The variable capacitors and switched inductor can also be
'	manually controlled with optical encoders (caps) or up/down buttons (inductor). The tuner shifts to manual
'	mode whenever the rotary encoders are turned. The tuner powers up by retrieving the last
'	settings (automatically stored in EEPROM) and switching to auto mode. There are 4 buttons, which have dual purposes.
'	All but the UP/DWN buttons have confirming beeps (short for 1 press, long if held down).
 
'	UP/DWN Buttons:		In auto mode, steps through the memories, in manual mode steps through the inductor settings. 
'	AUTO/SAVE Button:		One press shifts tuner to automatic mode. If held down, stores current setting in memory.
'	IN/OUT-RESET Button:	One press toggles tuner on-line/off-line. If held down, initializes the steppers and rotary solenoid to zero.			

'	The display shows a 2 sec startup message and then displays the C1,C2, and L settings (top line), and the memory
'	frequency (second line). A message also indicates when tuner is off-line.

'		Port Connections & INPUT/OUTPUT Status

'		P0:	IN	Encoder1 A 
'		P1:	IN  	Encoder1 B
'		P2:	IN	Encoder2 A
'		P3:  	IN	Encoder2 B
'		P4:	IN	UP button
'		  	OUT	Speaker
'		P5:  	IN	DOWN button
'			IN	Reset limit detect  
'		P6:	OUT	Auto Mode LED
 '		P7:	IN	IN/OUT-RESET button		
'		P8:  	IN	AUTO/SAVE button	
'		P9	OUT	IN/OUT relay
'		P10: 	OUT	Ext.capacitor relay
'		P11: 	OUT	Rotary solenoid step
'		P12: 	OUT	Stepper2 step
'		P13: 	OUT	Stepper1 step
'		P14: 	OUT	Stepper rotation CW=0,CCW=1
'		P15:  IN	TX frequency detect
'		P16: 	OUT	LCD serial data

'===============================================================================================
'Default C1, C2, and L Data in EEPROM (134 bytes)

' C1 Data (134 values) stored in EEPROM addresses 0-144 ($000-$08F)

	DATA 16,11,14,21,31,35,23,41,21,51,101,61,19,73,1,83,73,93,77,69		'160meters (0-19)
	DATA 81,101,13,23,13,55,33,13,65,33,45,55,61,77,89,99,11,23,33,45,55,67,77,87,89	'80m(20-44)
	DATA 41,23,123,87,65,21,35,11,100,29,33,35,21,43,49				'40meters (45-59)
	DATA 31,101,65,19,39									'30meters (60-64)
	DATA 20,85,17,93,13,101,51,11,41,21,100,51,33,13,65,33,45,29		'20 meters (65-82)
	DATA 17,77,87,99,11,79									'17 meters (83-88)
	DATA 15,43,55,65,77,89,99,11,159							'15meters (89-97)
	DATA 12,98,99										'12meters (98-100)
													'10 meters (99-134)
	DATA 101,30,10,146,20,30,35,22,40,21,50,200,60,19,70,1,80,170,90,160,100,150,110,140,120,130,250,130,14,65,33,44,204,109

' C2 Data (134 values) stored in EEPROM addresses 145-288 ($090-$11F)

	DATA @$090, 16,10,46,20,30,38,22,40,24,50,100,60,18,70,2,80,17,90,60,16	'160meters (0-19)
	DATA 82,100,14,20,100,50,13,14,64,32,44,56,66,78,88,98,12,22,32,44,54,66,76,48,88 '80m(20-44)
	DATA 42,22,12,88,66,22,30,10,99,20,30,36,24,40,48				'40meters (45-59)
	DATA 32,100,60,18,38									'30meters (60-64)
	DATA 20,80,10,90,16,100,15,10,40,20,13,50,10,14,64,34,44,28			'20 meters (65-82)
	DATA 17,76,88,98,22,78									'17 meters (83-88)
	DATA 15,44,54,66,76,88,99,12,58							'15meters (89-97)
	DATA 12,12,28										'12meters (98-100)
													'10 meters (101-134)
	DATA 10,30,10,46,20,30,35,22,40,21,50,100,60,19,70,1,80,17,90,16,96,10,100,40,20,30,25,30,14,65,33,44,24,102

' L Data (11 values) stored in EEPROM addresses 289-304 ($120-$12F)
' and startup Addr1,stpcnt1,stpcnt2,SWcnt ($12C-$12F)

	DATA @$120,1,2,3,4,5,6,7,8,9,10,11,0,101,30,98,6
'=======================================================================================	

'	SYMBOL TABLE


'	========================
'	User Supplied Parameter

vernier	con	10		'encoder vernier constant (an even number, twice the vernier ratio)

'	========================

old1A   	var	bit		'previous A-output, encoder1
old1B	  	var	bit		'previous B-output  encoder1
old2A		var	bit		'previous A output, encoder2
old2B		var	bit		'previous B output, encoder2
stpcnt1 	var	byte		'stepper1 count
stpcnt2 	var	byte		'stepper2 count
SWcnt 	var	byte		'rotary switch count
memval  	var	byte		'C1,C2, or L memory variable
stp	  	var	byte		'step variable
btnwk1  	var  	byte		'button workspace variable
btnwk2  	var  	byte		'button workspace variable
btnwk3  	var  	byte		'button workspace variable
btnwk4  	var  	byte		'button workspace variable
x	  	var	byte		'gen purpose variable
y	  	var	byte		'gen purpose variable
z		var	byte		'gen purpose variable
freq	  	var	word		'frequency variable
freq1		var	word		'frequency variable
addr1	  	var	byte		'memory address variable (0-135)
addr2	  	var	word		'memory address variable (145-288)
addr3	  	var	word		'memory address variable (289-304)
loopcnt1 	var	byte		'loop counter
loopcnt2	var	word		'loop counter
N96	  	con 	$40F0		'LCD 9600 baud		
I 	  	con	254		'LCD instruction toggle
CLR	  	con	1		'LCD clear display

DIRS=%0111111001000000	'P0-P5,P7-P8,P15 set to input, others to output
'=======================================================================================
'		PROGRAM BEGINS HERE
		
'Retrieve last stepper settings from EEPROM (stored before previous turnoff)

	READ 	$12C,addr1
	READ 	$12D,stpcnt1
	READ	$12E,stpcnt2
	READ	$12F,SWcnt

'Initialize LCD, display opening message

 top:	PAUSE 1000						'wait 1sec for LCD to wake up
	SEROUT 16,n96,[I,CLR]				'clear LCD
	PAUSE 1						'wait 1msec for LCD
								'display program name and revision number
	SEROUT 16,n96,[" W8ZR  EZ-Tuner",I,194,"Rev. 6/24/01"]
	PAUSE 2000						'show startup msg 2 secs
	SEROUT 16,n96,[I,CLR]				'clear LCD						

'Format LCD for displaying C1, C2, L, and frequency at following locations: L1_C4(131):stpcnt1,
'L1_C14(141):stpcnt2, L2_C6(197):freq, L2_14(205):SWcnt 

	SEROUT 16,n96,[I,128,"C1:",I,138,"C2:",I,192,"Freq:",I,203,"L:"]	
'=========================================================================================
'Initialize tuner to ON-LINE and AUTO mode

	OUT9=1		'Set mode to ON-LINE
	PUT 2,0		'Set mode flag to AUTO
	OUT6=1		'Light LED
	z=vernier/2		'set z at midpoint of vernier
				'now go to comp_freq
'=========================================================================================

'Take retrieved stepper settings, compute the frequency segment and move stepper to settings.

comp_freq:	'Input addr1 and branch to corresponding band.

	LOOKDOWN addr1,<[20,45,60,65,83,89,98,101,135],x
	BRANCH x,[freq160,freq80,freq40,freq30,freq20,freq17,freq15,freq12,freq10] 


'=========================================================================================

'Routine measures transmitter frequency at P15. First part of routine polls P15 for 400uS to
'see if signal present. If no signal detected (x=0), skips to rd_buttons. 
'Purpose is to avoid slowing down loop unless valid signal present, and to prevent measurement
' errors by ensuring signal is present when freq-measuring gate opens.

'Second part of routine measures frequency twice, with gate of 250*0.4usec=0.1sec, 
'and requries both measurements to agree. Reason for two measurements is to prevent errors caused by 
'tracking of modulated SSB signals.

get_freq:
		COUNT 15,1,x					'poll for signal, return 0 if NO,low integer if YES
		IF x=0 THEN rd_buttons				'skip if no signal present
		COUNT	15,250,freq					'otherwise,measure frequency of signal
		COUNT 15,250,freq1				'measure it again
		IF NOT freq = freq1 THEN rd_buttons		'skip if measurements not the same
		freq=freq+(freq/1186)				'trim freq to correct for BS2sx xtal error
		old1A=IN0 : old1B=IN1				'update old1A and old1B to fix encoder slippage during count	
									'now go to freq_tune

'===============================================================================================

' Input transmit frequency from get_freq. If in amateur band, compute the memory addresses and the frequency
' segment corresponding to the addresses. Then retrieve settings from memory and move stepper to the settings.
' If frequency not in amateur band,take no action, but go back to get_freq and poll TX frequency.
' Display shows the lower end of the memory frequency segment, not the actual TX freq.
' Note that addr1 (address of C1) is computed from the get_freq TX frequency. Addr2 tracks addr1
' but is offset by $090 (addr2=addr1+$090).Addr3 is the band index and is obtained from a band lookup table.


freq_tune:

		LOOKDOWN freq,<[1800,2001,3500,4001,7000,7351,10100,10201,14000,14351,18068,18169,21000,21451,24890,24991,28000,29701],x
		BRANCH x,[get_freq,band160,get_freq,band80,get_freq,band40,get_freq,band30,get_freq,band20,get_freq,band17,get_freq,band15,get_freq,band12,get_freq,band10]
		GOTO get_freq				'if freq>29700, take no action & read the buttons

band160:	addr1=freq/10-180				'addr1=0-19,addr2=144-163 for 160m band, 10kHz steps
freq160:	LOOKUP addr1/10,[$120,$121],addr3	'addr3=288,289 for 1800-1899kHz and 1900-1999kHz  
		freq=10*addr1+1800			'compute freq corresponding to addr1
		GOTO mem_step				'retrieve settings and move steppers 

		
band80:	addr1=freq/20-155				'addr1=20-44, addr2=164-188 for 80m band, 20kHz steps
freq80:	LOOKUP addr1/30,[$122,$123],addr3	'addr3=290,291 for 3500-3699kHz and 3700-3999kHz		
		freq=20*addr1+3100			'compute freq corresponding to address
		GOTO mem_step				'retrieve settings and move steppers

	
band40:	addr1=freq/20-305			'addr1 = 45-59, addr2=189-203 for 40m band, 20kHz steps
freq40:	addr3=$124				'addr3=292
		freq=20*addr1+6100		'compute freq corresponding to addr1
		GOTO mem_step			'retrieve settings and move steppers

	
band30:	addr1=freq/20-445			'addr1=60-64, addr2=204-208 for 30m band. 20kHz steps
freq30:	addr3=$125				'addr3=293
		freq=20*addr1+8900		'compute freq corresponding to addr1
		GOTO mem_step			'retrieve settings and move steppers


band20:	addr1=freq/20-635			'addr1=65-82, addr2=209-226 for 20m band, 20kHz steps
freq20:	addr3=$126				'addr3=294
		freq=20*addr1+12700		'compute freq corresponding to addr1
		GOTO mem_step			'retrieve settings and move steppers


band17:	addr1=freq/20-820			'addr1=83-88, addr2=227-232 for 17m band, 20kHz steps
freq17:	addr3=$127				'addr3=295
		freq=20*addr1+16400		'compute freq corresponding to addr1
		GOTO mem_step			'retrieve settings and move steppers		


band15:	addr1=freq/50-331			'addr1=89-97, addr2=233-241 for 15m band, 50kHz steps
freq15:	addr3=$128				'addr3=296
		freq=50*addr1+16550		'compute freq corresponding to addr1
		GOTO mem_step			'retrieve settings and move steppers


band12:	addr1=freq/50-399			'addr1=98-100, addr2=242-244 for 12m band, 50kHz steps
freq12:	addr3=$129				'addr3=297
		freq=50*addr1+19950		'compute freq corresponding to addr1
		GOTO mem_step			'retrieve settings and move steppers


band10:	addr1=freq/50-459			'addr1=101-134, addr2=245-278 for 10m band, 50kHz steps
freq10:	addr3=$12A				'addr3=298
		freq=50*addr1+22950		'compute freq corresponding to addr1
		GOTO mem_step			'retrieve settings and move steppers


'================================================================================================

' Input addr1, addr3, current encoder counts, and compute addr2, 
' Then retrieve the settings from memory, and move both steppers and rot.solenoid to the memory 
' settings. Note that the rotary solenoid only rotates in the CW direction.
' When done, go back and check for new frequency. Also switches ext. cap. on if freq is in 160m band.
	
mem_step:

		addr2=addr1+$090					'compute addr2
		IF addr1<20 THEN cap_on				'turn on ext. cap if inside 160m band
		OUT10=0						'turn off ext. cap if outside 160m band

	ms1: 	READ addr1,memval					'retrieve memval for addr1
		IF memval > stpcnt1 THEN  CWmemstep1	'test for CW or CCW direction
		IF memval < stpcnt1 THEN CCWmemstep1	'and move stepper
	ms2:	READ addr2,memval					'retrieve memval for addr2
		IF memval > stpcnt2 THEN  CWmemstep2
		IF memval < stpcnt2 THEN CCWmemstep2
	ms3:	READ addr3,memval					'retrieve memval for addr3
		IF memval > SWcnt THEN  pulse3		'step rotary solenoid CW
		IF memval < SWcnt THEN CCWmemstep3		'
	ms4:	GOSUB display
		GOTO get_freq					'if no change, check for new frequency

cap_on:
		OUT10=1						'switch on ext. cap
		GOTO ms1						'and return
'================================================================================================
' Stepper driver and rotary solenoid routines for CW and CCW rotation. No CCW routine is needed for
' rotary solenoid, since it only turns in CW direction. 
		
CWmemstep1:	OUT14=0				'set stepper1 to CW
		GOTO pulse1

CWmemstep2:	OUT14=0				'set stepper2 to CW
		GOTO pulse2


'		====================================================

CCWmemstep1:OUT14=1				'set stepper1 to CCW
		GOTO pulse1

		
CCWmemstep2:OUT14=1				'set stepper2 to CCW
		GOTO pulse2


CCWmemstep3:memval=memval+12			'advance memval one revolution
		GOTO pulse3

'		=====================================================

pulse1:	stp = ABS(memval-stpcnt1)	'calculate no. of steps needed	
		FOR x = 1 TO stp
		PULSOUT 13,10			'send stepper to destination
		PAUSE 10				'wait for stepper to finish
		NEXT
		stpcnt1=memval			'update stpcnt1
		GOTO ms2
	

pulse2:	stp = ABS(memval-stpcnt2)	'calculate no. of steps needed	
		FOR x = 1 TO stp
		PULSOUT 12,10			'send stepper to destination
		PAUSE 10				'wait for stepper to finish
		NEXT
		stpcnt2=memval			'update stpcnt2
		GOTO ms3
	

pulse3:	stp = memval-SWcnt		'calculate no. of steps needed	
		FOR x = 1 TO stp
		PULSOUT 11,65000			'pulse solenoid for 52msec (65K x 0.8usec)
		PAUSE 100				'wait 200msec for solenoid to finish
		NEXT
		SWcnt=memval//12			'update SWcnt, (mod 12 to keep memval<12)
		GOTO ms4				'and return
					
'===============================================================================================			

' Read the UP, DOWN, AUTO/SAVE, and IN-OUT/RESET buttons. If pressed, take appropriate action.
' and if not pressed, read the encoders
	
rd_buttons:
	
		BUTTON 4,0,254,1,btnwk1,1,upbutton		'UP button pressed?
		BUTTON 5,0,254,1,btnwk2,1,dwnbutton		'DOWN button pressed?
	     	BUTTON 8,0,254,255,btnwk3,1,auto_save	'AUTO mode if 1 press,SAVE if held down
	iobtn:BUTTON 7,0,254,255,btnwk4,1,IO_reset	'Toggle IN/OUT if 1 press, RESET if held down


' The variable loopcnt1 is used to count loops for the AUTO/SAVE and IO/RESET buttons, which have
' a second function if held down.The logic flow is more complicated for the IO/RESET button, because 
' one press toggles between IN-LINE and OFF-LINE, while holding the button down resets the tuner.
' The logic flow is easier for the AUTO/SAVE button, because there is no toggling of the auto mode.


		loopcnt1=loopcnt1+1 MAX 255			'count loops for SAVE & RESET buttons
		BRANCH out9,[iobtn,rd_encoders]	 	'if OFF-LINE read I/O button until changed

'===============================================================================================

'Auto_save BUTTON command checks status of port 8. Normally,the loop counter = 255
'when the button is first pressed, so the routine changes the mode to AUTO and resets loopcnt to 0. After a delay
'of 254 counts the button status is checked again, and if still pressed the routine branches to SAVE and stores
'the current stepper settings in EEPROM

auto_save:	

		IF loopcnt1=253 THEN save		'save if loop counter=253, otherwise set AUTO mode

	auto:	loopcnt1=0					'reset loop counter
		PUT 2,0					'set mode flag to auto mode
		OUT6=1					'light LED
		FREQOUT 4,200,1000 			'short beep to confirm mode change
		GOTO rd_encoders				'then exit


	save:	WRITE addr1,stpcnt1			'save settings
		WRITE addr2,stpcnt2
		WRITE addr3,SWcnt
		FREQOUT 4,300,800 			'long beep to confirm save (3 tones)
		FREQOUT 4,300,1000 			'
		FREQOUT 4,500,1200 			'	
		GOTO rd_encoders				'exit in auto mode

'===================================================================================================

'The IO_reset BUTTON instruction checks status of port 7. Normally,the loop counter = 255
'when the button is first pressed, so the routine toggles the IN/OUT status and resets loopcnt to 0. After a delay
'of 254 loops,the button status is checked again, and if still pressed the routine branches to RESET.

IO_reset:	IF loopcnt1=253 THEN reset		'reset if loop counter=254, otherwise toggle IN/OUT
	   	IF loopcnt1=255 THEN zeroloop		'zero loop counter only if starting count=255
								'otherwise go to inout
	inout:
		TOGGLE 9					'Toggle port 9 (1=IN-Line, 0=OFF-Line)
		FREQOUT 4,200,1000 			'short beep to confirm mode change
		BRANCH out9,[offline,online]		'read output latch and branch


	offline:
		SEROUT 16,n96,[I,192,"   OFF-LINE    "]	'display off-line msg
		GOTO iobtn						'loop to I/O button until pressed

	online:
		SEROUT 16,n96,[I,192,"Freq:",I,197,DEC freq,"  ",I,203,"L:",I,205,DEC SWcnt," "]	'restore 2nd line of display 
		GOTO rd_encoders											'and continue

zeroloop:	loopcnt1=0
	    	GOTO inout

reset:
		FREQOUT 4,300,800 			'long beep to confirm reset(3 tones)
		FREQOUT 4,300,1000 			'
		FREQOUT 4,500,1200 			'
		OUT9=0					'take tuner OFF-LINE
		OUT14=1					'set stepper direction to CCW and goto reset1 
	
'		=======================================================

		reset1: dir5=0				'
			  PULSOUT 13,10			'pulse stepper1
			  PAUSE 20				'wait for stepper to finish
			  IF IN5=0 THEN upstep1		'is limit reached?
		        GOTO reset1:			'if not,loop until limit reached	

		upstep1:
			  TOGGLE 14				'set stepper direction to CW
			  PULSOUT 13,10			'step one position to free up limit
			  PULSOUT 13,10			'step second position to free up limit
			  PAUSE 500				'TEMPORARY - delay for pushbutton limit
		        stpcnt1=2				'set stpcnt1 to match position
			  TOGGLE 14				'set stepper direction to CCW
			  GOTO reset2			'now goto reset 2 (stepper2)
									
'		=======================================================

		reset2:
			  PULSOUT 12,10				'pulse stepper2
			  PAUSE 20					'wait for stepper to finish
			  IF IN5=0 THEN upstep2			'limit reached?
			  GOTO reset2:				'if not,loop until limit reached	

		upstep2:
			  TOGGLE 14					'set stepper direction to CW
			  PULSOUT 12,10				'step one position to free up limit
			  PULSOUT 12,10				'step second position to free up limit
			  PAUSE 500					'TEMPORARY - delay for pushbutton limit
			  stpcnt2=2					'set stpcnt2 to match position
			  TOGGLE 14					'set stepper directiion to CCW
									'now go to reset3 (stepper 3)
'		========================================================

		reset3:
			 PULSOUT 11,65000				'pulse rotary solenoid 52 msec
			 PAUSE 100					'wait for solenoid to catch up
			 IF IN5=0 THEN finish			'finish if limit reached (no upstep needed)
			 GOTO reset3				'if not,loop until limit reached

		 finish:
			  SWcnt=0					'set SWcnt = 0
			  GOTO top					'go to start of program
			  	
'===============================================================================================
'===============================================================================================

rd_encoders:
	 enc1:	IF IN0=old1A AND IN1=old1B THEN enc2	'read ports P0,P1, if no change read 2nd encoder
			PUT 2,1						'if changed, set mode flag to Manual
			OUT6=0						'turn off LED
			IF IN1=old1A THEN CCWenc1			'test for CCW rotation and go to CCW if bits match
										'if not, go to CWenc
CWenc1:	'===================================
'			Encoder Vernier Routine - CW

			z=z-1							'decrement vernier counter
			old1A=IN0 : old1B=IN1				'update old1A and old1B	
			if z>0 then  enc1					'loop until count reaches zero
			z=vernier/2						'then reset count to vernier midpoint
										'and continue
'		====================================
	
			IF stpcnt1=102 THEN enc1			'loop again if stepper at maximum CW
			stpcnt1=stpcnt1+1					'increment encoder count,maximum is 102
			OUT14=0						'set rotation for CW
			GOTO pulser1					'and move stepper1

CCWenc1:	'===================================
'			Encoder Vernier Routine - CCW

			z=z+1							'increment vernier counter
			old1A=IN0 : old1B=IN1				'update old1A and old1B
			if z<vernier then enc1				'loop until vernier reached
			z=vernier/2						'reset count at vernier midpoint
		'===================================
			IF stpcnt1=2 THEN enc1 				'loop again if stepper at minimum CCW
			stpcnt1=stpcnt1-1					'decrement encoder count,minimum limit is 2
			OUT14=1						'set rotation to CCW
										'when done go to pulser1
			
	pulser1:
			PULSOUT 13,10					'8uS pulse to stepper1
			SEROUT 16,n96,[I,131, DEC stpcnt1,"  "]	'update C1 on display
  			GOTO enc1						'return to loop when done

'===================================================================================================

enc2:
			IF IN2=old2A AND IN3=old2B THEN ck_mode	'read ports P2,P3, if no change loop in auto or manual mode
			PUT 2,1						'if changed, set mode flag to Manual
			OUT6=0						'and turn off LED
			IF IN3=old2A THEN CCWenc2			'test for CCW rotation, goes to CCW if bits match
										'if not, go to CWenc2
CWenc2:	'===================================
'			Encoder Vernier Routine - CW

			z=z-1							'decrement vernier counter
			old2A=IN2 : old2B=IN3				'update old2A and old2B	
			if z>0 then  enc2					'loop until count reaches 0
			z=vernier/2						'then reset count to vernier midpoint
										'and continue
'		====================================
	
			if stpcnt2=102 then rd_buttons		'loop again if stepper 2 at max cw
			stpcnt2=stpcnt2+1					'increment encoder count,stop at 102
			OUT14=0						'set rotation to CW
			GOTO pulser2					'and move stepper2

			
CCWenc2:	'===================================
'			Encoder Vernier Routine - CCW

			z=z+1							'increment vernier count
			old2A=IN2 : old2B=IN3				'update old2A and old2B
			if z<vernier then enc2				'loop until count reaches vernier
			z=vernier/2						'then reset count to vernier midpoint
										'and continue
		'===================================

			if stpcnt2=2 then rd_buttons			'loop again if stepper2 at minimum CCW
			stpcnt2=stpcnt2-1					'decrement encoder count,stop at 2
			OUT14=1						'set rotation to CCW
										'when finished go to pulser2

	pulser2:
			PULSOUT 12,10					'8uS pulse to stepper2
			SEROUT 16,n96,[I,141, DEC stpcnt2,"  "]	'update C2 on display
			GOTO rd_buttons					'loop in MANUAL mode
'
'============================================================================================
' routine checks for auto or manual mode, and also stores the current settings in EEPROM after 255
' loops of no activity.

ck_mode:

			loopcnt2=loopcnt2 + 1			'increment loop counter
			IF loopcnt2=1000 THEN store_last	'store last settings after 1000 loops of no activity
	ck_md1:	GET 2,x					'retrieve mode (0=auto,1=manual)
			BRANCH x,[get_freq,rd_buttons]	'and branch accordingly.

'============================================================================================

'Stores current settings (addr1, stpcnt1, stpcnt2, SWcnt) in EEPROM after checking if 
'settings have changed. Memory addresses are addr1=$12C, stpcnt1=$12D, stpcnt2=$12E, SWcnt=$12F

store_last:

	stor0:READ $12C,memval				'read memory value
		IF memval=addr1 THEN stor1		'skip if no change
'		WRITE $12C,addr1				'if changed, store addr1

	stor1:READ $12D,memval
		IF memval=stpcnt1 THEN stor2		'skip if no change
'		WRITE $12D,stpcnt1			'if changed, store stpcnt1


	stor2:READ $12E,memval
		IF memval=stpcnt2 THEN stor3		'skp if no change
'		WRITE $12E,stpcnt2			'if changed, store stpcnt2

	stor3:READ $12F,memval
		IF memval=SWcnt THEN resetlc2		'skip if no change
'		WRITE $12F,SWcnt				'if changed, store SWcnt

	resetlc2:	loopcnt2=0				'reset loopcnt2 after store

		READ $12D,x
		GOTO ck_md1
	

'============================================================================================

'Increment or decrement indices and update stepper settings if UP or DOWN button pressed.
'In AUTO mode, steps through memories, in MANUAL mode, steps inductor.

upbutton:	GET 2,x					'check if auto (0) or manual (1) mode
		BRANCH x,[autoup,manup]			

dwnbutton:	GET 2,x					'check if auto (0) or manual (1) mode
		BRANCH x,[autodwn,mandwn]		

'                 ==================================================

autoup:	addr1=addr1+1 MAX 134			'increments addr1 and limits to highest value
		GOTO comp_freq				'output new address to stepper

autodwn:	IF addr1=0 THEN comp_freq		'exit if addr1 is zero
		addr1=addr1-1				'decrement address if greater than zero
		GOTO comp_freq				'output new address to stepper (comp_freq)


'                 ==================================================			
'Routine advances rotary solenoid 1 step for manup routine, and 11 steps for mandwn (switch has 12
'positions. For manup routine, switch counter rolls over to zero when it reaches 12. For mandwn
'routine, switch counter stops at zero, to minimize needless switch rotations.

manup:	SWcnt=(SWcnt+1)//12			'increment switch count, rollover if equals 12.
		PULSOUT 11, 65000				'pulse solenoid 52 msec
		PAUSE 100					'wait for solenoid to catch up
		GOSUB display				'update display
 		GOTO rd_buttons

mandwn:	IF SWcnt=0 THEN skp_mandwn		'skip if count=0	
		SWcnt=SWcnt-1				'decrement rotary switch count if not zero
		FOR z = 1 TO 11				'rotate solenoid 11 positions
		PULSOUT 11, 65000				'pulse solenoid 52msec
		PAUSE 100					'wait for stepper to catch up
		NEXT
		GOSUB display				'update display
 skp_mandwn:GOTO rd_buttons
	

'===========================================================================================

'Display stepper counts and frequency segments at following locations: L1_C4(131):stpcnt1,
'L1_C14(141):stpcnt2, L2_C6(197):freq, L2_14(205):SWcnt.


display:
							
	SEROUT 16,n96,[I,131,DEC stpcnt1," ",I,141,DEC stpcnt2," ",I,197,DEC freq," ",I,205,DEC SWcnt,"  "]	
	old1A=IN0 : old1B=IN1				'refresh old1A and old1B to avoid encoder slippage
	old2A=IN2 : old2B=IN3				'refresh old2A and old2B to avoid encoder slippage
	RETURN

'==========================================================================================

