We routinely write our own PID functions in ladder using a SLC platform for our industrial hydraulic control applications. I prefer to write my own rather than use a 'canned' function. Most of my PID functions are really PI functions either because the application won't tolerate derivative control, or the lack of an extremely acurate time base coupled with not quote so deterministic I/O can cause instability.
The proportional term is pretty straight forward to calculate.
The integral term is also pretty easy, but this is where I generally customize my routine by including the ability to turn the integrator off and on to prevent wind-up (example, If I am controlling a water regulating valve to control the temperature of the oil in my reservoir, and I know the oil is cold because the machine is just starting up first thing in the morning, I know I have a huge error between my set point and actual values. If I enabled my integrator, it will wind-up in a direction to close the valve and won't start to undwind until after the oil temperature is above my setpoint. To avoid this problem I disable the integrator until the temperature has gotten up to my setpoint at least once and then I enable it. This tends to promote a faster machine warm-up as well. In addition, I typically include limits on my integrator to prevent huge wind-ups, for example I might limit the integral output to 10% maximum. In this manner, the proportional term does most of the coarse adjustment to get the actual term close to the set point, and the integral term is used to tweek the system to reduce the error to zero.
Depending on the application, I will sometimes include a fixed offset or bias term. In the temperature control example, I might bias the water valve open some amount, say 50% for instance. This means that if I turn off the proportional and integral term, the valve will be open 50%, which I determine thru direct observation as the approximate opening required to provide some degree of oil cooling. The proportional and intergal terms will be summed with this bias and act as a venier around this bias value. In this manner my PI portional of the control doesn't have to work as hard to maintain the desired setpoint.
Another trick to a successful 'roll your own' loop control is to prevent insantaneous step changes to the set point. Include some form of 'ramping' function to change the set point over time. We typically make this transparent to the machine operator. The ramp is usually slow enough to prevent huge upsets, but fast enough that the operator can feel he has direct control as he changes the set point.
As John indicated above, you can also play tricks by changing the gains on the fly but this requires very good knowledge on the behaviour of the system. A typical case of when a gain change is required is on a hydraulic press in which the press will initially close on small cylinder areas for high speed and low force, and then switch (via hydraulic valving) to a configuration of large cylinder areas for low speed but very high force. The two configurations require significantly different gains for the same direction of travel. This gets to be a little trickier since it requires a very good understanding of the solenoid valve shift characteristics and system dynamics in order to successfully implement. Typically the gains are not step changed but are instead ramped to provide a smoother transition from one configuration to another.