PI controller using PIC micro

Status
Not open for further replies.

biswaIITH

Full Member level 4
Joined
Aug 23, 2014
Messages
205
Helped
27
Reputation
54
Reaction score
28
Trophy points
1,308
Location
Hyderabad
Visit site
Activity points
2,923
Hello folks ...i am trying to implement PI controller using PIC16F876A...Following is the code,i am using..I am applying approx 4.55V to VDD...Applying 4v to channel 1 of ADC as a reference


Code:
int err_val=0,I_err=0;
int current_duty_2=10;
int Kp=1,Ki=1;
int P_term=0,I_term=0;
int Sum_err=0;
unsigned int ADCRead(unsigned int channel)
{
 unsigned int l_byte, h_byte;
 unsigned int ADR;
 ADCON0 = 0x81 | (channel << 3);
 delay_us(30);
 ADCON0.F2 = 1;
  while(ADCON0.F2);
   l_byte = ADRESL;
   h_byte = ADRESH;
   ADR = h_byte;
   return (ADR);
}

void main(void)
{
  unsigned int Ch0,Ch1;
  TRISA = 0xFF;
  ADCON0 = 0x81;
  ADCON1 = 0x40;
  TRISC.F1=0;
  PWM2_Init(25000);
  PWM2_Start();
  PWM2_Set_Duty(current_duty_2);

  while(1)
  {
    Ch0= ADCRead(0);
    Ch1= ADCRead(1);
    err_val=(Ch1-Ch0);
    P_term=(Kp*err_val);
    I_err=I_err+err_val;
    I_term=(Ki*I_err);
  if(I_term>30000)
    I_term=30000;
  else if(I_term<-30000)
    I_term=-30000;
    Sum_err=(P_term+I_term);
********************************************
  if(Sum_err>245)
    Sum_err=245;
  else if(Sum_err<0)
    Sum_err=0;
    current_duty_2=Sum_err;
    PWM2_Set_Duty(current_duty_2);
}
}

DOUBTS
1)Is the above code ok as far as implementation of PI controller is concerned???I consulted one senior with this code..He told me the above code will have varying sampling frequency..How to fix that????
2)The line Sum_err=(P_term+I_term); will have 16 bit result in it...But, i am planning to use lower 8 bit of it(as the library functions in mikroC PRO i am using can handle upto 8 bit) ..How to do that???
 
Last edited:

1. If your PIC is not going to do anything else besides beeing this PID... I suggest you to use a Timer flag to synchronize the ADC readings... for that, you need some idea of how much time it takes to process all this program... (for example, add a togglin led, and check with a oscilloscope the minimum and maximum time it takes to perform the process; and use the Timer to overflow (or use an spare CCP to compare) at a little higher time.. (for example if you see in your oscilloscope a variation from 7.5ms to 8.5ms better be safe and configure the timer to overflow every 10ms, with that you can estimate a fixed sampling of 100Hz). you wait for the flag, then perform the process, and clear the flag, so you wait for it again...

If your pic need to do small things like showing in a LCD or serial to PC and you don't mind taking more time between tasks, you can still synchronize everything with the timer.
If your pic is destined to do higher and mightier things than this PID, the common approach is to use the Timer Interrupt to synchronize the ADC readings and the rest of the mathz...

2.for this you need to perform more tests, and some info about your process... let's assume it's something slow like a heather PWM-controlled and some kind of temperature sensor... in this kind of process the I_term WILL and NEED TO get a high value to maintain the output according the historical response in time... (and the P_term is used only to kickstart before stabilization...) so, yeah the Sum_err could get a high number and here comes the real magic...

in the math world your error should be between -1 to 1 (+-100%) and your output between -1 to 1 (again +-100%) with your Coefficients KP and KI should be values between 0.00 to 1.00 .... so the common way to do this in integers is by doing fixed point math, as you are doing here right?

the last step you are missing is converting the ideal output value [-1, 1] to a PWM value from 0 to 255 (also I think you don't have a heat pump or cooler to work when this values goes from 0 to -1, so limit also the Sum_err to positive values)...

for you, I suggest to try to guess the value Sum_err could get... (for example in 10 seconds) it gets to 30000 (your upper limit for I_err) and that value should output the PWM to its 100% so just divide 30000/118 =254 (close enough with integer math) soooo your magic number is 118 for now...

I have seen people getting pedantic with the math associated with a PID controller and started using float math and failing miserably by forgetting ADC scaling, negative readings, DC bias, sampling phases, output delay, and a list of stuff for a very simple task... and don't talk about PID tunning...

Maaaybe look in your compiler about Long ints (like 32 bits) for stuffing the I_err accumulator... and try to figure a better upper limit (again i suggest you to limit the lower value to 0 if this is a temperature case) and reuse that value to get a better magic number to convert to 0-255 (8 bit) number...
 

    V

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…