JF1980
Feb 25, 2009, 11:20 AM
Hi all,
I've been trying to move some servos around with a PIC 16F877A. I understand the principles of driving a servo but my code doesn't seem to work -- being a 'C' newbie I suspect I may have made a few coding errors although the program compiles. I'm using two CCP modules to generate servo on/off interrupts.
Hopefully someone can tell me what I've done wrong:
/*
* Project name:
MoveServo1
* Description:
Move Servo with TMR0/1 Interrupts.
* Test configuration:
MCU: PIC16F877A
Dev.Board: EasyPic4
Oscillator: HS, 08.000 MHz
Ext. Modules: -
SW: mikroC v7.0
* NOTES:
Drive up to 8 servos on PortB using CCP1, CCP2 and TMR1
Configure TMR1 for 1us ticks
CCP1 is set up for special event on match with TMR1
CCP1 is loaded with servo cycle length = 20000us / number of servos; 2500us for 8 servos. It triggers an interrupt and resets TMR1.
CCP1 triggers every servo cycle resetting TMR1, moves program to next servo via single left bitshift, turns turns that servo on.
CCP2 is set up for a normal event which does not reset the timer.
CCP2 value is loaded from the servo position array when the servo is switched on via CCP1 interrupt service.
CCP2 triggers when the servo-on cycle has been completed.
CCP2 interrupt service switches off servo output (all of PORTB) and clears the CCPIR2.0 interrupt flag.
*/
// Define variables
#define ServoOnIntEnable PIE1.F2
#define ServoOnFlag PIR1.F2
#define ServoOffIntEnable PIE2.F0
#define ServoOffFlag PIR2.F0
//#define ServoPeriod CCPR1L
//#define ServoDuty CCPR2L
unsigned int volatile ServoPeriod absolute 0x0015; // CCPR1L
unsigned int volatile ServoDuty absolute 0x001B; // CCPR2L
unsigned int Servo[8]; // servo position array
unsigned int xx ; // var for test loop
unsigned short Servo_Output; // Shadow register for Output
unsigned short sn ; // Servo number, to ref Servo array
// Define functions
void init(void) ;
// Main
void main(void) {
init();
while (1) {
for (xx = 350; xx <= 2400; xx++){ // cycle servos
Servo[0] = 500;
Servo[1] = xx;
Servo[2] = xx;
Servo[3] = xx;
Servo[4] = xx;
Servo[5] = xx;
Servo[6] = xx;
Servo[7] = 2400;
Delay_us(5500);
}
}
}
// Setup CPU
void init(void) {
PORTB = 0 ; // servo port is portB
TRISB = 0 ; // set portB as output
T1CON = 0b00010000 ; // prescaler = 2 = 1us ticks ; timer1 off
TMR1L = 0 ; // Timer1L starts at 0
TMR1H = 0 ; // Timer1H starts at 0
CCP1CON = 0b00001011 ; // CCP1 triggers special compare event on Timer1 match
CCP2CON = 0b00001010 ; // CCP2 normal compare event on Timer1 match
ServoPeriod = 2500 ; // special event interrupt every 2500us; jumps to ServoON ISR
Servo_Output = 0b00000001 ; // servo outputs start at PORTB.F0, then shift and rotate
sn = 0 ; // start with servo(0)
INTCON = 0b11000000 ; // enable GIE and PEIE
ServoOnFlag = 0 ;
ServoOffFlag = 0 ;
ServoOnIntEnable = 1 ;
ServoOffIntEnable = 1 ;
T1CON.F0 = 1; // start Timer1
}
// Interrupt
void interrupt(void) {
if (ServoOnFlag == 1) { // CCP1 Special Compare Event Interrupt
PortB = Servo_Output ; // Turn On Next Servo
ServoDuty = Servo[sn] ; // Active Servo Value loaded in CCPR2
Servo_Output = Servo_Output << 1 ; // Prepare Servo_Output for next cycle with bitshift
sn++ ;
//sn = sn And 7 ;
sn = sn & 7 ;
ServoOnFlag = 0 ;
}
else { // CCP2 Normal Compare Event Interrupt
PORTB = 0 ; // Turn Off Active Servo
ServoOffFlag = 0 ;
}
}
I've been trying to move some servos around with a PIC 16F877A. I understand the principles of driving a servo but my code doesn't seem to work -- being a 'C' newbie I suspect I may have made a few coding errors although the program compiles. I'm using two CCP modules to generate servo on/off interrupts.
Hopefully someone can tell me what I've done wrong:
/*
* Project name:
MoveServo1
* Description:
Move Servo with TMR0/1 Interrupts.
* Test configuration:
MCU: PIC16F877A
Dev.Board: EasyPic4
Oscillator: HS, 08.000 MHz
Ext. Modules: -
SW: mikroC v7.0
* NOTES:
Drive up to 8 servos on PortB using CCP1, CCP2 and TMR1
Configure TMR1 for 1us ticks
CCP1 is set up for special event on match with TMR1
CCP1 is loaded with servo cycle length = 20000us / number of servos; 2500us for 8 servos. It triggers an interrupt and resets TMR1.
CCP1 triggers every servo cycle resetting TMR1, moves program to next servo via single left bitshift, turns turns that servo on.
CCP2 is set up for a normal event which does not reset the timer.
CCP2 value is loaded from the servo position array when the servo is switched on via CCP1 interrupt service.
CCP2 triggers when the servo-on cycle has been completed.
CCP2 interrupt service switches off servo output (all of PORTB) and clears the CCPIR2.0 interrupt flag.
*/
// Define variables
#define ServoOnIntEnable PIE1.F2
#define ServoOnFlag PIR1.F2
#define ServoOffIntEnable PIE2.F0
#define ServoOffFlag PIR2.F0
//#define ServoPeriod CCPR1L
//#define ServoDuty CCPR2L
unsigned int volatile ServoPeriod absolute 0x0015; // CCPR1L
unsigned int volatile ServoDuty absolute 0x001B; // CCPR2L
unsigned int Servo[8]; // servo position array
unsigned int xx ; // var for test loop
unsigned short Servo_Output; // Shadow register for Output
unsigned short sn ; // Servo number, to ref Servo array
// Define functions
void init(void) ;
// Main
void main(void) {
init();
while (1) {
for (xx = 350; xx <= 2400; xx++){ // cycle servos
Servo[0] = 500;
Servo[1] = xx;
Servo[2] = xx;
Servo[3] = xx;
Servo[4] = xx;
Servo[5] = xx;
Servo[6] = xx;
Servo[7] = 2400;
Delay_us(5500);
}
}
}
// Setup CPU
void init(void) {
PORTB = 0 ; // servo port is portB
TRISB = 0 ; // set portB as output
T1CON = 0b00010000 ; // prescaler = 2 = 1us ticks ; timer1 off
TMR1L = 0 ; // Timer1L starts at 0
TMR1H = 0 ; // Timer1H starts at 0
CCP1CON = 0b00001011 ; // CCP1 triggers special compare event on Timer1 match
CCP2CON = 0b00001010 ; // CCP2 normal compare event on Timer1 match
ServoPeriod = 2500 ; // special event interrupt every 2500us; jumps to ServoON ISR
Servo_Output = 0b00000001 ; // servo outputs start at PORTB.F0, then shift and rotate
sn = 0 ; // start with servo(0)
INTCON = 0b11000000 ; // enable GIE and PEIE
ServoOnFlag = 0 ;
ServoOffFlag = 0 ;
ServoOnIntEnable = 1 ;
ServoOffIntEnable = 1 ;
T1CON.F0 = 1; // start Timer1
}
// Interrupt
void interrupt(void) {
if (ServoOnFlag == 1) { // CCP1 Special Compare Event Interrupt
PortB = Servo_Output ; // Turn On Next Servo
ServoDuty = Servo[sn] ; // Active Servo Value loaded in CCPR2
Servo_Output = Servo_Output << 1 ; // Prepare Servo_Output for next cycle with bitshift
sn++ ;
//sn = sn And 7 ;
sn = sn & 7 ;
ServoOnFlag = 0 ;
}
else { // CCP2 Normal Compare Event Interrupt
PORTB = 0 ; // Turn Off Active Servo
ServoOffFlag = 0 ;
}
}