please dont rip this site

IO Stepper Linistep Liniclock LINICLOCK_12HOUR.ASM

; ******************************************************************************
;
;  LiniClock_12hour.asm (one-hand analogue clock using LiniStepper V1 or v2 PCB)
;  PIC 16F628A code 
;  Copyright Sep 2010 - Roman Black   http://www.RomanBlack.com
;
;  200/400/1200/3600 steps
;  Clock uses one stepper motor to turn one hand. The clock takes exactly
;  12 hours for a full rotation, giving an attractive 12hour 
;  clock face with a single "hours" hand.
;  The clock is driven directly from the PIC's 16MHz xtal OR
;  can be driven from 60Hz or 50Hz mains freq for high accuracy.
;  One button is used to "set" the clock by advancing the hand,
;  the clock set button is on pin RA0 and HI = clock set (Note!!
;  if using Lini v1 PCB you also need a 10k pull-down resistor on that
;  pin but on Lini v2 PCB the resistor is not needed).
;
;  This code was adapted from the Linistepper v2 code, the main difference
;  is that instead of advancing the motor 1 microstep when the step
;  input goes /, it now advances the motor one microstep every 50 seconds,
;  this gives exactly 12 hours per rotation with a cheap 48step/rev stepper
;  motor. (If using a 200step/rev motor, it will advance one microstep
;  every 12 seconds).
;
;  Dip switch J1 selects motor type; ON = 200step/rev motor, OFF = 48step/rev motor
;  Dip switch J2 selects clock source; ON = mains freq detect, OFF = PIC 16Mhz xtal
;
;  PORTA.F0 = clock set button; Hi = clock set
;  PORTA.F1 = 60Hz mains freq input (optional)
;  PORTA.F2 = 50Hz mains freq input (optional)
;  (note!! replace C5 and C6 with large caps >=22uF for good clock hand smoothing)
;
;  (set mplab TABS to 5 for best viewing this .asm file)
;******************************************************************************


;==============================================================================
; mplab settings

	ERRORLEVEL -224		; suppress annoying message because of option/tris
	ERRORLEVEL -302		; suppress message because of bank select in setup ports

	LIST b=5, n=97, t=ON, st=OFF		;
	; absolute listing tabs=5, lines=97, trim long lines=ON, symbol table=OFF

;==============================================================================
; processor defined

	;include <p16f84A.inc>
	;include <p16f628.inc>
	include <p16f628A.inc>

; processor config

	IFDEF __16F84A
		__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC
	ENDIF
	IFDEF __16F628
		__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _MCLRE_ON & _BODEN_OFF & _LVP_OFF
	ENDIF
	IFDEF __16F628A
		__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _MCLRE_ON & _BODEN_OFF & _LVP_OFF
	ENDIF


;==============================================================================
; Variables here

	;-------------------------------------------------
	IFDEF __16F84A
		#define RAM_START	0x0C
		#define RAM_END	RAM_START+d'68' 		; 16F84 has only 68 ram
	ENDIF
	IFDEF __16F628
		#define RAM_START	0x20	
		#define RAM_END	RAM_START+d'96' 		; F628 has 96 ram
	ENDIF
	IFDEF __16F628A
		#define RAM_START	0x20	
		#define RAM_END	RAM_START+d'96' 		; F628A has 96 ram
	ENDIF
	;-------------------------------------------------
	CBLOCK 	RAM_START

		status_temp		; used for int servicing
		w_temp			; used for int servicing

		step				; (0-71) ustep position!
		steptemp			; for calcs

		phase			; stores the 4 motor phase pins 0000xxxx
		current1			; for current tween pwm
		current2			; for current tween pwm

		bres_hi			; hi byte of 24bit variable (for 1second timing)
		bres_mid			; mid byte
		bres_lo			; lo byte
		second_count		;
		input_edge		;
		hz_count			;

		button_debounce	; used for "clock set" button

	ENDC

	;-------------------------------------------------
	; NEW!! Just for LiniClock; set the stepper motor type!

	;#define   MOTOR_SECONDS	6	; This setting for 200step/rev motors
	#define   MOTOR_SECONDS	25	; This setting for 48step/rev motors

	;-------------------------------------------------
	; PIC input pins for porta

	#define 	CLOCK_SET		0		; HI = clock set
	#define 	Hz_60		1		; mains freq input
	#define 	Hz_50		2		; mains freq input (alternative)
	#define 	J1			3		; ON = HI = 200step/rev motor
	#define 	J2			4		; ON = HI = use mains freq input

	;-------------------------------------------------
	; Custom instructions!

	#define	skpwne		skpnz			; after subxx, uses zero
	#define	skpweq		skpz				; after subxx, uses zero
	#define	skpwle		skpc				; after subxx, uses carry
	#define	skpwgt		skpnc			; after subxx, uses carry

;==============================================================================
; CODE GOES HERE

	org 0x0000 			; Set program memory base at reset vector 0x00
reset
	goto main				;



;==============================================================================
; INTERRUPT vector here (int not used!)
	org 0x0004 			; interrupt routine must start here
int_routine

	;-------------------------------------------------
						; first we preserve w and status register
	movwf w_temp      		; 
	movf	STATUS,w          	; 
	movwf status_temp       	; 
	;-------------------------------------------------
						; we get here every TMR0 overflow 
						; int body code here if you want

	;-------------------------------------------------
						; finally we restore w and status registers and
						; clear TMRO int flag now we are finished.
