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