The USART communication is a simple single byte command structure which can be sent at virtually any baudrate and any order the user desires.
The following code is only 300 ROM compiled with mikroBasic 7.01, meaning that a free version of the compiler can be used to create the Hex Code.
Code: Select all
'*******************************************************************************
' Program to Control 12- 50Hz Servos @ 16 Positions Each With USART Updates
'*******************************************************************************
' Code compiled with mikroBASIC and tested on 16F887 @ 8MHz
' By Warren Schroeder June 5, 2008
'*******************************************************************************
'*******************************************************************************
'
' Each USART RX Byte:
' Servo ID = Upper 4 bits (0 to 11) 12 Servos
' Servo Position = Lower 4 bits (0 to 15) 16 Positions
'
' HITECH-HS422 50Hz Servo: 940us to 2140us for min and max servo rotation
' 16 positions (940us= Position#0 + (15 x 80us))
' Position#7 = 1500us Center
'
' Timer1 Setup for 1us ticks (Prescaler=2)
'
' CCP1 is set up for Special Event Compare Mode
' On Compare-Match between TIMER1 and CCPR1L:CCPR1H registers
' CCP1IF is Set (=1) and TIMER1 is RESET (=0)
'
'
'*******************************************************************************
'*******************************************************************************
Symbol Servo0 = PORTB.0
Symbol Servo1 = PORTB.1
Symbol Servo2 = PORTB.2
Symbol Servo3 = PortB.3
Symbol Servo4 = PORTB.4
Symbol Servo5 = PORTB.5
Symbol Servo6 = PORTB.6
Symbol Servo7 = PORTB.7
Symbol Servo8 = PORTD.0
Symbol Servo9 = PORTD.1
Symbol Servo10 = PORTD.2
Symbol Servo11 = PORTD.3
Dim AllOn as Boolean ' all servos ON flag
Dim t0, t1, t2 as Byte ' work variables
Dim Frame80 as Byte ' 80us time frame counter
Dim ServoPos as byte[12] ' 12 Servo Position Array from RX
Dim ServoWrk as byte[12] ' 12 Servo Position Work Array
sub procedure interrupt
If AllOn Then ' If AllOn flag=true then
PORTB = 255 ' All PORTB servos ON
PORTD = 15 ' All PORTD servos ON
AllOn = Not(AllOn) ' reset AllOn flag
Frame80 = 0 ' 80us frame counter
CCPR1L = 940 ' 940us = 0 position
CCPR1H = Hi(940)
For t2 = 0 to 11 ' load work array from USART RX array
ServoWrk[t2] = ServoPos[t2]
Next t2
Else
CCPR1L = 80 ' 80us frame delay
CCPR1H = 0
FSR = @ServoWrk ' servo work array pointer.. first servo
If INDF = 0 Then Servo0 = 0 End If ' turn each servo OFF on 0
Dec(INDF) ' decrement servo pos counter
INC(FSR) ' next servo.... etc. etc.
If INDF = 0 Then Servo1 = 0 End If
Dec(INDF)
INC(FSR)
If INDF = 0 Then Servo2 = 0 End If
Dec(INDF)
INC(FSR)
If INDF = 0 Then Servo3 = 0 End If
Dec(INDF)
INC(FSR)
If INDF = 0 Then Servo4 = 0 End If
Dec(INDF)
INC(FSR)
If INDF = 0 Then Servo5 = 0 End If
Dec(INDF)
INC(FSR)
If INDF = 0 Then Servo6 = 0 End If
Dec(INDF)
INC(FSR)
If INDF = 0 Then Servo7 = 0 End If
Dec(INDF)
INC(FSR)
If INDF = 0 Then Servo8 = 0 End If
Dec(INDF)
INC(FSR)
If INDF = 0 Then Servo9 = 0 End If
Dec(INDF)
INC(FSR)
If INDF = 0 Then Servo10 = 0 End If
Dec(INDF)
INC(FSR)
If INDF = 0 Then Servo11 = 0 End If
Dec(INDF)
If inc(Frame80) = 16 Then ' finished 15 80us position periods?
CCPR1L = 18800 ' load remaining time for 20ms interrupt
CCPR1H = Hi(18800)
AllOn = Not(AllOn) ' turn all servos ON at next 20ms interrupt
End If
End If
PIR1.CCP1IF = 0 ' clear CCP1 interrupt flag
end sub
sub procedure CCP1_Setup()
CCP1CON = 11 ' CCP1 Compare MODE with special event trigger; resets Timer1 on match
CCPR1L = 65000 ' preload for 65ms delay before servo startup
CCPR1H = Hi(65000)
T1CON = 16 ' Timer1 Prescaler = 2 = 1us ticks
PIE1.CCP1IE = 1 ' Enable CCP1 interrupt
PIR1.CCP1IF = 0 ' Clear CCP1 Interrupt Flag
INTCON = 192 ' Global & Peripheral interrupts enabled
T1CON.TMR1ON = 1 ' Start Timer1
end sub
main:
ANSEL = 0 ' disable adc's
ANSELH = 0 ' disable adc's
CM1CON0 = 0 ' disable comparators
CM2CON0 = 0 ' disable comparators
PORTB = 0
PORTD = 0
TRISB = 0
TRISD = 0
AllOn = True ' All servos ON flag
USART_INIT(19200)
CCP1_Setup()
While true
If USART_DATA_READY = 1 Then ' test for RX byte
t0 = USART_READ ' save new RX byte
t1 = SWAP(t0) And 15 ' extract servo ID from RX byte
ServoPos[t1] = t0 And 15 ' save Position Value per ID
End If
Wend
end.