int_exit
	bcf INTCON,T0IF		; must clear the overflow flag! 
	movf status_temp,w     	; 
	movwf STATUS            	; 
	swapf w_temp,f
	swapf w_temp,w          	; 
	retfie				; return from interrupt
	;-------------------------------------------------

;==============================================================================




;******************************************************************************
; MOVE MOTOR  		  sets 8 portb output pins to control motor
;******************************************************************************
; NOTE!! var step is used for sequencing the 0-71 steps
; uses tables! so keep it first in the code and set PCLATH to page 0

;------------------
move_motor				; goto label
;------------------

	;-------------------------------------------------
	; this code controls the phase sequencing and current
	; settings for the motor.

	; there are always 72 steps (0-71)

	; we can split the main table into 2 halves, each have identical
	; current sequencing. That is only 12 entries for hardware current.

	; Then can x3 the table to get 36 table entries which cover all 72 steps.
	; the 36 entries jump to 36 code pieces, which set the current values
	; for the 2 possible tween steps... We need 2 current values, one
	; for the x2 value and one for the x1 value.
	;-------------------------------------------------
	; PHASE SEQUENCING (switch the 4 coils)

	; there are 4 possible combinations for the phase switching:
	; each have 18 steps, total 72 steps:

	;	A+ B+	range 0		step 0-17
	;	A- B+	range 1		18-35
	;	A- B-	range 2		36-53
	;	A+ B-	range 3		54-71

	;-------------------------------------------------
						; find which of the 4 ranges we are in
	movf step,w			; get step
	movwf steptemp			; store as working temp

	movf steptemp,w		;
	sublw d'35'			; sub to test
	skpwle				;
	goto half_hi			; wgt, steptemp is 36-71 (upper half)

	;-------------------------
half_low					; wle, steptemp is 0-35

	movf steptemp,w		;
	sublw d'17'			; sub to test
	skpwle				;
	goto range1			; wgt
	
range0					; wle
	movlw b'00000101'		; 0101 = A+ B+
	goto phase_done		;

range1
	movlw b'00001001'		; 1001 = A- B+
	goto phase_done		;

	;-------------------------
half_hi					; steptemp is 36-71
						; NOTE! must subtract 36 from steptemp, so it
						; will become 0-35 and ok with table later!
	movlw d'36'			; subtract 36 from steptemp,
	subwf steptemp,f		; (now steptemp is 0-35)

						; now find the range
	movf steptemp,w		;
	sublw d'17'			; sub to test
	skpwle				;
	goto range3			; wgt
	
range2					; wle
	movlw b'00001010'		; 1010 = A- B-
	goto phase_done		;

range3
	movlw b'00000110'		; 0110 = A+ B-

phase_done				; note! steptemp is always 0-35 by here
	movwf phase			; store phase values

	;-------------------------------------------------
	; at this point we have the phasing done and stored as the last
	; 4 bits in var phase; 0000xxxx
	
	; now we have 36 possible current combinations, which we can do
	; by separate code fragments, from a jump table.

	; as we have 2 power modes; full and low power, we
	; need 2 tables.

	;-------------------------------------------------
	; LiniClock note!! motor is always set to high power;
	;btfsc inputs,POWER		; select table to use
	;goto table_lowpower		;

	;-------------------------------------------------
	; HIGH POWER TABLE
	;-------------------------------------------------

table_highpower			;

	movf steptemp,w		; add steptemp to the PCL
	addwf PCL,f			; 
						; here are the 36 possible values;
	;-------------------------
	goto st00				; * (hardware 6th steps)
	goto st01				;   (pwm tween steps)
	goto st02				;   (pwm tween steps)
	goto st03				; *
	goto st04				; 
	goto st05				; 

	goto st06				; *
	goto st07				;
	goto st08				;
	goto st09				; *
	goto st10				;
	goto st11				;

	goto st12				; *
	goto st13				;
	goto st14				;
	goto st15				; *
	goto st16				;
	goto st17				;

	goto st18				; *
	goto st19				;
	goto st20				;
	goto st21				; *
	goto st22				;
	goto st23				;

	goto st24				; *
	goto st25				;
	goto st26				;
	goto st27				; *
	goto st28				;
	goto st29				;

	goto st30				; *
	goto st31				;
	goto st32				;
	goto st33				; *
	goto st34				;
	goto st35				;

	;-------------------------------------------------
	; LOW POWER TABLE
	;-------------------------------------------------
	; as low power mode is for wait periods we don't need to
	; maintain the full step precision and can wait on the
	; half-step (400 steps/rev). This means much easier code tables.
	; The nature of the board electronics is not really suited
	; for LOW power microstepping, but it could be programmed here
	; if needed.

	; NOTE!! uses my hi-torque half stepping, not normal half step.

	;  doing half stepping with the 55,25 current values gives;
	; 55+25 = 80
	; max current 100+100 = 200
	; typical (high) current 100+50 = 150
	; so low power is about 1/2 the current of high power mode,
	; giving about 1/4 the motor heating and half the driver heating.

	; for now it uses only half-steps or 8 separate current modes.
	; we only have to use 4 actual current modes as
	; the table is doubled like the table_highpower is.

	; NOTE!! I have left the table full sized so it can be modified
	; to 1200 or 3600 steps if needed.
	;-------------------------------------------------

