PID using C


Thread Starter


I was just wondering if anyone had implemented a pid controller using C.The idea is that the C program allows me to vary the values of P,I and D values thus allowing me to use it for a number of different applications, Can it be done???. If so could someone please help with the code. The code will then be used on the 8051 microcontroller. I am a college student so need as much help as possible.!!

Below is a simplified series type PID. It uses normalized variables. No auto/manual, set point tracking, direct reverese action changing has been provided make it fairly easy to follwow. Pointers are passed for the error, proportional,
integral and derivative components so that they can be monitored independantly to give you insight into what the PID is doing.

Len Klochek

float Series_PID(float process, float set_point, float gain, float integral_time,
float derivative_time,float sample_time, float *return_error, float
*return_integral, float *return_derivative )

float error, derivative, con_out=0.5;
static float integral=0.5, olderror, output;

/* integral limiting switch - limiter=0 disables integral*/
int static limiter=1;

error = set_point - process;

integral = integral + sample_time*limiter*gain*error/integral_time;

if ( output >=1&error>0|output<=0&error<0|integral_time>60)
limiter = 0;
limiter = 1;

derivative = derivative_time*gain*(error-olderror)/sample_time;
output = gain*error + integral + derivative;

*return_error = error;
*return_integral = integral;
*return_derivative = derivative;

if(output<0) output = 0;
if(output>1) output = 1;

return output;

Johan Bengtsson

This subject and similar have been up before, several times, so you might want to serach the archives as well...

However, one of the smallest possiblem implementations goes something like this:

if (Ppart>0 && out<maxOut || Ppart<0 && out>minOut)

gain - the proportional gain of the controller (P)
Itime - the integral time of the controller (I)
Dtime - derivate time of the controller (D)
setpoint - desired value of processValue
processValue - the controlled value from the process
maxOut - the maximum allowed output value
minOut - the minimum allowed output value
timeStep - time between calculations
leadQuote - extra low pass filter for the D part, usually 10 or similar

values needed to retain between calculations
Dfilter - a value needed in order to do the filtering of the D part
Ipart - integrated value
out - the output is used backwards to determine if the I part is allowed to work

All times should be in the same time unit (whatever you feel like using)
Itime, Dtime and timeStep

You are of course not allowed to divide by 0, so if you don't want to use the D part of the controller you have to skip some lines of code

This implementation makes derivation on the control error, something you want in some cases but most often not recomended. This only makes a difference when the setpoint changes. If a parameter is changed or when you transfer from manual to auto you generally don't want the output to change by a large value immediately, this is not taken care of in the code above.

The test before increasing Ipart provides antiwindup. When the controller output can't be changed or it by any other reason isn't possible to further change the physical output in the desired direction the I part should be temporary shut of until it is possible again.

If you want to implement this using integer math, make sure you use a suitable scale for your values. The bigger the better generally, but you
should be aware if any value is in risk of wrapping around. If it is possible to use floating point math it is safer but probably a lot slower in processors like this.

/Johan Bengtsson

Do you need education in the area of automation?
P&L, Innovation in training
Box 252, S-281 23 H{ssleholm SWEDEN
Tel: +46 451 49 460, Fax: +46 451 89 833
E-mail: [email protected]

Ronald Nijssen

Hi Martin,

You can of course create a PID controller as a function in C. You should pass all its properties, including Gain, Int, and Reset as arguments with your function call. These properties should be stored in some global memory
that's part of your main() function. Simply declare multiple variables with appropriate values and call the PID function multiple times.
It shouldn't be difficult to find a PID algorithm on the web to implement the actual code inside the function


Johan Bengtsson

Good, except for the fact that this isn't an implementation of a serial PID but rather the one called ideal or in some cases parallell

That does not mean don't use this, rather the opposite. This is the reccomended for new PID implementations.

There are two other small implementation issues, you can't call this funcion twice in the same program to control two different process values since it uses static variables inside the function. This is not a problem if you ever use only one PID in your programs but watch out if you need two or more. The other one is that there really should be a separate low pass filter on the derivative part otherwise it would most probably produce an output signal too noisy for good use. Of course it can work without this but I reccomend there to be one.

(The use of a separate filter on the D part does not mean you don't need a proper anti-aliasing filter implemented with analog components before
your A/D converter, of course)

/Johan Bengtsson

Do you need education in the area of automation?
P&L, Innovation in training
Box 252, S-281 23 H{ssleholm SWEDEN
Tel: +46 451 49 460, Fax: +46 451 89 833
E-mail: [email protected]
reverse action --- calculate error as Set Point - Process Variable.
direct action --- calculate error as Process Variable - Set Point

or leave error calculation as Set Point - Process Variable and change the sign of the gain term to change action.

Len Klochek