Hades logoHades applet banner
Chronograph/stopwatch controller

applet icon

The image above shows a thumbnail of the interactive Java applet embedded into this page. Unfortunately, your browser is not Java-aware or Java is disabled in the browser preferences. To start the applet, please enable Java and reload this page. (You might have to restart the browser.)

Circuit Description

This applet demonstrates a PIC16-based controller for a quartz chronograph (like the Swatch I used for years, before the plastic casing broke). Press the input switches to control the stopwatch interactively; open the PIC user-interface to watch the program execution, setting breakpoints, etc. (I recommend to uncheck the 'update display' checkbox and to click the data and program memories to enforce repainting. This saves a lot of CPU cycles and makes the animation of the clock go smoothly).

Like many quartz-controlled chronographs, the Swatch has one main dial and three smaller dials:

  • the three arms on the main dial show minutes, hours, and stopwatch seconds,
  • the upper left small dial shows stopwatch minutes,
  • the upper right small dial shows the stopwatch tenths of seconds,
  • the lower centered small dial shows the time seconds.
In the simulation model, the main clock arms are shown in blue color, while green color is used for the stopwatch.

The main clockwork is standard and uses a single motor that drives the seconds arm, with the minutes and hours connected by gears with the standard 1:60 and 1:12 ratios. Setting the time is achieved mechanically via rotating the crown (this is not implemented in the simulation model, and the main clock will start at 12:00:00 every time you (re)start the simulation.)

The stopwatch is controlled by two switches:

  • the upper switch starts and stops the stopwatch,
  • the lower switch fulfils three different functions. First, click the switch while the stopwatch is running to take an intermediate time,
  • second, click the switch again, and the stopwatch dials return to showing the live current stopwatch time (advancing each tenth of a second),
  • third, click the switch when the stopwatch is stopped to reset the stopwatch.

Three different motors are used for the stopwatch. This can be seen on the 'real' clock when resetting the stopwatch or during resuming from an intermediate timing, because then all three stopwatch arms move simultaneusly and independently from each other. As explained above, one additional motor is used for the main clock (hours, minutes, seconds). Obviously, our software program must read the two input switches and control the four drive motors. For simplicity, we assume that stepping motors are used, where a single 0-1-0 transition advances the corresponding gear by one step. We also assume that the initial state of the motors is known, so that no additional position encoders or switches are required.

The following assembly code is used for the watch:

; TITLE           "Swatch chronograph controller"
; SUBTITLE        "FNH 24.10.2005"
; Processor       16F84
; Radix           DEC
; EXPAND
; include         "p16c84.inc"