table_lowpower				;

	movf steptemp,w		; add steptemp to the PCL
	addwf PCL,f			; 
						; here are the 36 possible values;
	;-------------------------
						; A+ B+ (A- B-)

	goto lp00				;
	goto lp00				;
	goto lp00				;
	goto lp00				;
	goto lp00				;	55,25 (100,45) current low (high)
	goto lp00				;
	goto lp00				;
	goto lp00				;
	goto lp00				;

	goto lp09				;
	goto lp09				;
	goto lp09				;
	goto lp09				;
	goto lp09				;	25,55 (45,100)
	goto lp09				;
	goto lp09				;
	goto lp09				;
	goto lp09				;

	;-------------------------
						; A- B+ (A+ B-)

	goto lp18				;
	goto lp18				;
	goto lp18				;
	goto lp18				;
	goto lp18				;	25,55 (45,100)
	goto lp18				;
	goto lp18				;
	goto lp18				;
	goto lp18				;

	goto lp27				;
	goto lp27				;
	goto lp27				;
	goto lp27				;
	goto lp27				;	55,25 (100,45)
	goto lp27				;
	goto lp27				;
	goto lp27				;
	goto lp27				;

	;-------------------------------------------------
	; all tables done, no more tables after this point!
	;-------------------------------------------------
	; next are the 36 code fragments for the high power table.

	; CURRENT INFO.
	; hardware requires that we send the entire 8 bits to the motor
	; at one time, to keep pwm fast.

	; ----xxxx,  where xxxx is the coils on/off phasing (done)
	; xxxx----,  where xxxx is the current settings for the A and B phases;
	; xx------,  where xx is current for A phase
	; --xx----,  where xx is current for B phase

	; hardware currents for 6th stepping have 4 possible values;
	; 00  =  0% current
	; 01  =  25% current
	; 10  =  55% current
	; 11  =  100% current

	;-------------------------------------------------
	; PWM INFO.
	; hardware gives us 6th steps, or 1200 steps/rev.
	; to get 3600 steps/rev we need TWO more
	; "tween" steps between every proper hardware 6th step.

	; to do this we set 2 currents, current1 and current2.
	; then we do FAST pwm, with 2 time units at current2,
	; and 1 time unit at current1.
	; this gives a current which is between the two currents,
	; proportionally closer to current2. (2/3 obviously)
	; this gives the ability to get 2 evenly spaced "tween" currents
	; between our hardware 6th step currents, and go from 1200 to 3600.

	; the next 36 code fragments set the 2 currents desired, then
	; we goto a fast-pwm loop (same loop used for all currents)
	; which modulates between the 2 currents and gives final
	; output current.
	;-------------------------------------------------

st00						; (6th step)
	movf phase,w			; get coil phasing (is 0000xxxx)
	iorlw b'11000000'		; set currents; 100,0 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st01						; (tween step)
	movf phase,w			; get coil phasing
	iorlw b'11000000'		; set 100,0 
	movwf current2			;
	movf phase,w			;
	iorlw b'11010000'		; set 100,25 
	movwf current1			;
	goto pwm				;

st02						; (tween step)
	movf phase,w			; get coil phasing
	iorlw b'11010000'		; set 100,25 
	movwf current2			;
	movf phase,w			;
	iorlw b'11000000'		; set 100,0 
	movwf current1			;
	goto pwm				;

	;-------------------------

st03						; (6th step)
	movf phase,w			;
	iorlw b'11010000'		; set 100,25 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st04						;
	movf phase,w			;
	iorlw b'11010000'		; set 100,25 
	movwf current2			;
	movf phase,w			;
	iorlw b'11100000'		; set 100,55 
	movwf current1			;
	goto pwm				;

st05						;
	movf phase,w			;
	iorlw b'11100000'		; set 100,55 
	movwf current2			;
	movf phase,w			;
	iorlw b'11010000'		; set 100,25 
	movwf current1			;
	goto pwm				;

	;-------------------------

st06						; (6th step)
	movf phase,w			;
	iorlw b'11100000'		; set 100,55 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st07						;
	movf phase,w			;
	iorlw b'11100000'		; set 100,55 
	movwf current2			;
	movf phase,w			;
	iorlw b'11110000'		; set 100,100 
	movwf current1			;
	goto pwm				;

st08						;
	movf phase,w			;
	iorlw b'11110000'		; set 100,100
	movwf current2			;
	movf phase,w			;
	iorlw b'11100000'		; set 100,55 
	movwf current1			;
	goto pwm				;

	;-------------------------

st09						; (6th step)
	movf phase,w			;
	iorlw b'11110000'		; set 100,100 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st10						;
	movf phase,w			;
	iorlw b'11110000'		; set 100,100 
	movwf current2			;
	movf phase,w			;
	iorlw b'10110000'		; set 55,100 
	movwf current1			;
	goto pwm				;

st11						;
	movf phase,w			;
	iorlw b'10110000'		; set 55,100
	movwf current2			;
	movf phase,w			;
	iorlw b'11110000'		; set 100,100 
	movwf current1			;
	goto pwm				;

	;-------------------------

st12						; (6th step)
	movf phase,w			;
	iorlw b'10110000'		; set 55,100 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st13						;
	movf phase,w			;
	iorlw b'10110000'		; set 55,100 
	movwf current2			;
	movf phase,w			;
	iorlw b'01110000'		; set 25,100 
	movwf current1			;
	goto pwm				;

