You are on page 1of 4

#include "p30f2020.

h"

_FOSCSEL(PRIOSC_PLL) // This sets up the device for use with external


Crystal in PLL MODE
_FOSC(CSW_FSCM_OFF & HS) // This sets the Oscillator Source
_FWDT(FWDTEN_OFF) // This turns the Watchdog timer off
_FBS(BWRP_WRPROTECT_ON) // Boot Segment is Write Protected
_FGS(CODE_PROT_OFF) //Code Protection is OFF

// Define Global Variables

struct pidParameters
{
float Kp;
float Ki;
float Kd;

signed long int error;


signed long int output;
signed long int outmax;
signed long int ReferenceSetpoint;
signed long int feedback;
signed long int integral;
signed long int derivitive;
signed long int previous_error;
signed long int saturated;
} pidParams;

void setup(void) // Funtion definition for setup of the ADC AND Power PWM Module.
{

PTCONbits.PTEN = 0; // This will disable the PWM Module


PTPER = 15992; // Sets the PWM Period to 16.667u secs (60KHz Switching
Frequency)Period Duration = (PTPER + 1) / 120MHz.

/* Initialize PWM Generator 1 */

IOCON1bits.PENH = 1; // PWM Module controls High output


IOCON1bits.PENL = 1; // PWM Module controls Low output
IOCON1bits.POLH = 0; // High Output Polarity is active High
IOCON1bits.POLL = 0; // Low Output Polarity is active High
IOCON1bits.PMOD = 1; // Independant output mode
IOCON1bits.OVRENH = 0; // High Output Override disabled
IOCON1bits.OVRENL = 0; // Low Output Override disabled

PWMCON1bits.FLTSTAT = 0; // Clear Fault Interrupt flag


PWMCON1bits.CLSTAT = 0; // Clear Current Limit Interrupt flag
PWMCON1bits.TRGSTAT = 0; // Clear PWM Trigger Interrupt flag
PWMCON1bits.FLTIEN = 0; // Disable Fault Interrupt
PWMCON1bits.CLIEN = 0; // Disable Current Limit Interrupt
PWMCON1bits.TRGIEN = 0; // Disable Trigger Interrupt
PWMCON1bits.ITB = 0; // Time base is read from PTMR
PWMCON1bits.MDCS = 0; // Duty cycle is read from PDC
PWMCON1bits.DTC = 2; // No Dead Time
PWMCON1bits.XPRES = 0; // No extenal reset for PTMR
PWMCON1bits.IUE = 0; // Immediate update to PDC
TRGCON1bits.TRGDIV = 2; // Trigger on every 3rd event. That is 50
usecs between successive interations with the system
TRGCON1bits.TRGSTRT = 0; // Start the counting at the start

TRIG1 = 15992; // Trigger event at 16.667 usec from


// start of the PWM cycle

PDC1 = 0; // Initially start with with a 0% Duty Cycle


PHASE1 = 0; // No staggering
FCLCON1 = 0x0003; // Fault Input is disabled
PTCON = 0x8000; // Enable PWM Module

/* Initialize the ADC */

ADCONbits.ADSIDL = 0; // Operate in Idle Mode


ADCONbits.FORM = 0; // Output in Integer Format
ADCONbits.EIE = 1; // Enable Early Interrupt
ADCONbits.ORDER = 0; // Even channel first
ADCONbits.SEQSAMP = 1; // Sequential Sampling Enabled
ADCONbits.ADCS = 4; // Clock Divider is set up for Fadc/12

ADSTAT = 0; // Clear the ADSTAT register


ADPCFG = 0xFFC0; // AN0/AN1, AN2/AN3, AN4/AN5 are analog
inputs
ADCPC0bits.TRGSRC0 = 0x4; // Trigger conversion OF CHANNELS AN0/AN1 on
PWM#1 Trigger
ADCPC0bits.IRQEN0 = 1; // Enable the interrupt

ADCONbits.ADON = 1; // Start the ADC module

/* Set up the Interrupts */

IFS0bits.ADIF = 0; // Clear AD Interrupt Flag


IPC2bits.ADIP = 4; // ADC Interrupt Priority Is Set To 1
IEC0bits.ADIE = 1; // Enable the ADC Interrupt

int main(void)

pidParams.Kp = 0.4;
pidParams.Ki = 0;
pidParams.Kd = 0;

pidParams.outmax = 15992; // The Maximum PWM Value is a function of


frequency
// Max Duty = (Percent *
PTPER) / 100
pidParams.ReferenceSetpoint = 707; //Corresponds to 14.5Volts
pidParams.feedback = 0;
pidParams.integral = 0;
pidParams.derivitive = 0;
pidParams.previous_error = 0;

setup(); // Function Call to setup peripherals

while(1)
{
}
}

// Interrupt Service Routine will read ADC and Update the Duty Cycle Register
// The ISR is Invoked at a 20KHz rate. This 50usecs between updates of the Duty
Cycle Register.

void __attribute__((__interrupt__)) _ADCInterrupt()


{

TRISE = 0xffCf; //Set LED pins E4 and E5 as outputs


LATEbits.LATE5 = 1; // Turn LED ON

IFS0bits.ADIF = 0; // Clear ADC Interrupt Flag


ADSTATbits.P0RDY = 0; // Clear the ADSTAT bits
pidParams.feedback = ADCBUF0; // Get the conversion result
from channel AN0

pidParams.error = pidParams.ReferenceSetpoint - pidParams.feedback; //


This claculated the proportional error

if ((pidParams.error > 2) || (pidParams.error < -2)) // If error is within 2


then do not do the PID Calculation.
{

if (pidParams.saturated == 0) // If the PID controller is


staurated the flag will be 1 and no
// accumulation of
integral/derivitive will be done.
{
if (pidParams.integral < 32000)

{
if (pidParams.integral > -32000)
pidParams.integral += pidParams.error;
}

pidParams.derivitive = pidParams.error -
pidParams.previous_error;

// NOW WE EXECUTE THE ACTUAL PID ALGORITHM

pidParams.output =(pidParams.Kp * pidParams.error


+ pidParams.Ki * pidParams.integral
+ pidParams.Kd * pidParams.derivitive);

// Perform boundary checks on the output of the PID algorithm. If the output limits
are exceeded then, then set output to the limit
// and set flag.

if (pidParams.output > pidParams.outmax)


{
pidParams.saturated = 1;
pidParams.output = pidParams.outmax;
}

else if (pidParams.output < 0)


{
pidParams.saturated = 1;
pidParams.output = 0;
}
else
pidParams.saturated = 0;

pidParams.previous_error = pidParams.error;

PDC1 = pidParams.output; // Update the duty cycle


register

LATEbits.LATE5 = 0;// Turn the LED OFF

}
}

You might also like