Servo angle controlled by an analog voltage using dsPIC30F4011

//
// dsPIC30F4011 servo control using output compare
// Written by Ted Burke - last updated 26-2-2014
//
// This dsPIC30F4011 example program controls a
// servo using the output compare module for PWM.
// The duty cycle varies between 1ms and 2ms as
// the analog voltage on AN0 varies between 0 and Vcc.
//
// Analog input is on AN0 (pin 2)
// PWM output is on OC1 (pin 23)
//
 
#include <xc.h>
#include <libpic30.h>
 
// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

unsigned int read_analog_channel(int channel);
 
int main()
{
    // Configure RD0 and RD1 as outputs
    TRISD = 0b1100;
    
    // Configure AN0-AN8 as analog inputs
    ADCON3bits.ADCS = 15;  // Tad = 266ns, conversion time is 12*Tad
    ADCON1bits.ADON = 1;   // Turn ADC ON
    
    // Configure Timer 2 (default timer for output compare)
    T2CONbits.TCKPS = 0b10; // Timer 2 prescaler 1:64
    PR2 = 9375;             // Timer 2 period (20ms)
    T2CONbits.TON = 1;      // Enable Timer 2
 
    // Configure Output Compare channel 1 (OC1)
    OC1CONbits.OCM = 0b101; // continuous pulse mode
    OC1R = 0;               // pulse start time
    OC1RS = min;            // pulse stop time
 
    // Set max and min OC1RS values
    int min = 469;  // OC1RS value for 1ms duty cycle (469 x 64 x Tcy = 1ms)
    int max = 937;  // OC1RS value for 2ms duty cycle (937 x 64 x Tcy = 2ms)
    int range = max - min;
 
    // Now just cycle through the angle positions
    while(1)
    {
        // Read voltage from pin AN0 as a value between 0 and 1023
        v = read_analog_channel(0);
        
        // update servo angle
        OC1RS = min + (range * v / 1023.0);
        
        __delay32(3000000); // 100ms delay
    }
 
    return 0;
}

// This function reads a single sample from the specified
// analog input. It should take less than 5us when the
// microcontroller is running at 30 MIPS.
// The dsPIC30F4011 has a 10-bit ADC, so the value
// returned is between 0 and 1023 inclusive.
unsigned int read_analog_channel(int channel)
{
    ADCHS = channel;          // Select the requested channel
    ADCON1bits.SAMP = 1;      // Start sampling
    __delay32(30);            // 1us delay @ 30 MIPS
    ADCON1bits.SAMP = 0;      // Start Converting
    while (!ADCON1bits.DONE); // Should take 12 * Tad = 3.2us
    return ADCBUF0;
}

To build this example with the XC16 compiler, the following build script can be used. It assumes that the above C code is saved as “main.c”.

xc16-gcc main.c -mcpu=30F4011 -Wl,--script=p30F4011.gld
if errorlevel 0 xc16-bin2hex a.out
Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s