st14						;
	movf phase,w			;
	iorlw b'01110000'		; set 25,100
	movwf current2			;
	movf phase,w			;
	iorlw b'10110000'		; set 55,100 
	movwf current1			;
	goto pwm				;

	;-------------------------
st15						; (6th step)
	movf phase,w			;
	iorlw b'01110000'		; set 25,100 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st16						;
	movf phase,w			;
	iorlw b'01110000'		; set 25,100 
	movwf current2			;
	movf phase,w			;
	iorlw b'00110000'		; set 0,100 
	movwf current1			;
	goto pwm				;

st17						;
	movf phase,w			;
	iorlw b'00110000'		; set 0,100
	movwf current2			;
	movf phase,w			;
	iorlw b'01110000'		; set 25,100 
	movwf current1			;
	goto pwm				;

	;-------------------------
	;-------------------------

st18						; (6th step)
	movf phase,w			;
	iorlw b'00110000'		; set 0,100 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st19						;
	movf phase,w			;
	iorlw b'00110000'		; set 0,100 
	movwf current2			;
	movf phase,w			;
	iorlw b'01110000'		; set 25,100 
	movwf current1			;
	goto pwm				;

st20						;
	movf phase,w			;
	iorlw b'01110000'		; set 25,100
	movwf current2			;
	movf phase,w			;
	iorlw b'00110000'		; set 0,100 
	movwf current1			;
	goto pwm				;

	;-------------------------

st21						; (6th step)
	movf phase,w			;
	iorlw b'01110000'		; set 25,100 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st22						;
	movf phase,w			;
	iorlw b'01110000'		; set 25,100 
	movwf current2			;
	movf phase,w			;
	iorlw b'10110000'		; set 55,100 
	movwf current1			;
	goto pwm				;

st23						;
	movf phase,w			;
	iorlw b'10110000'		; set 55,100
	movwf current2			;
	movf phase,w			;
	iorlw b'01110000'		; set 25,100 
	movwf current1			;
	goto pwm				;

	;-------------------------

st24						; (6th step)
	movf phase,w			;
	iorlw b'10110000'		; set 55,100 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st25						;
	movf phase,w			;
	iorlw b'10110000'		; set 55,100 
	movwf current2			;
	movf phase,w			;
	iorlw b'11110000'		; set 100,100 
	movwf current1			;
	goto pwm				;

st26						;
	movf phase,w			;
	iorlw b'11110000'		; set 100,100
	movwf current2			;
	movf phase,w			;
	iorlw b'10110000'		; set 55,100 
	movwf current1			;
	goto pwm				;

	;-------------------------

st27						; (6th step)
	movf phase,w			;
	iorlw b'11110000'		; set 100,100 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st28						;
	movf phase,w			;
	iorlw b'11110000'		; set 100,100 
	movwf current2			;
	movf phase,w			;
	iorlw b'11100000'		; set 100,55 
	movwf current1			;
	goto pwm				;

st29						;
	movf phase,w			;
	iorlw b'11100000'		; set 100,55
	movwf current2			;
	movf phase,w			;
	iorlw b'11110000'		; set 100,100 
	movwf current1			;
	goto pwm				;

	;-------------------------

st30						; (6th step)
	movf phase,w			;
	iorlw b'11100000'		; set 100,55 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st31						;
	movf phase,w			;
	iorlw b'11100000'		; set 100,55 
	movwf current2			;
	movf phase,w			;
	iorlw b'11010000'		; set 100,25 
	movwf current1			;
	goto pwm				;

st32						;
	movf phase,w			;
	iorlw b'11010000'		; set 100,25
	movwf current2			;
	movf phase,w			;
	iorlw b'11100000'		; set 100,55 
	movwf current1			;
	goto pwm				;

	;-------------------------

st33						; (6th step)
	movf phase,w			;
	iorlw b'11010000'		; set 100,25 
	movwf current2			;
	movwf current1			;
	goto pwm				;

st34						;
	movf phase,w			;
	iorlw b'11010000'		; set 100,25 
	movwf current2			;
	movf phase,w			;
	iorlw b'11000000'		; set 100,0 
	movwf current1			;
	goto pwm				;

st35						;
	movf phase,w			;
	iorlw b'11000000'		; set 100,0
	movwf current2			;
	movf phase,w			;
	iorlw b'11010000'		; set 100,25 
	movwf current1			;
	goto pwm				;
						; high power table done!


	;-------------------------------------------------
	; next are the 4 code fragments for the low power table.
	; (no PWM is used)
	;-------------------------------------------------

lp00						;
	movf phase,w			;
	iorlw b'10010000'		; set 55,25 
	movwf current2			;
	movwf current1			;
	goto pwm				;

lp09						;
	movf phase,w			;
	iorlw b'01100000'		; set 25,55 
	movwf current2			;
	movwf current1			;
	goto pwm				;

lp18						;
	movf phase,w			;
	iorlw b'01100000'		; set 25,55 
	movwf current2			;
	movwf current1			;
	goto pwm				;

lp27						;
	movf phase,w			;
	iorlw b'10010000'		; set 55,25
	movwf current2			;
	movwf current1			;
	goto pwm				;

	;-------------------------------------------------


;------------------------------------------------------------------------------




