Knowledge Base

The program code is reproduced below. You should master the Multitasking tutorial before attempting to understand this code!

;mdrv2.spt   Example motor drive program using SPice10213
;This program is written for an MMi99/200 with LCD, but can easily
;be ported to an MS12

;The program uses front panel push button inputs as follows:

; Input Function
; 12 + speed
; 11 - speed
; 10 Stop/Start
; 9 Forward/Reverse
; 8 Not used

;The program consists of 3 tasks:

;SPD (Speed) Simply monitors the + and - buttons and generates a target speed value
;DRV (Drive) Ramps the motor speed (PWM) towards the target speed
;MSQ (Motor sequencer) Master sequencer for stop/start, forward/reverse. Uses DRV
; for actual PWM generation.

;The 3 tasks are written as independent tasks witin a multitasking structure.
;You need to understand the material in the multitasking tutorial to make sense of this

;=============== Constants ====================
SPD_Increment EQU 10 ;Inc/Dec speed by this amount for each button push
StopTime EQU 10 ; x 10mS. Time allowed for motor to stop with dynamic braking

;============== I/O allocations ==============
;Alter for MS12
;----------- Inputs ----------------
iSPeedUp iEQU 12
iSpeedDn iEQU 11
iStopStart iEQU 10
iFwdRev iEQU 9

;----------- Outputs ---------------
oDirection oEQU 16

;========= RAM ==============
;-------- Semaphores (1-bit variables) in 1st 8 bytes ---------------
Direction sEQU 0
DRV_Accelerate sEQU 1
Tick10 sEQU 2
MSQ_DirFWD sEQU 3
MSQ_RevFlag sEQU 4

;-------- Other RAM ------------
MSQ_Addr mEQU 20 ;2 bytes. Suspend address for MSQ
SPD_Target mEQU 22 ;Target PWM
DRV_Addr mEQU 23 ;2 bytes. Suspend address for DRV
DRV_PWM mEQU 25 ;Current PWM value
SPD_Count mEQU 26
MSQ_Count mEQU 27
MSQ_State mEQU 28

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

Start:
setu 0,1 ;set spice connector pin 4 as DO
setu 3,1 ;set spice connector pin 7 as DO
setu 4,4 ;set spice connector pin 8 as PWM output
setu 5,4 ;set spice connector pin 9 as PWM output
SpiceConfigU

GoSub SPD_Init ;Initialize tasks
GoSub DRV_Init
GoSub MSQ_Init

MainLoop:
GetTick10 ;Generate 10mS heartbeat
StoreS Tick10
GoSub SPD_UpDate ;Run task
GoSub DRV_UpDate ;Run task
GoSub MSQ_UpDate ;Run task

;Debug: Display the MSQ state number
OBLCD_SetCur 1,13
OBLCD_UDecDispMFW MSQ_State

GoTo MainLoop

;====================================================================
;----------- Motor sequencer ---------------------

;Short name MSQ

;Entry points
; MSQ_Init Initialize
; MSQ_Update Update


MSQ_UpDate:
Resume MSQ_Addr

MSQ_Init:

;State 0 is the idle state.
MSQ_Set0:
SetMem MSQ_State,0 ;For debugging monitor
MSQ_0:
Suspend MSQ_Addr
GoIfInK iStopStart,MSQ_Set1 ;Test stop/start button
GoSub MSQ_ReadFR ;Test and process F/R
GoTo MSQ_0

;In state 1 we set the relay for the correct direction, then wait for it to settle
;prior to starting up the PWM drive
MSQ_Set1:
SetMem MSQ_State,1 ;For debugging monitor
RecallS MSQ_RevFlag ;Set direction relay ...
Output oDirection ;... according to direction flag

