EFX-TEK
September 09, 2010, 01:38:59 PM *
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: Prop-SX - 8 Servos plus 8 PWM with VSA  (Read 1213 times)
JonnyMac
Administrator
Hero Member
*****
Posts: 3302



WWW Email
« on: February 27, 2008, 07:03:10 AM »

For those that need more than digital control of channels P8 to P15 the program below converts them to PWM outputs.  Now you you can control the brightness of the LED spots on your talking skull.

VSA project setup: Channels: 0 to 15

Channels 0 to 7:
  * MiniSSC Servo
  * +Value = 240
  * -Value = 60
  * Default = 150

Channels 8 to 15:
  * MiniSSC Dimmer or MiniSSC Relay
  * +Value = 254
  * -Value = 0
  * Default = 0

Note that channels 8 to 15 can be setup as a dimmer or relay; use a relay if you're only going to be doing on/off control with a given channel in that range.

[Edit]: Posted updated version 25 OCT 2009

' =========================================================================
'
'   File...... VSA_Servo8_PWM8.SXB
'   Purpose...
'   Author.... Jon Williams, EFX-TEK
'              Copyright (c) 2008-2009 EFX-TEK
'              Some Rights Reserved
'              -- see http://creativecommons.org/licenses/by/3.0/
'   E-mail.... jwilliams@efx-tek.com
'   Started...
'   Updated... 25 OCT 2009
'
' =========================================================================


' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Servo/PWM controller designed for use with VSA or other real-time
' serial control programs.
'
'   P0 to  P7... Servo control
'   P8 to P15... PWM/Digital outputs
'
' The protocol is identical to the SEETRON (www.seetron.com) MiniSSC:
'
'   <sync><channel><value>
'
'   sync...... $FF (255)
'
'   channel... 0 to  7 for servos
'              8 to 15 for PWM/digital outputs
'
'   value..... 60 to 240 for servos (150 = center)
'               0 to 254 for pwm outputs
'
' In VSA define servo channels as MiniSSC servo using 240, 60, 150 as the
' settings, and pwm channels as MiniSSC dimmer using 254 (max) and 0 (min).
' For digital behavior of a PWM output (e.g., for a valve) use MiniSSC
' Relay with an on value of 254 and off value of 0.
'
' Note: Servo min/max range is based on 180 values for Hitec servos, and
' this program reverses the VSA values to match them.


' -------------------------------------------------------------------------
' Conditional Compilation Symbols
' -------------------------------------------------------------------------


' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

ID              "VSA_S8P8"

DEVICE          SX28, OSCHS2, BOR42
FREQ            50_000_000


' -------------------------------------------------------------------------
' I/O Pins
' -------------------------------------------------------------------------

PwmCtrl         PIN     RC   OUTPUT             ' PWM control pins
 Pwm7           PIN     RC.7                    ' use P15/OUT15
 Pwm6           PIN     RC.6                    ' use P14/OUT14
 Pwm5           PIN     RC.5                    ' use P13/OUT13
 Pwm4           PIN     RC.4                    ' use P12/OUT12
 Pwm3           PIN     RC.3                    ' use P11/OUT11
 Pwm2           PIN     RC.2                    ' use P10/OUT10
 Pwm1           PIN     RC.1                    ' use P9/OUT9
 Pwm0           PIN     RC.0                    ' use P8/OUT8

ServoCtrl       PIN     RB   OUTPUT             ' servo control pins
 Servo7         PIN     RB.7                    ' use P7
 Servo6         PIN     RB.6                    ' use P6
 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     60                      ' to prevent servo burn-up
HI_LIMIT        CON     240

SYNC            CON     255


' Bit dividers for 3.255us interrupt
' -- actual code runs at 3.33us (within tolerance for bit sampling)

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


' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

flags           VAR     Byte                    ' (keep global)
 isrFlag        VAR     flags.0
 rxReady        VAR     flags.1

pwmTemp         VAR     Byte                    ' (keep global)
global3         VAR     Byte


cmd             VAR     Byte                    ' SSC packet
chan            VAR     Byte
value           VAR     Byte
tValue          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

pwmData         VAR     Byte (16)               ' bank for pwm vars
 level          VAR     pwmData(0)
 level0         VAR     pwmData(0)
 level1         VAR     pwmData(1)
 level2         VAR     pwmData(2)
 level3         VAR     pwmData(3)
 level4         VAR     pwmData(4)
 level5         VAR     pwmData(5)
 level6         VAR     pwmData(6)
 level7         VAR     pwmData(7)
 acc0           VAR     pwmData(8)
 acc1           VAR     pwmData(9)
 acc2           VAR     pwmData(10)
 acc3           VAR     pwmData(11)
 acc4           VAR     pwmData(12)
 acc5           VAR     pwmData(13)
 acc6           VAR     pwmData(14)
 acc7           VAR     pwmData(15)

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


' =========================================================================
  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