;******************************************************************************
;  Main 
;******************************************************************************
;
;------------------
main						; goto label
;------------------

	;---------------------------------------------
						; do initial setup for ports and ints and stuff
	call setup			; this is our only proper call...
						; it is called only once, and does not really need
						; to be a function.
	;---------------------------------------------
	; main operating loop is here.
	;---------------------------------------------

	goto move_motor		; will set the motor to step 0,
						; and loop permanently from there

	;---------------------------------------------
	goto main				; safe loop, should never get here anyway.

;==============================================================================




;******************************************************************************
; UPDATE CLOCK     test if it is time to move the clock hand yet!
;******************************************************************************
;
;------------------
update_clock				; goto tag
;------------------

	;-------------------------------------------------
	; we enter here when TMR0 has overflowed (3906 Hz)
	; xtal is 16 MHz, TMR0 is 1:4 prescale so each TMR0
	; "tick" is 1uS (1 million ticks a second)
	; no interrupt is used, instead we poll for TMR0 overflow flag.	
	; 
	; there are 2 systems that can be used to operate the clock;
	; 1. generate 1 second period from the PIC 16MHz xtal
	; 2. generate 1 second period by counting mains freq pulses
	; (which is slected by jumper J2; ON = HI = mains freq)
	;-------------------------------------------------
	; first reset the TMR0 int flag
	bcf INTCON,T0IF		;

	; then test J2 to see which clock method is being used
	btfss PORTA,J2			; J2 HI = mains freq
	goto clock_xtal		;

	;-------------------------------------------------
	;-------------------------------------------------
clock_mains_freq

	; this system generates the 1 second period by simply
	; counting mains cycles; either 60 cycles (60Hz mains)
	; of 50 cycles (for 50Hz mains) =  1 second

	; check if a mains / edge was detected on either input pin
	; first, just check if either pin is hi
	movf PORTA,w			; read all pins on PORTA
	andlw b'00000110'		; keep only RA1 and RA2
	skpz					;
	goto cm_hi			; 

cm_lo
	; both pins are low
	clrf input_edge		; clear test flag
	goto button_test		; nothing more to do

cm_hi
	; one or more pin was high, so test if it was / edge
	btfsc input_edge,0		; test flag for zero
	goto button_test		; flag was already hi, so nothing to do

	; gets here on / edge (of either pin!)
	bsf input_edge,0		; set edge flag bit

	; now test for which pin it was
	btfss PORTA,Hz_60		;
	goto cm_50Hz			;

cm_60Hz
	; count one more mains cycle and see if 1 second reached
	decfsz hz_count,f		;
	goto button_test		; not 1 second, nothing more to do

	; gets here when 1 second reached!
	movlw d'60'			; load Hz counter again
	movwf hz_count			;
	goto reached_1second	;

cm_50Hz
	; count one more mains cycle and see if 1 second reached
	decfsz hz_count,f		;
	goto button_test		; not 1 second, nothing more to do

	; gets here when 1 second reached!
	movlw d'50'			; load Hz counter again
	movwf hz_count			;
	goto reached_1second	;

	;-------------------------------------------------
	;-------------------------------------------------
clock_xtal

	; clock system based on the 16MHz PIC xtal
	; This zero-error 1 second clock routine (see my web page)
	; will count +1 seconds for every 1 million TMR0 ticks.
	;
	; The LiniClock code then turns the stepper motor 1 microstep
	; for every 6 or 25 seconds, (depends on type of stepper motor)
	;-------------------------------------------------
	;-------------------------------------------------
	; zero-error 1 second clock here.

	; This consists of three main steps;
	; * subtract 256 counts from our 24bit variable
	; * test if we reached the setpoint
	; * if so, add 1,000,000 counts to 24bit variable and generate event.
	; (this code was copied from my "one_sec.asm" code)
	;-------------------------------------------------
						; * optimised 24 bit subtract here 
						; This is done with the minimum instructions.
						; We subtract 256 from the 24bit variable
						; by just decrementing the mid byte.

	tstf bres_mid			; first test for mid==0
	skpnz				; nz = no underflow needed
	decf bres_hi,f			; z, so is underflow, so dec the msb

	decfsz bres_mid,f		; dec the mid byte (subtract 256)

						; now the full 24bit optimised subtract is done!
						; this is almost 4 times faster than a "proper"
						; 24bit subtract.

	goto button_test		; nz, so definitely not one second yet.
						; in most cases the entire 'fake" int takes
						; only 9 instructions.
	;------------------------
						; * test if we have reached one second.
						; only gets here when mid==0, it MAY be one second.
						; only gets to here 1 in every 256 times.
						; (this is our best optimised test)
						; it gets here when bres_mid ==0.

	tstf bres_hi			; test hi for zero too
	skpz					; z = both hi and mid are zero, is one second!
	goto button_test		; nz, so not one second yet.

	;-------------------------------------------------
	; Only gets to here if we have reached one second.
						; Add the 1,000,000 ticks first.
						; One second = 1,000,000 = 0F 42 40 (in hex)

						; As we know hi==0 and mid==0 this makes it very fast.
						; This is an optimised 24bit add, because we can
						; just load the top two bytes and only need to do
						; a real add on the bottom byte. This is much quicker
						; than a "proper" 24bit add.

	movlw 0x0F			; get msb value 
	movwf bres_hi			; load in msb

	movlw 0x42			; get mid value
	movwf bres_mid			; load in mid

	movlw 0x40			; lsb value to add
	addwf bres_lo,f		; add it to the remainder already in lsb
	skpnc				; nc = no overflow, so mid is still ok

	incf bres_mid,f		; c, so lsb overflowed, so inc mid
						; this is optimised and relies on mid being known
						; and that mid won't overflow from one inc.

						; that's it! Our optimised 24bit add is done,
						; this is roughly twice as quick as a "proper"
						; 24bit add.
	;-------------------------
