A handy “super example” for the dsPIC30F4011

This is a handy “super example” for the dsPIC30F4011, which uses several features of the microcontroller:

  • Sets all Port D pins as outputs (I have LEDs connected to all four).
  • Toggles an LED on RD0 every 200ms approx.
  • Configures AN0-AN8 as analog inputs.
  • Enables all three PWM channels in complimentary mode, with period set to 20 ms (suitable for servo control).
  • Configures the UART for printing analog voltage read on AN0
  • Characters are also read via UART to control some of the outputs: “2” toggles RD2, “3” toggles RD3, “s” steps the servo angle on PWM channel 1.
  • Configures the Timer 1 interrupt to call an interrupt service routine every 125ms.

When using this as template code for a new project, just delete the featured you don’t need and edit the ones you do.

//
// dsPIC30F4011 Super Example
// Written by Ted Burke
// Last updated 19-10-2017
//
// Featuring digital i/o, analog input,
// PWM output, UART Tx/Rx, Timer 1 ISR.
//
 
#include <xc.h>
#include <stdio.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
 
// Function prototype for analog read function
unsigned int analogRead(int);
 
// Function prototype for Timer 1 interrupt service routine
void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void);
 
int main()
{
    double pw;   // Pulse width for servo (min 1ms, max 2ms)
    int voltage; // Analog voltage read which will be read from AN0
    char c;      // The char data type is basically just an 8-bit int
 
    ///////////////////////////////////////////////////////////////
    // Set up digital i/o, analog input, PWM, UART and interrupt //
    ///////////////////////////////////////////////////////////////
    
    // Configure all 4 port D pins as digital outputs
    TRISD = 0;
 
    // Configure AN0-AN8 as analog inputs
    ADCON3bits.ADCS = 15;  // Tad = 266ns, conversion time is 12*Tad
    ADCON1bits.ADON = 1;   // Turn ADC ON
 
    // Configure PWM for free running mode
    //
    //   PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * PTPER
    //   PWM pulse width = (Tcy/2) * prescale * PDCx
    //
    PWMCON1 = 0x00FF;     // Enable all PWM pairs in complementary mode
    PTCONbits.PTCKPS = 3; // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
    PTPER = 9375;         // 20ms PWM period (15-bit period value)
    PDC1 = 937;           // 1.0ms pulse width on PWM channel 1
    PDC2 = 937;           // 1.0ms pulse width on PWM channel 2
    PDC3 = 937;           // 1.0ms pulse width on PWM channel 3
    PTMR = 0;             // Clear 15-bit PWM timer counter
    PTCONbits.PTEN = 1;   // Enable PWM time base
 
    // Setup UART
    U1BRG = 48;            // 38400 baud @ 30 MIPS
    U1MODEbits.UARTEN = 1; // Enable UART
 
    // Configure Timer 1
    // In this example, I'm setting PR1 and TCKPS for 8Hz
    PR1 = 14648;          // Set the Timer 1 period (max 65535)
    TMR1 = 0;             // Reset Timer 1 counter
    IEC0bits.T1IE = 1;    // Enable Timer 1 interrupt
    T1CONbits.TCKPS = 3;  // Prescaler (0=1:1, 1=1:8, 2=1:64, 3=1:256)
    T1CONbits.TON = 1;    // Turn on Timer 1

    ///////////////////////
    // Main control loop //
    ///////////////////////
    
    while(1)
    {
        // Read a voltage from AN0 and print it via serial port
        voltage = analogRead(0);
        printf("Voltage = %d\r\n", voltage);
 
        // Toggle LED on RD0
        _LATD0 = 1 - _LATD0;
 
        // Check if any characters were received via UART
        if (U1STAbits.URXDA == 1)
        {
            c = U1RXREG;                       // read the character
            if (c == '2') _LATD2 = 1 - _LATD2; // toggle RD2 on/off
            if (c == '3') _LATD3 = 1 - _LATD3; // toggle RD3 on/off
            if (c == 's') pw = pw + 0.2;       // increase the servo angle
        }
        
        // Set servo angle by setting pulse width on PWM channel 1
        if (pw > 2.0) pw = 1.0;
        PDC1 = pw * 937.5; // Note: 937.5 units is equivalent to 1ms
 
        __delay32(6000000); // 200ms delay
    }
 
    return 0;
}
 
// Timer 1 interrupt service routine
void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void)
{
    // Clear Timer 1 interrupt flag
    IFS0bits.T1IF = 0;
 
    // Toggle LED on RD1
    _LATD1 = 1 - _LATD1;
}
  
// 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 analogRead(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;
}

This is the build script I’m using:

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.

One Response to A handy “super example” for the dsPIC30F4011

  1. Pingback: **OTHER MOTOR 1** DC Motor – Laurence Keighery

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