EFX-TEK
September 09, 2010, 12:02:08 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News: Got VSA?  Want to use your Prop-SX?  Now you can!  See the VSA section of the Library forum for Prop-SX code that works with VSA.
 
   Home   Help Search Calendar Login Register  
Pages: [1]
  Print  
Author Topic: EZ-8 as a Servo/PWM Controller  (Read 522 times)
JonnyMac
Administrator
Hero Member
*****
Posts: 3300



WWW Email
« 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

* EZ-8_Servo_6x2.vsa (7.73 KB - downloaded 44 times.)
« Last Edit: August 24, 2009, 03:33:21 PM by JonnyMac » Report to moderator   Logged

Jon Williams
EFX-TEK
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!