reached_1second	
	; Gets here every second. Now we can update the clock!
	; there are 2 speeds to suit the 2 possible motors.
	; dipwitch J1 on RA3 selects motor type; HI = 200step/rev motor

	btfss PORTA,J1			; test dipswitch J1
	goto clock_48			; is 48step/rev motor

	; gets here if a 200step/rev motor
	; need to advance motor 1 microstep every 12 seconds
clock_200

	incf second_count,f		; add a second
	movf second_count,w		; test for roll over >11
	sublw d'11'			; sub to test
	skpwgt				;
	goto pwm				; return, nothing to do yet

	; gets here every 6 seconds!
	clrf second_count		;
	goto make_a_step		; move motor!


	; gets here if a 48step/rev motor
	; need to advance motor 1 microstep every 50 seconds
clock_48

	incf second_count,f		; add a second
	movf second_count,w		; test for roll over >49
	sublw d'49'			; sub to test
	skpwgt				;
	goto pwm				; return, nothing to do yet

	; gets here every 25 seconds!
	clrf second_count		;
	goto make_a_step		; move motor!

make_a_step

	; for now just advance one microstep each second!
	; we are in 18th microstep mode, so step range is 0-71 (72 steps)
	incf step,f			; step++

	
	;movf step,w	; temp!! add a full step to w (is 18 counts)
	;addlw d'18'
	;movwf step



	movf step,w			; test for roll over >71
	sublw d'71'			; sub to test
	skpwgt				;
	goto move_motor		;
	

	clrf step				; wgt, rolled over so force to step 0

	;movlw 0x09			; temp!! rotate to full steps only
	;movwf step;



	goto move_motor		;

	;-------------------------------------------------
button_test

	; we get here roughly once for every TMR0 overflow
	; so we can test the clock set button and if it is set
	; advance the motor forward at a set speed.

	; note!! the dipswitch J1 on RA3 selects whether it is a
	; 48step or 200step motor. HI = 200 step

	btfss PORTA,J1			; test dipswitch J1
	goto button_test_48		; is 48step/rev motor

	;-------------------------
	; the clock set button is RA0; HI = set clock
	; this code below is for 200step/rev motor
button_test_200
	btfss PORTA,0			;
	goto button_low_200		;

button_high_200				; button is pressed!
	incf button_debounce,f	;
	movf button_debounce,w	; test for debounce >40
	sublw d'40'			; sub to test
	skpwgt				;
	goto pwm				; wle, just go back to pwm mode

	; is time to make a clock set step, to advance clock hand
	clrf button_debounce	; 
	goto make_a_step		;

button_low_200				; button is not pressed
	clrf button_debounce	; 
	goto pwm				; so return

	;-------------------------
	; the clock set button is RA0; HI = set clock
	; this code below is for 48step/rev motor
button_test_48
	btfss PORTA,0			;
	goto button_low_48		;

button_high_48				; button is pressed!
	incf button_debounce,f	;
	movf button_debounce,w	; test for debounce >150
	sublw d'150'			; sub to test
	skpwgt				;
	goto pwm				; wle, just go back to pwm mode

	; is time to make a clock set step, to advance clock hand
	clrf button_debounce	; 
	goto make_a_step		;

button_low_48				; button is not pressed
	clrf button_debounce	; 
	goto pwm				; so return


;------------------------------------------------------------------------------




;******************************************************************************
; PWM		is the fast pwm loop
;******************************************************************************
; NOTE!! we enter the code in the middle of the loop!

	;-------------------------------------------------
	; the 2 target currents were set in the move_motor code.

	; what this function does is spend 2 time units at current2,
	; and 1 time unit at current1.
	; actual is 8 clocks at current2
	; and 4 clocks at current 1
	; total 12 cycles, so 333 kHz with 16MHz resonator.

	; this gives an average pwm current of 2/3 the way between
	; current2 and current1.

	; the routine is kept short to keep pwm frequency high, so it
	; is easy to smooth in hardware by the ramping caps.

	; IMPORTANT! is timed by clock cycles, don't change this code!
	; it also checks for any change in input pins here

	; the 8/4 code seen here was supplied by Eric Bohlman (thanks!)
	;-------------------------------------------------
pwm_loop
						; first output current1 to motor
	movf current1,w		; get currents and phase switching
	movwf PORTB			; send to motor!

	nop					; timing delay
	nop					;
						; (4 cycles)
	;-------------------------
pwm						; main entry!
						; better to enter at current2 for motor power.

						; now output current2
	movf current2,w		;
	movwf PORTB			; send to motor!
	nop					; safe wait 250nS

						; now test input pins
	movf PORTA,w			; get pin values from port

	nop					;
	btfss INTCON,T0IF		; see if TMR0 overflowed yet!
	goto pwm_loop			; z, inputs not changed, so keep looping
						; (8 cycles)
	;-------------------------------------------------
						; TMR0 has overlfowed, so check if clock
						; hand needs to move (need to advance a step)
	goto update_clock		; 
	;-------------------------------------------------

