program SERVO8_10000
'*********************************************************************************
' SERVO8_10000 by Warren Schroeder on October 3, 2006
' Program successfully compiled using mikroBASIC 5.0.0.0
' Tested on 16F877A @ 20MHz
' Servo8_10000 is a demonstration of managing 8 servos every 20ms with more
' than 13-bit position resolution without using inline assembler code.
' You can theoretically achieve 10,000 servo positions per servo if using
' 500us to 2500us range servos and a 20MHz oscillator. Any servo timing range
' is possible up to maximum of 2500us.
'
' Theory of operation is to give each servo an exact 2500us frame to do its
' position duty-cycle. The servo turns ON at the start of the 2500us frame,
' completes its duty-cycle, turns OFF, and then waits for the next frame. At
' the next 2500us frame a new servo is then turned ON and the cycle is repeated.
' Each of the 8 servos occupies a 2500us slot and refreshed sequentially. All
' 8 servos thus require 20ms to complete. At this point, we go back to the first
' servo and repeat this whole process. This method creates exact 20ms periods
' between same servo time frames, which is required for 50Hz servos.
'
' The example below assumes using servos with a timing range of 900us to 2100us
' Timer1 is setup for 0.2us per count (no prescaler @ 20MHz). Therefore, the min
' and max position values for this servo would be 4500 to 10,500. To acheive 90
' degrees of motion, or 1500us, the formula is 1500 x 5 = 7500.
'
' ABOUT USING RX.
' To use RX with USART I recommend using the mB USART library commands. These
' commands do not implement the USART Interrupts and are ideal for this program.
' Put the USART_DATA_READY and USART_READ function in the two wait loops in the
' MAIN program. USART has a 2-byte buffer which will not fill up and is not
' affected by the Timer interrupts as long as you take advantage of reading it
' regularly. Using the two wait loops is the best time to check the RX buffer.
'**********************************************************************************
symbol T1_Switch = T1CON.TMR1ON
symbol T1_Int_Flag = PIR1.TMR1IF
symbol T1_Int_En = PIE1.TMR1IE
symbol T0_Int_Flag = INTCON.TMR0IF
symbol T0_Int_En = INTCON.TMR0IE
const IsEnabled = 1
const IsDisabled = 0
const IsSet = 1
const IsRst = 0
const IsOn = 1
const IsOff = 0
dim intflag as boolean
dim servo as byte
dim T1 as word absolute $0E
dim T0 as byte absolute $01
dim pos as word[8]
sub procedure interrupt
If T0_Int_Flag = IsSet Then ' if Timer0 interrupt
T0 = -196 ' load Frame 196 x 12.8us = 2508us interrupt cycle
Clearbit(PORTB, servo) ' force servo off...in case value was wrong
servo = inc(servo) And 7 ' next servo
Setbit(PORTB, servo) ' turn on next servo
T1 = 0 - pos[servo] ' load servo position...each count is 0.2us
T1_Switch = IsOn ' turn Timer1 On
T1_Int_Flag = IsRst ' reset Timer1 Interrupt Flag
T0_Int_Flag = IsRst ' reset Timer0 Interrupt Flag
Else ' if Timer1 interrupt
Clearbit(PORTB, servo) ' turn off servo
T1_Switch = IsOff ' turn Timer1 Off
End If
intflag = not(intflag) ' interrupt flag status
end sub
main:
TRISB = 0
OPTION_REG = $85 ' Timer0 prescaler = 64 = 12.8us
PORTB = 0
INTCON = $E4 ' GIE, PEIE, Timer0 Enabled; Timer0 Flag Set
T1CON = 0 ' Timer1 Off; No prescaler
For servo = 0 to 7
pos[servo] = 7500 ' set for 1500us mid-point
Next servo
intflag = False
servo = 0
T1 = 0 - 4500 ' load Timer1
T1_Int_Flag = IsRst ' reset Timer1 Interrupt Flag
T1_Int_En = IsEnabled ' Timer1 Interrupt Enabled
T1_Switch = IsOn ' Timer1 On
T0 = -196 ' load TMR0 for 2500us Interrupt Cycle Count
T0_Int_En = IsEnabled ' reset Timer0 Interrupt Flag
Setbit(PORTB, 0) ' turn on first servo
While 1=1
While intflag = False ' WAIT until Timer1 Interrupt
nop ' place USART Read routines in here
Wend
While intflag = True ' WAIT until Timer0 Interrupt
nop ' place USART Read routines in here
Wend
Wend
end.
VVV said:You can use the CCP modules in the PIC16F877A, together with TMR2. Both can be used to produce PWM pulses.
What kind of inverter are you going to design? There are newer parts that can handle the bridge. For example PIC16F690. Check the datasheet.
VVV said:You can use the CCP modules in the PIC16F877A, together with TMR2. Both can be used to produce PWM pulses.
What kind of inverter are you going to design? There are newer parts that can handle the bridge. For example PIC16F690. Check the datasheet.
Nice example and method.xorcise said:I have written tons of 50Hz PWM code for servos. The following might be helpful for some of your own ideas. It runs 8 servos at super high resolution using mikroBasic.
SERVO8_10000 occupies less than 200 ROM and can individually position 8 servos to within 1/10000th of an 180 degree arc +/- 0.1%...if you have such a type of 50Hz servo. Add USART easily and without jitter and interruptions. This code example will work on P16's running @ 20Mhz. It is easily ported to P18's and uses NO INLINE ASSEMBLER.
static unsigned char n = 0;
static unsigned int Pulse [] = { 1500, 1500, 1500, 1500,
1500, 1500, 1500, 1500,
20000 };
static unsigned char Servo = 1;
void isr_hi ()
{
/****************************************************************
* K8LH Crazy-8 Hi-Rez Soft 8-channel (PORTB) Servo Algorithm *
****************************************************************/
if (PIR1bits.CCP1IF == 1) // if CCP1 "compare" interrupt
{ LATB = Servo; // output new Servo pulse and
CCPR1 += Pulse[n]; // setup next "compare" value
PIR1bits.CCP1IF = 0; // clear CCP1 interrupt flag
Pulse[8] -= Pulse[n++]; // adjust end-of-cycle off time
Servo <<= 1; // and prep for next channel
if (n == 9) // if end of a 20-msec cycle
{ n = 0; // reset array index
Pulse[8] = 20000; // reset the 20.0-msec period
Servo++; // reset Servo shadow to Servo 1
}
}
}
Actually you can. Sort of (grin).xorcise said:You cannot get 50Hz (20ms period) from the CCP PWM module, unless you run the PIC with less than 1MHz oscillator.VVV said:You can use the CCP modules in the PIC16F877A, together with TMR2. Both can be used to produce PWM pulses.
What kind of inverter are you going to design? There are newer parts that can handle the bridge. For example PIC16F690. Check the datasheet.
unsigned char select = 0; // Servo channel number, 0..7
unsigned char frame = 10; //
unsigned int pulse1;
/* *
* Servo[] array elements contain Servo pulse width values in *
* the range of 3000..9000 (250-nsec 'ticks') which represent *
* extended Servo pulse width ranges of 750 to 2250-usecs *
* */
static unsigned int Servo [] = { 6000, 6000, 6000, 6000,
6000, 6000, 6000, 6000 };
/*****************************************************************
* K8LH 8-Channel 74HC238 Hi-Rez 'PWM' Servo Algorithm Example *
*****************************************************************/
#pragma interrupt isr_hi
void isr_hi ()
{ if(PIR1bits.TMR2IF)
{ PIR1bits.TMR2IF = 0; // clear TMR2 interrupt flag
/**************************************************************
* setup 74HC238 address lines and our work variables for *
* the next servo channel interval during the final (10th) *
* frame of the current servo channel interval (the final *
* frame in each interval will always have a 0% duty cycle *
* and all 74HC238 outputs are 'off' so it will be safe to *
* change the address lines) *
* */
if(frame == 10) // 10 PWM frames/Servo interval
{ frame = 0; // reset PWM frame number
select %= 8; // 8 Servo intervals/20-msec cycle
pulse1 = Servo[select]; // setup 'pulse' work variable
LATB = (LATB & 0b11111000) | select; // set address lines
select++; // preset for next interval
}
frame++; // bump for next interrupt
/**************************************************************
* setup CCP1 PWM duty cycle for next 250-usec PWM 'frame' *
* */
if(pulse1 > 1000) // if pulse1 > 250-usecs
{ CCPR1L = 250; // do a 100% duty cycle frame
pulse1 -= 1000; // subtract 250-usecs
}
else // do a variable or 0% frame
{ CCP1CONbits.CCP1Y = (pulse1 & 1);
CCP1CONbits.CCP1X = (pulse1 & 2);
CCPR1L = (pulse1 >>= 2);
pulse1 = 0; // remaining frames are %0
}
}
}
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?