Servo control with a PIC24F via Output Compare module. Operates in CPU idle mode.
Code:
/*************************************************************************/ /* Program: ServoPWM.c */ /* Author: J. Graham Keggi on 6/19/2009 */ /* */ /* Description: Written in MPLAB C30, and tested on a PIC24FJ16GA002 but */ /* should work for any generic PIC24Fxxxxx. This program contains two */ /* functions, ServoInit() and SetServo() to demonstrate the setup and */ /* use of the Output Compare module to accurately control a servo. */ /* */ /*************************************************************************/ #include "p24FJ16GA002.h" // Or any PIC24Fxxxxxx.h // Declare Prototypes void ServoInit(void); void SetServo(unsigned int position); // Config for Primary Osc, 20Mhz, HS, No CP, No JTAG, No WDT _CONFIG2(IESO_OFF & SOSCSEL_LPSOSC & WUTSEL_LEG & FNOSC_PRI & FCKSM_CSECMD & OSCIOFNC_ON & IOL1WAY_OFF & I2C1SEL_PRI & POSCMOD_HS); _CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & BKBUG_OFF & COE_OFF & ICS_PGx1 & FWDTEN_OFF & WINDIS_OFF & FWPSA_PR128 & WDTPS_PS32768); int main(void) { //Set up oscillator OSCCON = 0x2200; // External Oscillator CLKDIV = 0x0000; // Don't divide the frequency RPOR3bits.RP6R = 22; // Tie Output Compare 5 to physical pin RP6 ServoInit(); // Setup the servo module SetServo(127); // Set the position, 0-farthest cw, 127-centered, 255-farthest ccw Idle(); // Enter low power mode, stops code execution } void ServoInit(void) { OC5CONbits.OCM = 0; // Turn output compare off so we can modify it OC5R = 0x0000; // Load primary register with zero duty cycle OC5RS = 0x0000; // Load secondary register with zero duty cycle OC5CONbits.OCSIDL = 0; // Allow the servo to remain on when CPU is in idle mode OC5CONbits.OCTSEL = 0; // Set Timer2 as clock source OC5CONbits.OCM = 0x6; // PWM mode on OC, Fault pin disabled PR2 = 0x61A7; // Load Timer2 PR2 with 0x61A7 = 0d24999 as PWM cycle of 50Hz IFS0bits.T2IF = 0; // Clear interrupt flag IEC0bits.T2IE = 0; // Disable interrupts T2CONbits.T32 = 0; // 2 16-bit timers, allows use of Timer 3 T2CONbits.TCKPS = 1; // Prescale 1:8 for 20Mhz clock frequency T2CONbits.TON = 1; // Start Timer2 } void SetServo(unsigned int position) { position = (float) position * 7.5; // Scale 0-255 input to 624-3200 for full servo range position += 624; // Scale is adjustable from 0.5ms-2.5ms to servo specs (24999 = 20ms) OC5R = position; // Write primary register OC5RS = position; // Write secondary register }