I've been trying to get the following functions to compile. I'm trying to put together some functions to move single or multiple servos simultaneously. I have up to three servos to move at the same time. I get an error that there are too many parameters in the while statement. From what I can determine from code examples there are none that address this feature. I'm aware that the & and AND commands are are for manipulating bits. I've used structures like this in other languages like 'C' but can't find examples in SX/B. Any suggestions of how to restructure the functions would be useful. SEE the FUNC EYES_CENTER code. Or the FUNC CENTER_ALL code as examples of what I'm trying to do. The definitions are from the Servo6Digital10.SXB code from the forum.
FUNC EYES_UP
FOR idx4 = pos(4) TO HI_LIMIT STEP 1
put pos(4), idx4
DELAY_MS 10
NEXT
RETURN
ENDFUNC
FUNC EYES_UD_MID
FOR idx4 = pos(4) TO MID
IF idx4 < MID THEN
INC idx4
ELSE
DEC idx4
put pos(4), idx4
DELAY_MS 10
NEXT
RETURN
ENDFUNC
FUNC EYES_CENTER
idx0 = pos(3)
idx1 = pos(3)
DO WHILE idx3 <> MID AND idx4 <> MID
IF idx3 > MID THEN
DEC idx3
ENDIF
IF idx3 < MID THEN
INC idx3
ENDIF
IF idx4 > MID THEN
DEC idx4
ENDIF
IF idx4 < MID THEN
INC idx4
ENDIF
put pos(3), idx3
put pos(4), idx4
DELAY_MS 10
LOOP
RETURN
ENDFUNC
FUNC LEFT_UP
idx0 = pos(0)
idx1 = pos(1)
DO WHILE idx0 > LO_LIMIT && idx1 < HI_LIMIT
IF idx0 > LO_LIMIT THEN
DEC idx0
ENDIF
IF idx1 < HI_LIMIT THEN
INC idx1
ENDIF
put pos(0), idx0
put pos(1), idx1
DELAY_MS 10
LOOP
RETURN
ENDFUNC
FUNC RIGHT_UP
idx0 = pos(0)
idx1 = pos(1)
DO WHILE idx0 < HI_LIMIT && idx1 < HI_LIMIT
IF idx0 < HI_LIMIT THEN
INC idx0
ENDIF
IF idx1 < HI_LIMIT THEN
INC idx1
ENDIF
put pos(0), idx0
put pos(1), idx1
DELAY_MS 10
LOOP
RETURN
ENDFUNC
FUNC LEFT_DWN
idx0 = pos(0)
idx1 = pos(1)
DO WHILE idx0 < HI_LIMIT && idx1 > LO_LIMIT
IF idx0 < HI_LIMIT THEN
INC idx0
ENDIF
IF idx1 > LO_LIMIT THEN
DEC idx1
ENDIF
put pos(0), idx0
put pos(1), idx1
DELAY_MS 10
LOOP
RETURN
ENDFUNC
FUNC RIGHT_DWN
idx0 = pos(0)
idx1 = pos(1)
DO WHILE idx0 > LO_LIMIT && idx1 > LO_LIMIT
IF idx0 > LO_LIMIT THEN
DEC idx0
ENDIF
IF idx1 > LO_LIMIT THEN
DEC idx1
ENDIF
put pos(0), idx0
put pos(1), idx1
DELAY_MS 5
LOOP
RETURN
ENDFUNC
FUNC CENTER_ALL
idx0 = pos(0)
idx1 = pos(1)
idx2 = pos(2)
DO WHILE idx0 <> MID && idx1 <> MID && idx2 <> MID
IF idx0 < MID THEN
INC idx0
ENDIF
IF idx0 > MID THEN
DEC idx1
ENDIF
IF idx1 < MID THEN
INC idx1
ENDIF
IF idx1 > MID THEN
DEC idx1
ENDIF
IF idx2 < MID THEN
INC idx2
ENDIF
IF idx2 > MID THEN
DEC idx2
ENDIF
put pos(0), idx0
put pos(1), idx1
put pos(2), idx2
DELAY_MS 5
LOOP
RETURN
ENDFUNC
It's really quite difficult to assist with an advanced Prop-SX program unless you let us open it in and editor and run it for ourselves. Please consider attaching your complete program.
On problem I see from the get-go, however, is that you seem to have multiple servos that are not being refreshed every 20ms as they need to be. ANY load on the servo without refreshing every 20ms will cause it to drift. With the Prop-SX one can create a virtual servo controller in the interrupt that allows you to write to position variables and not worry about refreshing (it will be handled automatically).
Her is the whole thing - cut down a bit:
' Taken from Servo6_Digital10 BY
' Author.... Jon Williams, EFX-TEK
' Copyright (c) 2008-2009 EFX-TEK
' Some Rights Reserved
' -- see http://creativecommons.org/licenses/by/3.0/
' channel... 0 to 5 for servos
' 6 to 15 for digital outputs
'
' value..... 55 to 245 for servos (150 = center)
' >127 = on for digital channels
' <128 = off for digital channels
'
' Default baud rate is 38.4K but can be changed down to as low as 2400.
' Device Settings
ID "Srvo6+10"
DEVICE SX28, OSCHS2, BOR42
FREQ 50_000_000
' I/O Pins
Trigger PIN RC.6 INPUT ' P15 SETUP = DN (trainer)
Leds PIN RC ' P8..P13 (trainer)
OutsHi PIN RC OUTPUT ' solenoid control outputs
Out9 PIN RC.7 ' use P15/OUT15
' Out8 PIN RC.6 ' use P14/OUT14
Out7 PIN RC.5 ' use P13/OUT13
Out6 PIN RC.4 ' use P12/OUT12
Out5 PIN RC.3 ' use P11/OUT11
Out4 PIN RC.2 ' use P10/OUT10
Out3 PIN RC.1 ' use P9/OUT9
Out2 PIN RC.0 ' use P8/OUT8
OutsLo PIN RB OUTPUT
Out1 PIN RB.7 ' use P7/OUT7
Out0 PIN RB.6 ' use P6/OUT6
ServoCtrl PIN RB OUTPUT ' servo control pins
Servo5 PIN RB.5 ' use P5
Servo4 PIN RB.4 ' use P4
Servo3 PIN RB.3 ' use P3
Servo2 PIN RB.2 ' use P2
Servo1 PIN RB.1 ' use P1
Servo0 PIN RB.0 ' use P0
TX PIN RA.3 OUTPUT ' to PC
RX PIN RA.2 INPUT ' from PC
SCL PIN RA.1 INPUT ' EE clock line (I2C)
SDA PIN RA.0 INPUT ' EE data line (I2C)
' Note: TX, SCL, and SDA lines are not used by this program
' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------
IsOn CON 1
IsOff CON 0
Yes CON 1
No CON 0
LO_LIMIT CON 65 ' to prevent servo burn-up
MID CON 155
HI_LIMIT CON 245
' Variables
flags VAR Byte ' (keep global)
isrFlag VAR flags.0
rxReady VAR flags.1 ' rx byte waiting
sync VAR Byte
chan VAR Byte
value VAR Byte
mask VAR Byte
rxSerial VAR Byte (16)
rxBuf VAR rxSerial(0) ' 8-byte buffer
rxCount VAR rxSerial(8) ' rx bit count
rxDivide VAR rxSerial(9) ' bit divisor timer
rxByte VAR rxSerial(10) ' recevied byte
rxHead VAR rxSerial(11) ' buffer head (write to)
rxTail VAR rxSerial(12) ' buffer tail (read from)
rxBufCnt VAR rxSerial(13) ' # bytes in buffer
svoData VAR Byte (16) ' bank servo data
pos VAR svoData(0) ' position table
pos0 VAR svoData(0)
pos1 VAR svoData(1)
pos2 VAR svoData(2)
pos3 VAR svoData(3)
pos4 VAR svoData(4)
pos5 VAR svoData(5)
pos6 VAR svoData(6)
pos7 VAR svoData(7)
svoTix VAR svoData(8) ' isr divider
svoFrame_LSB VAR svoData(9) ' frame timer
svoFrame_MSB VAR svoData(10)
svoIdx VAR SvoData(11) ' active servo pointer
svoTimer VAR svoData(12) ' pulse timer
svoPin VAR svoData(13) ' active servo pin
dbTimer VAR Byte
Incr VAR Byte
idx0 VAR Byte
idx1 VAR Byte
idx2 VAR Byte
idx3 VAR Byte
idx4 VAR Byte
idx5 VAR Byte
' =========================================================================
INTERRUPT NOPRESERVE 300_000 ' (4) run every 3.333 uS
' =========================================================================
Mark_ISR:
\ SETB isrFlag ' (1)
' not used but not yet removed from Servo6_Digital10
' ----------------
' Servo Processing
' ----------------
'
Test_Servo_Tix:
ASM
BANK svoData ' (1)
INC svoTix ' (1) update divider
CJB svoTix, #3, Servo_Done ' (4/6) done?
CLR svoTix ' (1) yes, reset for next
' Code below this point runs every 10 uS
Check_Frame_Timer:
CJNE svoFrame_LSB, #2000 & 255, Inc_FrTmr ' (4/6) svoFrame = 2000 (20 ms)?
CJNE svoFrame_MSB, #2000 >> 8, Inc_FrTmr ' (4/6)
CLR svoFrame_LSB ' (1) yes, reset
CLR svoFrame_MSB ' (1)
MOV svoPin, #%0000_0001 ' (2) start servo sequence
CLR svoIdx ' (1) point to servo 0
MOV FSR, #pos ' (2)
MOV svoTimer, IND ' (2)
JMP Refesh_Servo_Outs ' (3)
Inc_FrTmr:
INC svoFrame_LSB ' (1) DEC svoFrame
ADDB svoFrame_MSB, Z ' (2)
Check_Servo_Timer:
TEST svoPin ' (1) any servos on?
SNZ ' (1)
JMP Servo_Done ' (1) no, exit
DEC svoTimer ' (1) yes, update timer
SZ ' (1) still running?
JMP Servo_Done ' (1) yes, exit
Reload_Servo_Timer:
INC svoIdx ' (1) point to next servo
MOV W, #pos ' (1) get pulse timing
ADD W, svoIdx ' (1)
MOV FSR, W ' (1)
MOV W, IND ' (1)
MOV svoTimer, W ' (1) move to timer
Select_Next_Servo:
CLC ' (1)
RL svoPin ' (1)
AND svoPin, #%0011_1111 ' (2) limit servo channels
Refesh_Servo_Outs:
AND ServoCtrl, #%1100_0000 ' (2) clear last
OR ServoCtrl, svoPin ' (2) update outputs
Servo_Done:
ENDASM
ISR_Exit:
RETURNINT ' (4)
' Too be removed most likely from here to above
' -------------------------------------------------------------------------
' Subroutine / Function Declarations
' -------------------------------------------------------------------------
RX_BYTE FUNC 1, 0 ' receive a byte
DELAY_MS SUB 2, 2, Word, Word ' shell for PAUSE
NOD_DWN FUNC 1, 0
NOD_UP FUNC 1, 0
NOD_MID FUNC 1, 0
TURN_LEFT FUNC 1, 0
TURN_RIGHT FUNC 1, 0
TURN_MID FUNC 1, 0
TILT_LEFT FUNC 1, 0
TILT_RIGHT FUNC 1, 0
TILT_MID FUNC 1, 0
EYES_LEFT FUNC 1, 0
EYES_RIGHT FUNC 1, 0
EYES_RL_MID FUNC 1, 0
EYES_DWN FUNC 1, 0
EYES_UP FUNC 1, 0
EYES_UD_MID FUNC 1, 0
EYES_CENTER FUNC 2, 0
LEFT_DWN FUNC 2, 0
RIGHT_DWN FUNC 2, 0
LEFT_UP FUNC 2, 0
RIGHT_UP FUNC 2, 0
CENTER_ALL FUNC 3, 0
' =========================================================================
PROGRAM Start
' =========================================================================
Start:
TX = 1 ' set TX line to idle
' center servos
PUT pos, MID, MID, MID, MID, MID, MID
PLP_A = %0000
TRIS_C = %1100_0000 ' make RC.0 .. RC.5 outputs
Main:
Leds = IsOff
dbTimer = 0
Check_Trigger:
' PAUSE 1
INC dbTimer
IF Trigger = IsOff THEN Main
IF dbTimer < 100 THEN Check_Trigger
Zip_It: ' just playing with the prop-1 trainer here
FOR chan = 0 TO 4
Leds = 1 << chan
DELAY_MS 100
NEXT
FOR chan = 5 TO 0 STEP -1
Leds = 1 << chan
DELAY_MS 100
NEXT
Leds = IsOff
FOR Incr = MID TO LO_LIMIT STEP -1 ' This will be replaced by calls
put pos, Incr, Incr ' to the Functions
DELAY_MS 5
NEXT
FOR Incr = LO_LIMIT TO HI_LIMIT STEP 1
put pos, Incr, Incr
DELAY_MS 5
NEXT ' Functions replace to here
IF Trigger = IsOn THEN Zip_It
GOTO Main
overs
' Subroutine / Function Code
SUB DELAY_MS
PAUSE __wparam12
ENDSUB
FUNC NOD_DWN ' Functions to control servos
FOR idx0 = pos(0) TO LO_LIMIT STEP -1
put pos(0), idx0
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC NOD_UP
FOR idx0 = pos(0) TO HI_LIMIT STEP 1
put pos(0), idx0
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC NOD_MID
FOR idx0 = pos(0) TO MID
IF idx0 < MID THEN
INC idx0
ELSE
DEC idx0
put pos(2), idx2
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC TURN_LEFT
FOR idx1 = pos(1) TO LO_LIMIT STEP -1
put pos(1), idx1
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC TURN_RIGHT
FOR idx1 = pos(1) TO HI_LIMIT STEP 1
put pos(1), idx1
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC TURN_MID
FOR idx1 = pos(1) TO MID
IF idx1 < MID THEN
INC idx1
ELSE
DEC idx1
put pos(2), idx1
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC TILT_LEFT
FOR idx2 = pos(2) TO LO_LIMIT STEP -1
put pos(2), idx2
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC TILT_RIGHT
FOR idx2 = pos(2) TO HI_LIMIT STEP 1
put pos(2), idx2
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC TILT_MID
FOR idx2 = pos(2) TO MID
IF idx2 < MID THEN
INC idx2
ELSE
DEC idx2
put pos(2), idx2
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC EYES_LEFT
FOR idx3 = pos(3) TO LO_LIMIT STEP -1
put pos(3), idx3
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC EYES_RIGHT
FOR idx3 = pos(3) TO HI_LIMIT STEP 1
put pos(3), idx3
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC EYES_RL_MID
FOR idx3 = pos(3) TO MID
IF idx3 < MID THEN
INC idx3
ELSE
DEC idx3
put pos(3), idx3
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC EYES_DWN
FOR idx4 = pos(4) TO LO_LIMIT STEP -1
put pos(4), idx4
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC EYES_UP
FOR idx4 = pos(4) TO HI_LIMIT STEP 1
put pos(4), idx4
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC EYES_UD_MID
FOR idx4 = pos(4) TO MID
IF idx4 < MID THEN
INC idx4
ELSE
DEC idx4
put pos(4), idx4
DELAY_MS 5
NEXT
RETURN
ENDFUNC
FUNC EYES_CENTER
idx0 = pos(3)
idx1 = pos(3)
DO WHILE idx3 <> MID AND idx4 <> MID
IF idx3 > MID THEN
DEC idx3
ENDIF
IF idx3 < MID THEN
INC idx3
ENDIF
IF idx4 > MID THEN
DEC idx4
ENDIF
IF idx4 < MID THEN
INC idx4
ENDIF
put pos(3), idx3
put pos(4), idx4
DELAY_MS 5
LOOP
RETURN
ENDFUNC
FUNC LEFT_UP
idx0 = pos(0)
idx1 = pos(1)
DO WHILE idx0 > LO_LIMIT && idx1 < HI_LIMIT
IF idx0 > LO_LIMIT THEN
DEC idx0
ENDIF
IF idx1 < HI_LIMIT THEN
INC idx1
ENDIF
put pos(0), idx0
put pos(1), idx1
DELAY_MS 5
LOOP
RETURN
ENDFUNC
FUNC RIGHT_UP
idx0 = pos(0)
idx1 = pos(1)
DO WHILE idx0 < HI_LIMIT && idx1 < HI_LIMIT
IF idx0 < HI_LIMIT THEN
INC idx0
ENDIF
IF idx1 < HI_LIMIT THEN
INC idx1
ENDIF
put pos(0), idx0
put pos(1), idx1
DELAY_MS 5
LOOP
RETURN
ENDFUNC
FUNC LEFT_DWN
idx0 = pos(0)
idx1 = pos(1)
DO WHILE idx0 < HI_LIMIT && idx1 > LO_LIMIT
IF idx0 < HI_LIMIT THEN
INC idx0
ENDIF
IF idx1 > LO_LIMIT THEN
DEC idx1
ENDIF
put pos(0), idx0
put pos(1), idx1
DELAY_MS 5
LOOP
RETURN
ENDFUNC
FUNC RIGHT_DWN
idx0 = pos(0)
idx1 = pos(1)
DO WHILE idx0 > LO_LIMIT && idx1 > LO_LIMIT
IF idx0 > LO_LIMIT THEN
DEC idx0
ENDIF
IF idx1 > LO_LIMIT THEN
DEC idx1
ENDIF
put pos(0), idx0
put pos(1), idx1
DELAY_MS 5
LOOP
RETURN
ENDFUNC
FUNC CENTER_ALL
idx0 = pos(0)
idx1 = pos(1)
idx2 = pos(2)
DO WHILE idx0 <> MID && idx1 <> MID && idx2 <> MID
IF idx0 < MID THEN
INC idx0
ENDIF
IF idx0 > MID THEN
DEC idx1
ENDIF
IF idx1 < MID THEN
INC idx1
ENDIF
IF idx1 > MID THEN
DEC idx1
ENDIF
IF idx2 < MID THEN
INC idx2
ENDIF
IF idx2 > MID THEN
DEC idx2
ENDIF
put pos(0), idx0
put pos(1), idx1
put pos(2), idx2
DELAY_MS 5
LOOP
RETURN
ENDFUNC 'End of Servo control functions.
This is the first section giving you trouble:
DO WHILE idx3 <> MID AND idx4 <> MID
' stuff
LOOP
You can't do it -- SX/B only allows one conditional test per line. You can change it to:
DO
IF idx3 = MID THEN Exit
IF idx4 = MID THEN Exit
' loop stuff
LOOP
I'd do it this way just for clean form.
Don't use PUT with a single array element, just assign the new value. Instead of
PUT pos(0), idx0
Use:
pos(0) = idx0
BTW, functions are used to return a value -- yours don't You should just make them subroutines as this will generate a little less code (and they're easier to define).
If I understand what you wrote in the example, if either idx value equals MID then exit the DO - LOOP. That is not exactly what I was trying to accomplish. I want the loop to continue to run until both idx values equal MID not just until the first one gets there. (idx3 not equal MID) AND (idx4 not equal MID). I think I understand the logic change (change the not equal to EQUAL and change the AND to an OR) supposed to be equivalent but you then made it exit instead of executing the loop which makes the logic wrong. How can I get two tests so that either continue the same one loop.
I originally had the FUNC's defined as SUBroutines but was getting an error so I changed them to FUNC's only to find the problem to be with the earlier Define of the SUBroutine. It should have been EYE_CENTER SUB 0 or EYE_CENTER SUB 2, 0 not sure which? Two parameters are used as input - pos(3) and pos(4) but nothing is returned.
If they both must equal MID, then the loop would be structured very close to what Jon had:
DO
IF idx3 = MID AND idx4 = MID THEN Exit
' loop stuff
LOOP
Can't do that Mike as SX/B doesn't allow compound statements.
Here's what I'd do. First, I'd redefine anything that doesn't return a value as a SUBroutine:
EYES_CENTER SUB 0, 0
And I would re-code it like this (it compiles):
SUB EYES_CENTER
idx0 = pos(3)
idx1 = pos(3)
EC_Move:
IF idx3 = MID THEN
IF idx4 = MID THEN
GOTO EC_Exit
ENDIF
ENDIF
IF idx3 > MID THEN
DEC idx3
ELSEIF idx3 < MID THEN
INC idx3
ENDIF
pos(3) = idx3
IF idx4 > MID THEN
DEC idx4
ELSEIF idx4 < MID THEN
INC idx4
ENDIF
pos(4) = idx4
DELAY_MS 5
GOTO EC_Move
EC_Exit:
ENDSUB
what about like this then:
SUB EYES_CENTER
idx3 = pos(3)
idx4 = pos(4)
DO
IF idx3 = MID THEN
IF idx4 = MID THEN
Exit
ENDIF
ENDIF
IF idx3 > MID THEN
DEC idx3
ELSEIF idx3 < MID THEN
INC idx3
ENDIF
pos(3) = idx3
IF idx4 > MID THEN
DEC idx4
ELSEIF idx4 < MID THEN
INC idx4
ENDIF
pos(4) = idx4
DELAY_MS 40
LOOP
It might work (you'll have to try) but my rule is no more than five or so lines within a DO-LOOP as long structures can make the code really difficult to follow, especially when attempting to troubleshoot. Skip fancy, go for simple, robust code. ;D