' --------------
' PWM Processing
' --------------
'
Process_PWM:
  ASM
    BANK  pwmData                               ' (1)
    ADD   acc0, level0                          ' (2)
    RR    pwmTemp                               ' (1)
    ADD   acc1, level1                          ' (2)
    RR    pwmTemp                               ' (1)
    ADD   acc2, level2                          ' (2)
    RR    pwmTemp                               ' (1)
    ADD   acc3, level3                          ' (2)
    RR    pwmTemp                               ' (1)
    ADD   acc4, level4                          ' (2)
    RR    pwmTemp                               ' (1)
    ADD   acc5, level5                          ' (2)
    RR    pwmTemp                               ' (1)
    ADD   acc6, level6                          ' (2)
    RR    pwmTemp                               ' (1)
    ADD   acc7, level7                          ' (2)
    RR    pwmTemp                               ' (1)
    MOV   PwmCtrl, pwmTemp                      ' (2)
  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, #%00000001                    ' (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)   INC 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
    CLRB  svoidx.3                              ' (1)   keep 0 - 7
    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)

Refesh_Servo_Outs:
    MOV   ServoCtrl, svoPin                     ' (2)   update outputs

Servo_Done:
  ENDASM


ISR_Exit:
  RETURNINT                                     ' (4)


' -------------------------------------------------------------------------
' Subroutine / Function Declarations
' -------------------------------------------------------------------------

FLUSH_RX        SUB     0                       ' clear RX buffer
RX_BYTE         FUNC    1, 0     Byte           ' receive a byte

DELAY_MS        SUB     2, 2,    Word           ' delay in 1ms units


' =========================================================================
  PROGRAM Start
' =========================================================================

Start:
  TX = 1                                        ' set TX line to idle
  DELAY_MS 50
  FLUSH_RX

  ' center servos
  PUT pos, 150 , 150, 150, 150, 150, 150, 150, 150


Main:
  cmd = RX_BYTE
  IF cmd <> SYNC THEN Main

Get_Channel:
  chan = RX_BYTE
  IF chan = SYNC THEN Get_Channel               ' correct for re-sync
  IF chan > 15 THEN Main                        ' check channel range

Get_Value:
  value = RX_BYTE
  IF value = $FF THEN Get_Channel               ' correct for re-sync

Process_Value:
  IF chan < 8 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
    chan = chan & $07                           ' adjust for PWM port
    tValue = value * value                      ' linearize; x = (x*x)/256
    level(chan) = tValue_MSB                    ' update pwm channel
  ENDIF

  GOTO Main


' -------------------------------------------------------------------------
' Subroutine / Function Code
' -------------------------------------------------------------------------

' Use: FLUSH_RX
' -- flushes pending bytes in rx buffer
' -- waits on incoming byte if in process

SUB FLUSH_RX
  ASM
    BANK  rxSerial                              ' point to serial vars
    TEST  rxCount                               ' receiving now?
    JNZ   @FLUSH_RX                             ' let it finish
    CLR   rxHead                                ' clear buffer pointers
    CLR   rxTail
    CLR   rxBufCnt                              ' clear buffer count
    BANK  $00
    CLRB  rxReady                               ' clear ready flag
  ENDASM
  ENDSUB

' -------------------------------------------------------------------------

' 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

' -------------------------------------------------------------------------

' Use: DELAY_MS duration
' -- delay in milliseconds

SUB DELAY_MS
  ms            VAR     __WPARAM12
  msTix         VAR     __WPARAM34

  DO WHILE ms > 0
    msTix = 300                                 ' load 1 ms timer
    DO WHILE msTix > 0                          ' let timer expire
      \ CLRB isrFlag                            ' clear ISR flag
      \ JNB  isrFlag, @$                        ' wait for flag to be set
      DEC msTix                                 ' update 1 ms timer
    LOOP
    DEC ms                                      ' update delay timer
  LOOP
  ENDSUB


' =========================================================================
' User Data
' =========================================================================

* VSA_Servo8_PWM8.SXB (15.81 KB - downloaded 29 times.)
* VSA_Servo8_PWM8.SXH (9.73 KB - downloaded 29 times.)
* prop-sx_servo-8_pwm-8.vsa (7.69 KB - downloaded 25 times.)
« Last Edit: October 25, 2009, 09:04:25 PM by JonnyMac » Report to moderator   Logged

Jon Williams
EFX-TEK
gadget-evilusions
Full Member
***
Posts: 227


gadgetnightmare deathstoofaraway666
WWW Email
« Reply #1 on: February 27, 2008, 07:49:28 AM »

Am I the only one who sees a bunch of smiley faces in the code?
« Last Edit: February 27, 2008, 08:59:50 AM by JonnyMac » Report to moderator   Logged

Brian
Evilusions LLC
www.evilusions.com for all your pneumatic components
JonnyMac
Administrator
Hero Member
*****
Posts: 3302



WWW Email
« Reply #2 on: February 27, 2008, 07:58:08 AM »

No, the problem is that if I don't leave smileys enable someone may think I'm cranky -- when an array index is 8 we end up with that.  So...

(Cool = ( 8 )

I'll fix those indexes because I just found that the smileys cause an error when one copies and pastes from the forum listing.
« Last Edit: February 27, 2008, 09:00:00 AM 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!