![]() | ![]() | |||
| TAMS / Java / Hades / applets: contents | previous | next | ||||
| Hades Applets contents visual index introduction std_logic_1164 gatelevel circuits delay models flipflops adders and arithm... counters LFSR and selftest memories programmable logic state-machine editor misc. demos I/O and displays DCF-77 clock relays (switch-le... CMOS circuits (sw... RTLIB logic RTLIB registers Prima processor D*CORE MicroJava Pic16 cosimulation PIC16C84 dem... fast PIC16C8... interrupt-dr... on-chip timer EEPROM access EEPROM access RS-232 trans... software RS-232 software RS-... chronograph MIDI footswi... MIDI footswi... MIDI footswi... MIDI organ p... MIDI organ p... ultrasonic r... ultrasonic r... "Phrasendres... "mastermind"... Mips R3000 cosimu... Intel MCS4 (i4004) image processing ... [Sch04] Codeumsetzer [Sch04] Addierer [Sch04] Flipflops [Sch04] Schaltwerke [Sch04] RALU, Min... [Fer05] State-Mac... [Fer05] PIC16F84/... [Fer05] Miscellan... [Fer05] Femtojava FreeTTS | Chronograph/stopwatch controller
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 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:
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 |