;------------------------------------------------------------------------------






;******************************************************************************
;  SETUP   sets port directions and interrupt stuff etc,
;******************************************************************************
; NOTE!! is the only proper funtion, is done before other activity

;------------------
setup					; routine tag
;------------------

	;-------------------------------------------------
	; Note! there are added bits for the 16F628!
	; here we set up peripherals and port directions.
	; this will need to be changed for different PICs.
	;-------------------------------------------------
						; OPTION setup
	movlw b'10000001'		;
		;  x-------		; 7, 0=enable, 1=disable, portb pullups
		;  -x------		; 6, 1=/, int edge select bit
		;  --x-----		; 5, timer0 source, 0=internal clock, 1=ext pin.
		;  ---x----		; 4, timer0 ext edge, 1=\
		;  ----x---		; 3, prescaler assign, 1=wdt, 0=timer0
		;  -----x--		; 2,1,0, timer0 prescaler rate select
		;  ------x-		;   000=2, 001=4, 010=8, 011=16, etc.
		;  -------x		; (using 1:4 for Clock using 167MHz xtal)
						;
	banksel OPTION_REG		; go proper reg bank
	movwf OPTION_REG		; load data into OPTION_REG
	banksel 0				;
	;-------------------------------------------------
	; note! check for 16F628 (and A) and do extra setup for it.

	IFDEF  __16F628
		banksel VRCON		; do bank 1 stuff
		clrf VRCON		; disable Vref
		clrf PIE1			; disable pi etc
		banksel 0			;

		clrf T1CON		; disable timer1
		clrf T2CON		; disable timer2
		clrf CCP1CON		; disable CCP module

		movlw b'00000111'	; disable comparators
		movwf CMCON		;
	ENDIF
	IFDEF  __16F628A
		banksel VRCON		; do bank 1 stuff
		clrf VRCON		; disable Vref
		clrf PIE1			; disable pi etc
		banksel 0			;

		clrf T1CON		; disable timer1
		clrf T2CON		; disable timer2
		clrf CCP1CON		; disable CCP module

		movlw b'00000111'	; disable comparators
		movwf CMCON		;
	ENDIF
	;-------------------------------------------------
						; PORTB pins direction setup
						; 1=input, 0=output
	clrf PORTB			;
						;
	movlw b'00000000'		; all 8 portb are outputs
						;
	banksel TRISB			; go proper reg bank
	movwf TRISB			; send mask to portb
	banksel 0				;
	;-------------------------------------------------

						; PORTA pins direction setup
						; 1=input, 0=output
	clrf PORTA			;

						; NOTE!! all 5 PORTA pins are inputs
	movlw b'00011111'		;
		;  ---x----		; RA4
		;  ----x---		; RA3
		;  -----x--		; RA2
		;  ------x-		; RA1
		;  -------x		; RA0

	banksel TRISA			; go proper reg bank
	movwf TRISA			; send mask to porta
	banksel 0				;
	;-------------------------------------------------

	movlw 0x00			; set up PCLATH for all jump tables on page 0
	movwf PCLATH			; (all tables are in move_motor)
	;-------------------------------------------------

						; CLEAR RAM! for lower bank
	movlw RAM_START		; first byte of ram
	movwf FSR				; load pointer
ram_clear_loop
	clrf INDF				; clear the ram we pointed to
	incf FSR,f			; inc pointer to next ram byte
	movf FSR,w			; get copy of pointer to w
	sublw RAM_END			; test if PAST the last byte now
	skpweq				;
	goto ram_clear_loop		;

	;-------------------------------------------------
						; here we can set the user variables and output pins

	movlw 0x09			; for step 9 of 0-71 (first full step position)
	movwf step			; loaded ready for jump table

	clrf bres_hi			; set up for 1 second clock
	movlw d'1'			;
	movwf bres_mid			;
	clrf second_count		;

	clrf button_debounce	;

	;-------------------------------------------------
						; set up INTCON register last
	movlw b'00000000'		; set the bit value 

		;  x-------		; bit7 	GIE global int enable, 1=enabled
		;  -x------		; bit6	EE write complete enable, 1=en
		;  --x-----		; bit5 	TMR0 overflow int enable, 1=en
		;  ---x----		; bit4 	RB0/INT enable, 1=en
		;  ----x---		; bit3	RB port change int enable, 1=en
		;  -----x--		; bit2	TMR0 int flag bit, 1=did overflow and get int
		;  ------x-		; bit1	RB0/INT flag bit, 1=did get int
		;  -------x		; bit0	RB port int flag bit, 1=did get int

	movwf INTCON			; put in INTCON register
	;-------------------------------------------------
	return				;
;------------------------------------------------------------------------------