;Here we mark off two timer ticks to ensure at least a 10mS pause while the relay settles.
MSQ_1:
Suspend MSQ_Addr
GoIfSF Tick10,GenRet ;Sync to timer tick
Suspend MSQ_Addr
GoIfInK iStopStart,MSQ_Set0 ;Test stop/start button
GoIfSF Tick10,GenRet ;Wait for next tick

;State 2 is the run state. the DRV task may well be accelerating, but that does
;not concern us one way or the other here.
MSQ_Set2:
SetMem MSQ_State,2 ;For debugging monitor
GoSub DRV_Run ;Start ramping up speed
MSQ_2:
Suspend MSQ_Addr
GoIfInK iStopStart,MSQ_Set3 ;Test stop/start button
GoSub MSQ_ReadFR ;Test and process F/R
GoIfF MSQ_2 ;G/ not pressed

;State 6 is decellerating prior to reversing direction.
MSQ_Set6:
SetMem MSQ_State,6 ;For debugging monitor
GoSub DRV_Stop ;Commence stop process
MSQ_6:
Suspend MSQ_Addr
GoIfInK iStopStart,MSQ_Set8 ;Test stop/start button
GoSub DRV_Get_ZPWM ;Test if PWM is zero
GoIfT MSQ_Set7
GoSub MSQ_ReadFR ;Test and process F/R
GoIfF MSQ_6 ;G/ not pressed
GoTo MSQ_Set2

;State 3 is decellerating prior to stopping
MSQ_Set3:
SetMem MSQ_State,3 ;For debugging monitor
GoSub DRV_Stop
MSQ_3:
Suspend MSQ_Addr
GoIfInK iStopStart,MSQ_Set2 ;Test stop/start button
GoSub DRV_Get_ZPWM
GoIfT MSQ_Set4
GoSub MSQ_ReadFR ;Test and process F/R
GoIfF MSQ_3 ;G/ not pressed

;State 5 is if F/R is pushed while decellerating for a stop
MSQ_Set5:
SetMem MSQ_State,5 ;For debugging monitor
MSQ_5:
Suspend MSQ_Addr
GoIfInK iStopStart,MSQ_6 ;Test stop/start button
GoSub DRV_Get_ZPWM
GoIfT MSQ_Set4
GoSub MSQ_ReadFR ;Test and process F/R
GoIfF MSQ_5 ;G/ not pressed
GoTo MSQ_3

;State 8 is if Stop/start is hit while decelleration prior to reversing
MSQ_Set8:
SetMem MSQ_State,8 ;For debugging monitor
MSQ_8:
Suspend MSQ_Addr
GoIfInK iStopStart,MSQ_6 ;Test stop/start button
GoSub DRV_Get_ZPWM
GoIfT MSQ_Set4
GoTo MSQ_8

;State 4 is timing the dynamic braking interval after a stop.
MSQ_Set4:
SetMem MSQ_State,4 ;For debugging monitor
InputO oDirection ;Read back direction relay
NOT
Output oDirection
SetMem MSQ_Count,StopTime
MSQ_4:
Suspend MSQ_Addr
GoSub MSQ_ReadFR
GoIfSF Tick10,MSQ_4
DMGNZ MSQ_Count,MSQ_4
GoTo MSQ_Set0

;State 7 is timing the dynamic braking interval foir stopping during reversal
MSQ_Set7:
SetMem MSQ_State,7 ;For debugging monitor
RecallS MSQ_RevFlag
Output oDirection
SetMem MSQ_Count,StopTime
MSQ_7:
Suspend MSQ_Addr
GoSub MSQ_ReadFR
GoIfSF Tick10,MSQ_7
DMGNZ MSQ_Count,MSQ_7
GoTo MSQ_Set2

;----- Read and process F/R button. Return True if pressed
MSQ_ReadFR:
InputK iFwdRev
Push
RetIfF
RecallS MSQ_RevFlag
NOT
StoreS MSQ_RevFlag
Return

