I am trying to implement a PI controller in C that outputs / controls a PWM's duty cycle on a microcontroller. The duty cycle that I can write to the certain PWM control register is limited to 10bit (values 0 - 1023 correspond to 0% - 100% duty cycle). My controllers output "Stell", that should correspond to a duty cycle, exceeds this bit limit due to calculations of the controlled values. Here is a simplified version of my controller function that is called regularly with a base clock:
void controller(void)
{
int32_t stell_1, stell_2, stell;
int32_t Integral;
int16_t delta_e;
uint32_t DZSoll, DZIst;
uint16_t duty_cycle;
int32_t temp_duty_cycle;
//Error = Setpoint - actual_value
delta_e = DZSoll - DZIst;
//PI controller
stell_1 = delta_e * Kp;
Integral += delta_e;
stell_2 = Ki * Integral;
stell = stell_1 + stell_2;
//Max values
Max_S1 = Max_delta_e * Kp;
Max_S2 = (Max_delta_e + Integral) * Ki;
Max_Stell = Max_S1 + Max_S2;
//Scaling of the controller output to a 10bit duty cycle
temp_duty_cycle = stell<<10; //*1023
duty_cycle = temp_duty_cycle/Max_Stell;
PWMUpdate(duty_cycle);
//...
}
Now, I thought that I would need to scale the controller output "Stell" to the desired 10bit "duty cycle" by setting them into a relation: duty_cycle/2^10 = Stell/Max_Stell (basically to receive the scaling factor). Nevertheless, this only works for positive values of "stell" as my duty cycle by definition has to be a positive value (uint16_t). In the case that my actual value "DZIst" is bigger that the setpoint "DZSoll" (for instance on a overshoot of the integral part of the PI controller), this results in a negative "Stell" which is then incorrectly calculated into a duty cycle. This is especially a problem on lower setpoints as the Integral value cannot compensate the negative control error.
Am I scaling "Stell" correctly to the 10bit duty cycle? Could I compensate the negative "Stell" values with an offset (and how?)?