;==============================================================================
	; this code is only to display 1k of the memory usage chart
	; in the absolute listing!

	; page 0 256 byte block--------------------
	;org 0x40-2
	;nop
	;org 0x80-1
	;nop
	;org 0xC0-1
	;nop
	;org 0x100-1
	;nop

	; page 1 256 byte block--------------------
	;org 0x140-2
	;nop
	;org 0x180-1
	;nop
	;org 0x1C0-1
	;nop
	;org 0x200-1
	;nop

	; page 2 256 byte block--------------------
	org 0x240-2
	nop
	org 0x280-1
	nop
	org 0x2C0-1
	nop
	org 0x300-1
	nop

	; page 3 256 byte block--------------------
	org 0x340-2
	nop
	org 0x380-1
	nop
	org 0x3C0-1
	nop
	org 0x400-1
	nop


	IFDEF __16F628A
		; page 4 256 byte block--------------------
		org 0x440-2
		nop
		org 0x480-1
		nop
		org 0x4C0-1
		nop
		org 0x500-1
		nop

		; page 5 256 byte block--------------------
		org 0x540-2
		nop
		org 0x580-1
		nop
		org 0x5C0-1
		nop
		org 0x600-1
		nop

		; page 6 256 byte block--------------------
		org 0x640-2
		nop
		org 0x680-1
		nop
		org 0x6C0-1
		nop
		org 0x700-1
		nop

		; page 7 256 byte block--------------------
		org 0x740-2
		nop
		org 0x780-1
		nop
		org 0x7C0-1
		nop
		org 0x800-1
		nop
	ENDIF

	;-------------------------------------------------------------------------
	end
	;-------------------------------------------------------------------------

;==============================================================================
;==============================================================================
;==============================================================================



	;-------------------------------------------------
	; NOTE!! example! below is the original (non-pwm) table for the
	; 24x hardware 6th steps.
	; this will be useful to code a minimum-rom microstepper
	; if you don't need 3600 and can make do with 1200 steps.

	; same system as the main code;
	; ----xxxx	are the phase sequencing
	; xxxx----	are the current values

	; (this code table has been used and tested!)
	;-------------------------------------------------
	; COMMENTED OUT!

		;movlw b'11000101'		; 0,		100,0 	A+ B+	00=0		01=25
		;movlw b'11010101'		; 1,		100,25	A+ B+	10=55	11=100
		;movlw b'11100101'		; 2, 	100,55 	A+ B+
		;movlw b'11110101'		; 3, 	100,100	A+ B+
		;movlw b'10110101'		; 4, 	55,100	A+ B+
		;movlw b'01110101'		; 5, 	25,100	A+ B+
	;-------------------------
		;movlw b'00111001'		; 6, 	0,100	A- B+
		;movlw b'01111001'		; 7, 	25,100	A- B+
		;movlw b'10111001'		; 8, 	55,100	A- B+
		;movlw b'11111001'		; 9, 	100,100	A- B+
		;movlw b'11101001'		; 10, 	100,55	A- B+
		;movlw b'11011001'		; 11, 	100,25	A- B+
	;-------------------------
		;movlw b'11001010'		; 12, 	100,0	A- B-
		;movlw b'11011010'		; 13, 	100,25	A- B-
		;movlw b'11101010'		; 14, 	100,55	A- B-
		;movlw b'11111010'		; 15, 	100,100	A- B-
		;movlw b'10111010'		; 16, 	55,100	A- B-
		;movlw b'01111010'		; 17, 	25,100	A- B-
	;-------------------------
		;movlw b'00110110'		; 18, 	0,100	A+ B-
		;movlw b'01110110'		; 19, 	25,100	A+ B-
		;movlw b'10110110'		; 20, 	55,100	A+ B-
		;movlw b'11110110'		; 21, 	100,100	A+ B-
		;movlw b'11100110'		; 22, 	100,55	A+ B-
		;movlw b'11010110'		; 23, 	100,25	A+ B-



	EXAMPLE! full table example here, 0-71 steps showing every step...

	;-------------------------
	0	100,0 	A+ B+
	1	 100,8   (pwm tween)
	2	 100,17  (pwm tween)
	3	100,25	A+ B+
	4	 100,35  (pwm tween)
	5	 100,45  (pwm tween)
	6	100,55 	A+ B+
	7	 100,70  (pwm tween)	
	8	 100,85  (pwm tween)
	9	100,100	A+ B+	(rest of table is same, tweens not shown)
	10
	11
	12	55,100	A+ B+
	13
	14
	15	25,100	A+ B+
	16
	17
	;-------------------------
	18	0,100	A- B+
	19
	20
	21	25,100	A- B+
	22
	23
	24	55,100	A- B+
	25
	26
	27	100,100	A- B+
	28
	29
	30	100,55	A- B+
	31
	32
	33	100,25	A- B+
	34
	35
	;-------------------------
	36	100,0	A- B-
	37
	38
	39	100,25	A- B-
	40
	41
	42	100,55	A- B-
	43
	44
	45	100,100	A- B-
	46
	47
	48	55,100	A- B-
	49
	50
	51	25,100	A- B-
	52
	53
	;-------------------------
	54	0,100	A+ B-
	55
	56
	57	25,100	A+ B-
	58
	59
	60	55,100	A+ B-
	61
	62
	63	100,100	A+ B-
	64
	65
	66	100,55	A+ B-
	67
	68
	69	100,25	A+ B-
	70
	71
	;-------------------------------------------------
	




file: /Techref/io/stepper/linistep/LiniClock/LiniClock_12hour.asm, 40KB, , updated: 2010/9/30 08:46, local time: 2024/11/15 23:24,
TOP NEW HELP FIND: 
3.135.187.231:LOG IN

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://linistepper.com/techref/io/stepper/linistep/LiniClock/LiniClock_12hour.asm"> io stepper linistep LiniClock LiniClock_12hour</A>

Did you find what you needed?