; This program implements a controller for a quartz-controlled stopwatch
; like my old 'Swatch Chrono' (from around 1997) based on the PIC16F84.
; The program is intended as a medium complexity (and nicely animated)
; demonstration application for cosimulation in the Hades simulation 
; framework. It also shows how to use the PIC timers and interrupt handling.
; 
; For details about Hades visit our applet collection at 
; http://tams.informatik.uni-hamburg.de/applets/hades/webdemos/toc.html
; (the demo is in the 72-pic/60-swatch subdirectory).
;
; The clock is assumed to contain four separate dials:
; 1. main dial with three arms: hours, minutes, stopwatch seconds
; 2. upper-left small dial:     stopwatch minutes
; 3. upper-right small dial:    stopwatch tenths of seconds
; 4. lower-centered small dial: stopwatch seconds
; The simulation model of the clock uses blue color for the main clock,
; and green for the stopwatch.
;
; We also assume that the clock uses four separate stepper-type motors;
; one to drive the seconds of the main clock (with mechanical gears to
; drive minutes and hours), and three motors to drive the three dials
; of the stopwatch. A single 0-1-0 pulse on the inputs of the clock
; simulation model steps the corresponding clock are by one position.
;
; The program uses four main states:
; a) stopwatch stopped
; b) stopwatch running and displaying (no intermediate time taken)
; c) stopwatch running, intermediate time taken, displaying intermediate time
; d) stopwatch stopped, but displaying intermediate time
;
; The on-chip timer and prescaler are programmed to result in periodic
; timer interrupts at a rate of 1/80th of a second. After the one-time
; program initialization, all calculations are performed from within
; the timer interrupt handler. 
;
; The algorithm used in this program assumes that we can drive the 
; stepping motors with a maximum frequency of about 100 Hz; also, we want
; to drive at most one motor at a time to reduce maximum currents. 
; As a result of those restrictions, we cannot easily use wait loops 
; to generate the motor pulses without either overrunning the motors
; or risking to lose interrupts.
;
; Instead, we divide the basic 1/10 second cycle of the stopwatch into
; 8 subcycles and distribute the updating of the stopwatch states and
; motor positions over the eight subcycles as follows:
;
; t              0.0                 0.1                 0.2     seconds
; cycle        [ 0               ] [ 1               ] [ 2 
; subcycle     [ 0 1 2 3 4 5 6 7 ] [ 0 1 2 3 4 5 6 7 ] [ 0 1 2 ...
;
; clock update [ C               ] [ C               ] [ C
; main motor   [ M               ] [                 ] [  
;
; state update [   u             ] [   u             ] [   u
; tenth motor  [     t      t    ] [     t     t     ] [     t  
; secs motor   [      s      s   ] [       s     s   ] [       s
; mins motor   [        m      m ] [         m     m ] [         m
;
; This timing strategy ensures that at most one motor is driven at a time,
; and that the motors are driven with a frequency of 20 Hz at most. It also
; means that a state update can take up to 59steps/20Hz or 3 seconds
; - slighly slower that my Swatch, which manages this in a little over one
; second. On the other hand, this makes it easier to see the animation in
; the Hades editor, which is usually limited to about 10..20 repaints per
; seconds (unless you have a very fast computer).
;
; Given the fixed prescaler ratios of (1:2, ... 1:64, 1:128, 1:256),
; we choose a prescaler value of 1:4 and let the on-chip timer count
; continuously (0..255). This leads to an instruction cycle time of
; 1/(80*256*4) seconds = 1/81920 seconds, or an instruction cycle length
; of 1.220703125E-5 seconds.
; Note that the actual input clock frequency is 327.680 KHz, as the PIC
; needs four clock cycles per instruction.
;
; Between interrupts, the processor should wait in the sleep state 
; to save power, but this doesn't work on the PIC16F84 (because the 
; on-chip timer is stopped in sleep-mode).
; A real-world design could use an external toggle-flipflop based
; asynchronous counter, and trigger an PIC portB wakeup interrupt
; when the external counter overflows.
;
; Revision history:
;
; 24.10.05 - subcycle-based version
; 22.10.05 - first timer-interrupt based version
; 21.10.05 - first working state-machine
; 20.10.05 - new program
;
; (C) 2005, F.N.H., hendrich@informatik.uni-hamburg.de
;

_ResetVector	equ	0x00
_IntVector	equ	0x04


;
; memory locations: states, time, stopwatch time, stopwatch intermediate time,
;                   current motor positions
;
SUBCYCLE	equ	0x0f

STATE		equ	0x10
KEYS		equ	0x11
OLDKEYS		equ	0x12

DAYS		equ	0x13
HOURS		equ	0x14
MINS		equ	0x15
SECS		equ	0x16
CENTS		equ	0x17

STOP_MINS	equ	0x18
STOP_SECS	equ	0x19
STOP_TENTHS	equ	0x1a

INTER_MINS	equ	0x1d
INTER_SECS	equ	0x1e
INTER_TENTHS	equ	0x1f


;
; state-machine stuff. We use a one-hot encoding allow fast testing
; for states via the btfsc instruction:
;
STOPPED			equ 0x01
RUNNING			equ 0x02
RUNNING_INTERMEDIATE	equ 0x04
STOPPED_INTERMEDIATE	equ 0x08

MASK_STOPPED		equ 0
MASK_RUNNING		equ 1
MASK_RUNNING_INTERM	equ 2
MASK_STOPPED_INTERM	equ 3

;
; the current actual and target positions of the motors
;
MOTOR_MINS	equ	0x20
MOTOR_SECS	equ	0x21
MOTOR_TENTHS	equ	0x22

TARGET_MINS	equ	0x25
TARGET_SECS	equ	0x26
TARGET_TENTHS	equ	0x27

;
; pin assignments on port A
;
PIN_START_STOP	equ	0
PIN_RESET_PAUSE	equ	1

;
; pin assignments on port B
;
PIN_MAIN_MOTOR  equ	7
PIN_MINS_MOTOR  equ	6
PIN_SECS_MOTOR  equ	5
PIN_TENTHS_MOTOR equ	4



; ***************************************************************************
; ***************************************************************************
; ***************************************************************************
;
; code starts here: this does not return
;
	ORG	_ResetVector	
	goto	Start


;
; main interrupt vector
;
	ORG	_IntVector
	goto	InterruptHandler

;
; main initialization routine
;
Start:
	movlw	0x00
	movwf	INTCON			; disable all interrupts
	movwf	SUBCYCLE		; reset subcycle counter

	call	ResetTime
	call	ResetStopwatchTime
	call	ResetIntermediateTime
	call	ResetMotorValues
	call	ResetTargetValues
	call	InitStateMachine
	call	InitPorts
	call	InitTimerAndInterrupts

DemoLoop:
	nop
	clrwdt
	; sleep
	goto	DemoLoop	




;
; endless loop to catch errors
;
Error:
	goto Error



;
; reset the main clock to dd/hh:mm:ss.ccc 00/00:00:00.000
;
ResetTime:	
	movlw	0x00
	movwf	DAYS			; init main clock variables
	movwf	HOURS			;
	movwf	SECS			;
	movwf	CENTS			;
	return


;
; reset the stop-watch clock to mm:ss.t 00:00.0
;
ResetStopwatchTime:
	movlw	0x00
	movwf	STOP_MINS		; init stopwatch to 0:00:00
	movwf	STOP_SECS		;
	movwf	STOP_TENTHS		;
	return


;
; reset the stop-watch intermediate time to mm:ss:t 00:00.0
;
ResetIntermediateTime:
	movlw	0x00
	movwf	INTER_MINS		; init intermediate time
	movwf	INTER_SECS		;
	movwf	INTER_TENTHS		;
	return


;
; reset the actual motor positions to mm:ss:t 00:00.0
;
ResetMotorValues:
	movlw	0x00
	movwf	MOTOR_MINS		; init (actual) motor positions
	movwf	MOTOR_SECS
	movwf	MOTOR_TENTHS
	return


;
; reset the target motor positions to mm:ss:t 00:00.0
;	
ResetTargetValues:
	movlw	0x00
	movwf	TARGET_MINS		; init target motor positions
	movwf	TARGET_SECS
	movwf	TARGET_TENTHS
	return

;
; initialize the state-machine stuff including keyboard debouncing
;
InitStateMachine:
	movlw	STOPPED
	movwf	STATE
	movlw 	0x00
	movwf	KEYS
	movwf	OLDKEYS
	return


;
; initialize port PA0 and PA1 as inputs, PB7..PB4 as outputs
;
InitPorts:
	bsf	STATUS, RP0		; access port direction regs (1=input)
	movlw	0x1F			; all five bits are inputs
	movwf	TRISA			; on port A

	; movlw	0x0F			; upper four bits are outputs 
	movlw	0x00			; all eight bits are outputs
	movwf	TRISB			; on port B

	bcf	STATUS, RP0		; access data regs
	movlw	0x00			; 
	movwf 	PORTB			; motor controls driven low (inactive)
	return


;
; initialize the timer and prescaler, then enable timer interrupts
;
InitTimerAndInterrupts:
        bsf     STATUS, RP0     ; bank 1
        ; movlw   B'10000101'     ; rtcc inc = tcylc/64 = tclk/(4*64)
        movlw   B'10000001'     ; rtcc inc = tcylc/2 = tclk/(4*2)
        movwf   OPTION_REG      ;  
        bcf     STATUS, RP0     ; bank 0

        clrf    TMR0            ; reset timer (and prescaler!)
        movlw   B'10100000'     ; enable timer interrupt and GIE
        movwf   INTCON          ;  
	return;


;
; read the two input switches and debounce the input values.
; The result is a bit-mask in the KEYS register:
; 0x00 - no keypress
; 0x01 - keypress of the start-stop switch
; 0x01 - keypress of the reset-pause switch
; If both switches are pressed, only a reset-pause is reported
;
ReadSwitches:
	movf	KEYS,0			; save keypress state from previous 
	movwf	OLDKEYS			; iteration to OLDKEYS

	movf	PORTA,0			; read port A 
	andlw	0x03			; mask lower two bits (the switches)
	movwf	KEYS			; and save to KEYS

	btfsc	KEYS,PIN_START_STOP	; start-stop pressed right now?
	goto	StartStopPressed	;

	btfsc	KEYS,PIN_RESET_PAUSE	; reset-pause pressed right now?
	goto	ResetPausePressed	
	return


;
; handle a keypress on the start-stop switch:
; 1) If the key was already pressed during the previous iteration, 
;    we return immediately.
; 2) In STOPPED, we start the stopwatch and change to RUNNING
; 3) In RUNNING or PAUSED or INTERMEDIATE we change to STOPPED
;
StartStopPressed:			; start-stop pressed right now;
	btfsc	OLDKEYS,PIN_START_STOP	; but also on previous iteration?
	return				; yes, ignore.

	; bsf	PORTB,PIN_SECS_MOTOR	; for debugging the debounce logic
	; bcf	PORTB,PIN_SECS_MOTOR
	; return

	btfsc	STATE,MASK_STOPPED	; state==STOPPED?
	goto	_SSP_Running		; yes, start the stopwatch

	btfsc	STATE,MASK_RUNNING	; state==RUNNING?
	goto	_SSP_Stopped

	btfsc	STATE,MASK_RUNNING_INTERM; state==RUNNING_INTERMEDIATE?
	goto	_SSP_Stopped_Intermediate

	goto 	_SSP_Running_Intermediate




_SSP_Running:				; start the stopwatch
	movlw	RUNNING			; next state is RUNNING
	movwf	STATE
	call	CopyStopwatchTimeToTargetTime
	; call	MoveMotorsToTargetPositions
	return

_SSP_Stopped:				; stop the stopwatch
	movlw	STOPPED			; next state is STOPPED
	movwf	STATE
	call	CopyStopwatchTimeToTargetTime
	; call	MoveMotorsToTargetPositions
	return

_SSP_Stopped_Intermediate:		; from running_intermediate to stopped,
	movlw	STOPPED_INTERMEDIATE	; but keep showing intermediate time
	movwf	STATE
	call	CopyIntermediateTimeToTargetTime
	; call	MoveMotorsToTargetPositions
	return

_SSP_Running_Intermediate:		; from stopped_intermediate:
	movlw	RUNNING_INTERMEDIATE	; running again, but still showing the
	movwf	STATE			; intermediate time.
	call	CopyIntermediateTimeToTargetTime
	; call	MoveMotorsToTargetPositions
	return
	


;
; handle a keypress of the reset-pause switch (aka 'intermediate time' switch).
;	
ResetPausePressed:
	btfsc	OLDKEYS,PIN_RESET_PAUSE	; debouncing: if pressed on previous
	return				; iteration return immediately

	; bsf	PORTB,PIN_MINS_MOTOR	; for debugging
	; bcf	PORTB,PIN_MINS_MOTOR
	; return

	btfsc	STATE,MASK_STOPPED	; state==STOPPED?
	goto	_RPP_Reset		; yes, reset the stopwatch

	btfsc	STATE,MASK_RUNNING	; state==RUNNING?
	goto	_RPP_TakeIntermediateTime

	btfsc	STATE,MASK_RUNNING_INTERM; state==RUNNING_INTERMEDIATE?
	goto	_RPP_ResumeRunning

	goto 	_RPP_Stop		; state == STOPPED_INTERMEDIATE


_RPP_Reset:				; we're already stopped, now reset
	call	ResetStopwatchTime	; the stopwatch time.
	call	CopyStopwatchTimeToTargetTime
	; call	MoveMotorsToTargetPositions
	return

_RPP_TakeIntermediateTime:		; we're running, now take an
	movlw	RUNNING_INTERMEDIATE	; intermediate time and display it
	movwf	STATE
	call	TakeIntermediateTime
	call	CopyIntermediateTimeToTargetTime
	; call	MoveMotorsToTargetPositions
	return

_RPP_ResumeRunning:			; resume showing the stopwatch time
	movlw	RUNNING
	movwf 	STATE
	call	CopyStopwatchTimeToTargetTime
	; call	MoveMotorsToTargetPositions
	return

_RPP_Stop:				; move to stopped state
	movlw 	STOPPED
	movwf	STATE
	call	CopyStopwatchTimeToTargetTime
	; call	MoveMotorsToTargetPositions
	return





;
; increment the current (main) clock, and generate a motor-pulse every second
; 
IncrementTime:

	movf	CENTS,0			; increment cents value by 10
	addlw	10			; (use 1 for real 1/100s of seconds)
	movwf	CENTS			;

	sublw	100			; (cents==100)?
	btfss	STATUS,Z		; 
	return				; no. 

_IncrSecs:				; yes, need to increment seconds
	movlw	0x00			; 
	movwf	CENTS			; reset cents value

	incf	SECS,1			; increments seconds
	movf	SECS,0			;
	sublw	60			; (secs==60)?
	btfss	STATUS,Z		; 	
	return				; no.

_IncrMins:				; yes, need to increment minutes
	movlw	0x00			; 
	movwf	SECS			; reset seconds

	incf	MINS,1			; increment minutes
	movf	MINS,0			;
	sublw	60			; (mins==60)?
	btfss	STATUS,Z		;
	return				; no.

_IncrHours:				; yes, need to increment hours
	movlw	0x00			; 
	movwf	MINS			; reset minutes

	incf	HOURS,1			; increment minutes
	movf	HOURS,0			;
	sublw	24			; (hours==24)?
	btfss	STATUS,Z		;
	return				; no.

_IncrDays:				; yes, need to increment days
	movlw	0x00			;
	movwf	HOURS			; reset hours

	incf	DAYS,1			; increment days
	movf	DAYS,0			;
	sublw	32			; (days==32)?  FIXME: respect days/month
	btfss	STATUS,Z		;
	return

	movlw	0x00			; reset days
	movwf	DAYS
	return




;
; increment stopwatch time mm:ss.t (by one tenth second)
;
IncrementStopwatch:
	incf	STOP_TENTHS,1		; increment stopwatch tenths of secs
	movf	STOP_TENTHS,0		
	sublw	10			; (stop_tenths==10)?
	btfss	STATUS,Z		; 
	return				; no. 

_IncrStopSecs:				; yes, increment stopwatch secs
	movlw	0x00			; 
	movwf	STOP_TENTHS		; 

	incf	STOP_SECS,1		; 
	movf	STOP_SECS,0		;
	sublw	60			; (stop_secs==60)?
	btfss	STATUS,Z		; 	
	return				; no.

_IncrStopMins:				; yes, increment stopwatch mins
	movlw	0x00			; 
	movwf	STOP_SECS		; reset seconds

	incf	STOP_MINS,1		; increment minutes
	movf	STOP_MINS,0		;
	sublw	60			; (stop_mins==60)?
	btfss	STATUS,Z		;
	return				; no.

_ResetStopMins:
	movlw	0x00			; 
	movwf	STOP_MINS		;
	return


;
; check the current stopwatch state. If STOPPED, do nothing,
; otherwise increment the stopwatch time (by one tenth of a second).
;
CheckIncrementStopwatch:
	btfsc	STATE,MASK_STOPPED	; state==STOPPED?
	return				; yes: do nothing
	call 	IncrementStopwatch	; no: increment the stopwatch time
	return



;
; take intermediate time (from current stopwatch time)
;
TakeIntermediateTime:
	movf	STOP_TENTHS,0
	movwf	INTER_TENTHS
	movf	STOP_SECS,0
	movwf	INTER_SECS
	movf	STOP_MINS,0
	movwf	INTER_MINS
	return


;
; copy stopwatch time to motor-target-time register
;
CopyStopwatchTimeToTargetTime:
	movf	STOP_TENTHS,0
	movwf	TARGET_TENTHS
	movf	STOP_SECS,0
	movwf	TARGET_SECS
	movf	STOP_MINS,0
	movwf	TARGET_MINS
	return



;
; copy intermediate time to motor-target-time register
;
CopyIntermediateTimeToTargetTime:
	movf	INTER_TENTHS,0
	movwf	TARGET_TENTHS
	movf	INTER_SECS,0
	movwf	TARGET_SECS
	movf	INTER_MINS,0
	movwf	TARGET_MINS
	return



;
; check current state to decide whether to show the current stopwatch time
; or the intermediate time on the small dials.
;
CheckSetTargetPositions:
	btfsc	STATE,MASK_RUNNING_INTERM
	goto	CopyIntermediateTimeToTargetTime
	btfsc	STATE,MASK_STOPPED_INTERM
	goto	CopyIntermediateTimeToTargetTime
	goto	CopyStopwatchTimeToTargetTime
	







;
; generate a pulse for the main clock motor (once every second).
; We insert a few nop instructions to ensure a minimum pulse-length.
;
MainMotorPulse:
	bsf	PORTB,PIN_MAIN_MOTOR
	nop
	nop
	nop
	bcf	PORTB,PIN_MAIN_MOTOR
	return


;
; handle subcycle zero (where a cycle consists of eight subcycles of 1/80 secs).
; The algorithm used by this program reserves subcycle zero to increment
; the main clock time; given the timer interrupt rate of 1/80 seconds,
; this method is called every 0.1 seconds, and we have to generate 
; one main motor step every ten calls.
;
HandleSubcycle0:
	call	IncrementTime		; time += 0.1 secs

	movf	CENTS,0			; if cents==0
	subwf	0			;
	btfsc	STATUS,Z		; generate one motor pulse
	call	MainMotorPulse		;
	return


;
; handle subcycle one (where a cycle consists of eight subcycles of 1/80 secs).
; The algorithm used by this program reserves subcycle one to increment the
; stopwatch time (if running), to check the input switches, and to handle
; the corresponding stopwatch state changes.
; No motor pulses are generated in subcycle one; any motor updates are
; deferred to subcycles 2..7.
;
HandleSubcycle1:
	call	CheckIncrementStopwatch
	call	ReadSwitches
	call	CheckSetTargetPositions	
	return


;
; generate one-step for the stopwatch tenths-of-seconds-motor when necessary
;
UpdateTenthsMotor:
	movf	TARGET_TENTHS,0		; W = target_tenths
	subwf	MOTOR_TENTHS,0		; W = (motor_tenths - target_tenths)
	btfsc	STATUS,Z		; zero difference?
	return				; yes: return

	bsf	PORTB,PIN_TENTHS_MOTOR 	; one motor step
	nop
	nop
	nop
	bcf	PORTB,PIN_TENTHS_MOTOR

	incf	MOTOR_TENTHS,1		; update motor position
	movf	MOTOR_TENTHS,0		; check for overflow
	sublw	10			;
	btfsc	STATUS,Z		; if (motor_tenths==10):
	clrf	MOTOR_TENTHS
	return


;
; generate one-step for the stopwatch seconds-motor when necessary
;
UpdateSecsMotor:
	movf	TARGET_SECS,0		; W = target_secs
	subwf	MOTOR_SECS,0		; W = (motor_secs - target_secs)
	btfsc	STATUS,Z		; zero difference?
	return				; yes: return

	bsf	PORTB,PIN_SECS_MOTOR 	; one motor step
	nop
	nop
	nop
	bcf	PORTB,PIN_SECS_MOTOR
	incf	MOTOR_SECS,1		; update motor position
	movf	MOTOR_SECS,0		; check for overflow
	sublw	60			;
	btfsc	STATUS,Z		; if (motor_secs==60):
	clrf	MOTOR_SECS		; then motor_secs=0
	return


;
; generate one-step for the stopwatch minutes-motor when necessary
;
UpdateMinsMotor:
	movf	TARGET_MINS,0		; W = target_mins
	subwf	MOTOR_MINS,0		; W = (motor_mins - target_mins)
	btfsc	STATUS,Z		; zero difference?
	return				; yes: return

	bsf	PORTB,PIN_MINS_MOTOR 	; one motor step
	nop
	nop
	nop
	bcf	PORTB,PIN_MINS_MOTOR

	incf	MOTOR_MINS,1		; update motor position
	movf	MOTOR_MINS,0		; check for overflow
	sublw	60			;
	btfsc	STATUS,Z		; if (motor_mins==60):
	clrf	MOTOR_MINS
	return



;
; main interrupt handler starts here.
;
; We first increment the subcycle counter variable (0..7) and then
; dispatch to the action corresponding to the subcycles.
; The extra bsf/bcf instructions are inserted for debugging; just
; add a signal probe to PORT B.3 and use the waveform viewer to
; watch the time spent inside the interrupt handler.
;
InterruptHandler:	
	clrf	INTCON			; clear all interrupts

	bsf	PORTB,3			; for debugging and cycle counting

	incf	SUBCYCLE		; increment subcycle
	movlw	b'00000111'		; lower 3 bits mask	
	andwf	SUBCYCLE,1		; subcycle AND 00000111

	movf	SUBCYCLE,0		; subcycle==0?
	sublw	0x0			;
	btfsc	STATUS,Z		;
	call	HandleSubcycle0		; yes, increment main clock

	movf	SUBCYCLE,0		; subcycle==1?
	sublw	0x1			;
	btfsc	STATUS,Z		;
	call	HandleSubcycle1		; yes, update stopwatch 

	movf	SUBCYCLE,0		; subcycle==2?
	sublw	0x2			;
	btfsc	STATUS,Z		;
	call	UpdateTenthsMotor	; yes, tenths-of-seconds motor update
	
	movf	SUBCYCLE,0		; subcycle==3?
	sublw	0x3			;
	btfsc	STATUS,Z		;
	call	UpdateSecsMotor		; yes, seconds motor update
	
	movf	SUBCYCLE,0		; subcycle==4?
	sublw	0x4			;
	btfsc	STATUS,Z		;
	call	UpdateMinsMotor		; yes, minutes motor update
	
	movf	SUBCYCLE,0		; subcycle==5?
	sublw	0x5			;
	btfsc	STATUS,Z		;
	call	UpdateTenthsMotor	; yes, tenths-of-seconds motor update
	
	movf	SUBCYCLE,0		; subcycle==6?
	sublw	0x6			;
	btfsc	STATUS,Z		;
	call	UpdateSecsMotor		; yes, seconds motor update
	
	movf	SUBCYCLE,0		; subcycle==7?
	sublw	0x7			;
	btfsc	STATUS,Z		;
	call	UpdateMinsMotor		; yes, minutes motor update

	bcf	PORTB,3			; for debugging on B.3

	bsf	INTCON,T0IE		; enable timer interrupt RTIE again
	retfie				; return (and enable GIE again)



	END

Print version | Run this demo in the Hades editor (via Java WebStart)
Usage | FAQ | About | License | Feedback | Tutorial (PDF) | Referenzkarte (PDF, in German)
Impressum http://tams.informatik.uni-hamburg.de/applets/hades/webdemos/72-pic/60-swatch/swatch.html