All that control for only 530 ROM!
Code: Select all
program SERVO30_18F452
'**********************************************************************
'****** ******
'****** 30 Servo Driver @ 256 Positions using P18 @ 40MHz ******
'****** by W. Schroeder on July 22, 2006 ******
'****** REVISED on Sept 19, 2006..added USART & code tweaks ******
'****** Compiled with mikroBASIC 5.0.0.1 & Tested on 18F452 ******
'****** ******
'****** Servo routines use only ~2.5ms of 20ms cycle ******
'****** This ensures enough time for changing servo values ******
'****** ******
'****** USART is used for communicating new servo values to ******
'****** the PIC. It is important that the PIC initiate this ******
'****** communication with the PC. Therefore, PC software ******
'****** must regularly scan the Comm Port for receipt of a ******
'****** an initiate-communication signal. The PC will send ******
'****** exactly 30 bytes which represent the servo values. ******
'****** ******
'**********************************************************************
' These are the port pin assignments for the servo array:
' servo[0]- PORTA.0
' servo[1]- PORTA.1
' servo[2]- PORTA.2
' servo[3]- PORTA.3
' servo[4]- PORTA.5 <-- note: skips RA4 open-drain output
' servo[5]- PORTB.0
' servo[6]- PORTB.1
' servo[7]- PORTB.2
' servo[8]- PORTB.3
' servo[9]- PORTB.4
' servo[10]-PORTB.5
' servo[11]-PORTB.6
' servo[12]-PORTB.7
' servo[13]-PORTC.0
' servo[14]-PORTC.1
' servo[15]-PORTC.2
' servo[16]-PORTC.3
' servo[17]-PORTC.4
' servo[18]-PORTC.5
' servo[19]-PORTD.0
' servo[20]-PORTD.1
' servo[21]-PORTD.2
' servo[22]-PORTD.3
' servo[23]-PORTD.4
' servo[24]-PORTD.5
' servo[25]-PORTD.6
' servo[26]-PORTD.7
' servo[27]-PORTE.0
' servo[28]-PORTE.1
' servo[29]-PORTE.2
'********************************************************************
dim aa, pos, tmp as byte
dim tmr as word
dim servo as byte[30]
sub procedure interrupt
LATA = 63 ' turn on all servos on PortA
LATB = 255 ' turn on all servos on PortB
LATC = 63 ' turn on all servos on PORTC
LATD = 255 ' turn on all servos on PortD
LATE = 7 ' turn on all servos on PORTE
pos = 0 ' manage outputs with 256 positions each
delay_us(500)
ASM ' VERY efficient PWM masking routine
movlw 0
decfsz _servo+0, 1,0
iorlw 1
decfsz _servo+1, 1,0
iorlw 2
decfsz _servo+2, 1,0
iorlw 4
decfsz _servo+3, 1,0
iorlw 8
decfsz _servo+4, 1,0
iorlw 32
andwf LATA, 1,0
movlw 0
decfsz _servo+5, 1,0
iorlw 1
decfsz _servo+6, 1,0
iorlw 2
decfsz _servo+7, 1,0
iorlw 4
decfsz _servo+8, 1,0
iorlw 8
decfsz _servo+9, 1,0
iorlw 16
decfsz _servo+10, 1,0
iorlw 32
decfsz _servo+11, 1,0
iorlw 64
decfsz _servo+12, 1,0
iorlw 128
andwf LATB, 1,0
movlw 0
decfsz _servo+13, 1,0
iorlw 1
decfsz _servo+14, 1,0
iorlw 2
decfsz _servo+15, 1,0
iorlw 4
decfsz _servo+16, 1,0
iorlw 8
decfsz _servo+17, 1,0
iorlw 16
decfsz _servo+18, 1,0
iorlw 32
andwf LATC, 1,0
movlw 0
decfsz _servo+19, 1,0
iorlw 1
decfsz _servo+20, 1,0
iorlw 2
decfsz _servo+21, 1,0
iorlw 4
decfsz _servo+22, 1,0
iorlw 8
decfsz _servo+23, 1,0
iorlw 16
decfsz _servo+24, 1,0
iorlw 32
decfsz _servo+25, 1,0
iorlw 64
decfsz _servo+26, 1,0
iorlw 128
andwf LATD, 1,0
movlw 0
decfsz _servo+27, 1,0
iorlw 1
decfsz _servo+28, 1,0
iorlw 2
decfsz _servo+29, 1,0
iorlw 4
andwf LATE, 1,0
nop
nop
nop
nop
nop
incfsz _pos, 1,0
bra $-76
END ASM ' these routines have used ~2500us to this point
TMR0H= Hi(-5438) ' balance of time for 20ms cycle (=17.5ms)
TMR0L = -5438
INTCON.TMR0IF = 0 ' clear interrupt flag
aa = 1
end sub
sub procedure _init
LATA = 0
LATB = 0
LATC = 0
LATD = 0
LATE = 0
TRISA = 0
TRISB = 0
TRISC = 0
TRISD = 0
TRISE = 0
ADCON1 = 7
T0CON = %00000100 ' prescaler = 32 or 3.2us per increment
TMR0H = -2 ' load high byte first
TMR0L = 0 ' load low byte second
INTCON = %10100000 ' Timer0 Interrupt Enabled and Flag Cleared
T0CON.7 = 1 ' Timer0 On
aa = 0
end sub
main:
_init
USART_Init(19200) ' 19200 should be minimum speed...faster is better
' communicate with PC every 20ms
While true
If aa = 1 Then ' interrupt occurred?...time to check for new servo values
aa = 0 ' prepare for next interrupt
USART_Write(128) ' send some value to get PC's attention
For tmp = 0 to 29 ' get 30 servo values from PC
While USART_DATA_READY = 0 ' wait until Usart Read buffer has a byte
If inc(tmr) = 0 Then Break End If
Wend
servo[tmp] = USART_Read + 1 ' store servo value
Next tmp ' servo data transfer should complete in ~15ms @ 19200 baud
End If
Wend
end.