;----------- Drive Task --------------------------
;This task is responsible for ramping the PWM up and down to the target speed
;(when enabled). In essence it simply makes the actual PWM track the target PWM,
;with ramping. There is a coding option for sudden stop or smooth stop.

;Short name DRV

;Uses lcd 1,0 through 1,3

;Entry points

; DRV_Init Initialize
; DRV_Update Update.
; DRV_Run Start ramping up. Simply updates DRV_Accelerate semaphore
; DRV_Stop Start ramping down. Simply updates DRV_Accelerate semaphore
; DRV_Get_ZPWM Return true if PWM=0

DRV_Get_ZPWM:
Recall DRV_PWM
Push
OR
NOT
Return

DRV_Update:
Resume DRV_Addr

DRV_Init:
DRV_Set0:
SetMem DRV_PWM,0
GoSub DRV_PWMOut
DRV_0:
Suspend DRV_Addr
GoIfST DRV_Accelerate,DRV_Set1 ;Test for RUN command
GoTo DRV_0

DRV_Set1: ;Here on RUN command
Suspend DRV_Addr

;Which of the following 2 code lines determines whether the controller
;executes sudden stops, with dynamic braking, or smooth stop (ramping down the speed)
;Comment out the line you don't want.

;This line for sudden stop:
GoIfSF DRV_Accelerate,DRV_Set0 ;Test for STOP command
;This line for smooth stop:
GoIfSF DRV_Accelerate,DRV_Set2 ;Test for STOP command


GoIfSF Tick10,DRV_Set1 ;wait for time tick
GoSub SPD_GetSpeed ;Target PWM
Recall DRV_PWM ;Actual PWM
CompareR ;Compare Target to actual
BranchR ;Test result
Target DRV_Set1 ;On target
Target DRV_1_Dec ;PWM too high
Target DRV_1_Inc ;PWM too low

DRV_1_Dec: ;Here to decrement PWM
DecM DRV_PWM
GoSub DRV_PWMOut
GoTo DRV_Set1

DRV_1_Inc: ;Here to increment PWM
IncM DRV_PWM ;
GoSub DRV_PWMOut
GoTo DRV_Set1

DRV_Set2: ;Here on stop command
Suspend DRV_Addr
GoIfST DRV_Accelerate,DRV_Set1 ;Test for RUN command
GoIfSF Tick10,DRV_Set2 ;wait for time tick
GoIfMZ DRV_PWM,DRV_Set0
DecM DRV_PWM
GoSub DRV_PWMOut
GoTo DRV_Set2


DRV_Run:
SetS DRV_Accelerate
Return

DRV_Stop:
ClrS DRV_Accelerate
Return

DRV_PWMOut: ;Output the PWM
Recall DRV_PWM
AnOutJ ;Alter for MS12
OBLCD_SetCur 1,0
OBLCD_UDecDispMFW DRV_PWM
Return


;----------- Speed task ---------------------------
;This task maintains the target speed.
;Short name SPD

;Uses lcd 0,0 through 0,3

;Entry points

; SPD_Init Initialize
; SPD_UpDate Service push buttons, update target accordingly
; SPD_Get_Speed return current target speed in X

SPD_Init:
Return

SPD_GetSpeed:
Recall SPD_Target
Return

SPD_UpDate:
GoIfInK iSpeedUp,SPD_Up
GoIfInK iSpeedDn,SPD_Dn
GenRet: Return

SPD_Dn:
SetMem SPD_Count,SPD_Increment
SPD_DnA:
GoIfMZ SPD_Target,SPD_Show
DecM SPD_Target
DMGNZ SPD_Count,SPD_DnA


SPD_Show:
OBLCD_SetCur 0,0
OBLCD_UDecDispMFW SPD_Target
Return

SPD_Up:
SetMem SPD_Count,SPD_Increment
SPD_UpA:
GoIfMEQ SPD_Target,255,SPD_Show
IncM SPD_Target
DMGNZ SPD_Count,SPD_UpA
GoTo SPD_Show