|
JonnyMac
|
 |
« on: August 24, 2009, 02:23:49 PM » |
|
For those that are looking for a servo/pwm controller for VSA this program will do the trick. It converts the EZ-8 into a VSA-compatible servo controller that will run six servos (Ch1 - Ch6) and two PWM channels (Ch7 - Ch8). So, why would you use the EZ-8 for this instead of the Prop-SX? 1) Smaller footprint 2) EZ-8 has a 5A regulator for the 5v outputs (yes, we snuck that in just for this purpose) -- that's not to say that 5A will handle all servo apps, but it should handle many if not most small props 3) The selector switch allows you to isloate a channel -- 0 : all channels on -- 1 to 8 : isolate a channel -- 9 : all channels off The ability to isolate a channel will be helpful when you want to go back and fine-tune the mouth movements of your talking skull without disrupting the whole VSA show. I've attached a blank VSA (version 4) file for you to start with. ' ========================================================================= ' ' File...... EZ-8_Servo.SXB ' Purpose... ' Author.... Jon Williams, EFX-TEK ' Copyright (c) 2009 EFX-TEK ' Some Rights Reserved ' -- see http://creativecommons.org/licenses/by/3.0/ ' E-mail.... jwilliams@efx-tek.com ' Started... ' Updated... 24 AUG 2009 ' ' =========================================================================
' ------------------------------------------------------------------------- ' Program Description ' ------------------------------------------------------------------------- ' ' Servo controller/output device designed for use with VSA or other ' real-time serial control programs. ' ' CH1 to CH6... Servo control ' CH7 to CH8... PWM outputs ' ' The protocol is identical to the SEETRON (www.seetron.com) MiniSSC: ' ' <sync><channel><value> ' ' sync...... $FF (255) ' ' channel... 0 to 5 for servos ' 6 to 7 for pwm outputs ' ' value..... 55 to 245 for servos (150 = center) ' 0 to 254 for pwm outputs ' ' Default baud rate is 38.4K but can be changed down to as low as 2400.
' ------------------------------------------------------------------------- ' Conditional Compilation Symbols ' -------------------------------------------------------------------------
' ------------------------------------------------------------------------- ' Device Settings ' -------------------------------------------------------------------------
ID "EZ8_Srvo"
DEVICE SX28, OSCHS2, BOR42 FREQ 50_000_000
' ------------------------------------------------------------------------- ' I/O Pins ' -------------------------------------------------------------------------
Outs PIN RC Ch8 PIN RC.7 OUTPUT Ch7 PIN RC.6 OUTPUT Ch6 PIN RC.5 OUTPUT Ch5 PIN RC.4 OUTPUT Ch4 PIN RC.3 OUTPUT Ch3 PIN RC.2 OUTPUT Ch2 PIN RC.1 OUTPUT Ch1 PIN RC.0 OUTPUT
LedGrn PIN RB.7 OUTPUT LedRed PIN RB.6 OUTPUT PgmBtn PIN RB.5 INPUT PULLUP StartBtn PIN RB.4 INPUT PULLUP MS3 PIN RB.3 INPUT PULLUP MS2 PIN RB.2 INPUT PULLUP MS1 PIN RB.1 INPUT PULLUP MS0 PIN RB.0 INPUT PULLUP
TX PIN RA.3 OUTPUT RX PIN RA.2 INPUT SCL PIN RA.1 INPUT SDA PIN RA.0 INPUT
' ------------------------------------------------------------------------- ' Constants ' -------------------------------------------------------------------------
IsOn CON 1 IsOff CON 0
Yes CON 1 No CON 0
LO_LIMIT CON 55 ' to prevent servo burn-up HI_LIMIT CON 245
' Bit dividers for 3.255 uS interrupt ' -- ISR actually runs at 3.333 uS for better servo timing
Baud2400 CON 128 Baud4800 CON 64 Baud9600 CON 32 Baud19K2 CON 16 Baud38K4 CON 8
Baud1x0 CON Baud38K4 ' 1 bit period (ISR counts) Baud1x5 CON Baud1x0 * 3 / 2 ' 1.5 bit periods
LED_OFF CON 0 LED_GRN CON 1 LED_RED CON 2 LED_YEL CON 3
' ------------------------------------------------------------------------- ' Variables ' -------------------------------------------------------------------------
flags VAR Byte ' (keep global) isrFlag VAR flags.0 rxReady VAR flags.1 ' rx byte waiting ledFlash VAR flags.7
btnFlags VAR Byte ' (global) swMS0 VAR btnFlags.0 swMS1 VAR btnFlags.1 swMS2 VAR btnFlags.2 swMS3 VAR btnFlags.3 btnStart VAR btnFlags.4 btnRec VAR btnFlags.5
pwmTemp VAR Byte
' -------------------------------------------------------------------------
sync VAR Byte chan VAR Byte value VAR Byte mask VAR Byte
tmpW1 VAR Word
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
dimmer VAR Byte(4) BANK level1 VAR dimmer(0) level2 VAR dimmer(1) acc1 VAR dimmer(2) acc2 VAR dimmer(3)
ledCtrl VAR Byte (2) BANK ' LED color / flash ctrl ledState VAR ledCtrl(0) ' 0-7; off, grn, red, yel rgTimer VAR ledCtrl(1)
dbControl VAR Byte (4) BANK ' for debounce ms1Timer_LSB VAR dbControl(0) ' isr ticks/millisecond ms1Timer_MSB VAR dbControl(1) btnTimer VAR dbControl(2) ' debounce timer (ms) btnTemp VAR dbControl(3) ' work var for debounce
' ========================================================================= INTERRUPT NOPRESERVE 300_000 ' (4) run every 3.333 uS ' =========================================================================
Mark_ISR: \ SETB isrFlag ' (1)
' ------- ' RX UART ' ------- ' ' UART code by C. Gracey, A. Williams, et al ' -- buffer and flow control mods by Jon Williams ' Receive: ASM BANK rxSerial ' (1) JB rxBufCnt.3, RX_Done ' (2/4) skip if buffer is full MOVB C, RX ' (4) sample serial input TEST rxCount ' (1) receiving now? JNZ RX_Bit ' (2/4) yes, get next bit MOV W, #9 ' (1) no, prep for next byte SC ' (1/2) MOV rxCount, W ' (1) if start, load bit count MOV rxDivide, #Baud1x5 ' (2) prep for 1.5 bit periods
RX_Bit: DJNZ rxDivide, RX_Done ' (2/4) complete bit cycle? MOV rxDivide, #Baud1x0 ' (2) yes, reload bit timer DEC rxCount ' (1) update bit count SZ ' (1/2) RR rxByte ' (1) position for next bit SZ ' (1/2) JMP RX_Done ' (3)
RX_Buffer: MOV W, #rxBuf ' (1) point to buffer head ADD W, rxHead ' (1) MOV FSR, W ' (1) MOV IND, rxByte ' (2) move rxByte to head INC rxHead ' (1) update head CLRB rxHead.3 ' (1) keep 0..7 INC rxBufCnt ' (1) update buffer count SETB rxReady ' (1) set ready flag
RX_Done: ENDASM
' ---------------- ' 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 Outs, #%1100_0000 ' (2) clear last OR Outs, svoPin ' (2) update outputs
Servo_Done: ENDASM
' ----------- ' PWM Control ' ----------- ' PWM_Control: ASM BANK dimmer ' (1) CLR pwmTemp ' (1) clear work byte ADD acc1, level1 ' (2) update accumlator RR pwmTemp ' (1) rotate bit into work byte ADD acc2, level2 ' (2) RR pwmTemp ' (1) AND Outs, #%0011_1111 ' (2) clear old bits OR Outs, pwmTemp ' (2) update new pwm bits ENDASM
' -------------- ' LED Controller ' -------------- ' Led_Control: ASM BANK ledCtrl ' (1) MOV W, ledState ' (1) get state AND W, #%0000_0011 ' (1) keep legal (0 to 3) JMP PC+W ' (3) jump to handler JMP Led_0 ' (3) JMP Led_1 ' (3) JMP Led_2 ' (3) JMP Led_3 ' (3)
Led_0: ' LED off CLRB LedGrn ' (1) CLRB LedRed ' (1) JMP Led_Exit ' (3)
Led_1: ' LED green SETB LedGrn ' (1) CLRB LedRed ' (1) JMP Led_Exit ' (3)
Led_3: ' LED yellow INC rgTimer ' (1) JNB rgTimer.3, Led_1 ' (2/4) 7G:1R CLR rgTimer ' (1)
Led_2: ' LED red CLRB LedGrn ' (1) SETB LedRed ' (1) JMP Led_Exit ' (3)
Led_Exit: ENDASM
' ------------------------ ' Switch / Button Debounce ' ------------------------ ' Check_Inputs: ASM BANK dbControl ' (1) point to timer INC ms1Timer_LSB ' (1) ADDB ms1Timer_MSB, Z ' (2) CJNE ms1Timer_LSB, #$2C, DB_Exit ' (4/6) at 1ms? CJNE ms1Timer_MSB, #$01, DB_Exit ' (4/6) CLR ms1Timer_LSB ' (1) yes, re-start CLR ms1Timer_MSB
DB_Check: INC btnTimer CJB btnTimer, #25, DB_Port_Scan ' (2/4) keep scanning for 25ms CLR btnTimer ' (1) restart scan timer MOV btnFlags, btnTemp ' (2) update program flags MOV btnTemp, #%0011_1111 ' (2) reset for next scan JMP DB_Exit
DB_Port_Scan: MOV W, /RB ' (1) scan port bits (invert) AND btnTemp, W ' (1) clear any released
DB_Exit: ENDASM
ISR_Exit: RETURNINT ' (4)
' ------------------------------------------------------------------------- ' Subroutine / Function Declarations ' -------------------------------------------------------------------------
RX_BYTE FUNC 1, 0 ' receive a byte
' ========================================================================= PROGRAM Start ' =========================================================================
Start: TX = 1 ' set TX line to idle
' center servos PUT pos, 150, 150, 150, 150, 150, 150
Main: chan = btnFlags & $0F ' read the selector IF chan = 0 THEN ' if 0 ledState = LED_GRN ' all channels active ELSEIF chan < 9 THEN ' if 1-to-8 then ledState = LED_YEL ' isolate ELSE ' if 10 then ledState = LED_RED ' all off ENDIF
READ Isolate + chan, mask ' convert position to TRIS value TRIS_C = mask ' update
IF rxReady = No THEN Main ' if no serial, keep waiting
Get_Sync: sync = RX_BYTE IF sync <> $FF THEN Main
Get_Channel: chan = RX_BYTE IF chan = $FF THEN Get_Channel ' correct for re-sync IF chan > 7 THEN Main ' check channel range
Get_Value: value = RX_BYTE IF value = $FF THEN Get_Channel ' correct for re-sync
Process_Value: IF chan < 6 THEN ' servo channel? value = value MIN LO_LIMIT ' force to legal limits value = value MAX HI_LIMIT value = HI_LIMIT - value ' invert to match VSA value = value + LO_LIMIT pos(chan) = value ELSE tmpW1 = value * value ' linearize; x = (x*x)/256 value = tmpW1_MSB IF chan = 6 THEN level1 = value ELSE level2 = value ENDIF ENDIF GOTO Main
' ------------------------------------------------------------------------- ' Subroutine / Function Code ' -------------------------------------------------------------------------
' Use: aByte = RX_BYTE ' -- returns "aByte" from 8-byte circular buffer ' -- will wait if buffer is presently empty ' -- rxBufCnt holds byte count of receive buffer (0 to 8)
FUNC RX_BYTE ASM JNB rxReady, @$ ' wait if empty BANK rxSerial ' point to serial vars MOV W, #rxBuf ADD W, rxTail ' point to rxBuf(rxTail MOV FSR, W MOV __PARAM1, IND ' get byte at tail INC rxTail ' update tail CLRB rxTail.3 ' keep 0..7 DEC rxBufCnt ' update buffer count SNZ ' exit if not zero CLRB rxReady ' else clear ready flag BANK $00 ENDASM ENDFUNC
' ========================================================================= ' User Data ' =========================================================================
Isolate: DATA %00_000000 ' all outputs on DATA %11_111110 ' isolate ch1 DATA %11_111101 DATA %11_111011 DATA %11_110111 DATA %11_101111 DATA %11_011111 DATA %10_111111 DATA %01_111111 ' isolate ch8 DATA %11_111111 ' all off
|