Necesita manejar dos problemas:
- desbordamiento aritmético
- enrollador integrador
El desbordamiento aritmético es bastante sencillo: siempre que esté haciendo matemática entera, asegúrese de usar valores intermedios de mayor ancho: por ejemplo, si a y bson 16 bits, y los suma / resta, use un intermedio de 32 bits valor y limítelo al rango de un valor de 16 bits (0 a 65535 para sin signo, -32768 a 32767 para firmado) antes de volver a reducir a 16 bits. Si está absolutamente seguro de que nunca puede obtener un desbordamiento, porque está absolutamente seguro de los rangos de las variables de entrada, puede omitir este paso, pero tenga cuidado.
El problema del integrador windup es más sutil. Si tiene un gran error durante un período prolongado de tiempo, de modo que alcance el límite de saturación de la salida del controlador, pero el error sigue siendo distinto de cero, entonces el integrador seguirá acumulando el error, posiblemente haciéndose mucho más grande de lo que debería para lograr estado estable. Una vez que el controlador sale de la saturación, el integrador tiene que volver a bajar, causando demoras innecesarias y posiblemente inestabilidad en la respuesta de su controlador.
En otra nota:
Recomiendo encarecidamente (sí, sé que esta pregunta tiene 18 meses de edad, por lo que probablemente haya terminado su tarea, pero para beneficio de los lectores, supongamos que no lo es) que calcule el término integral de manera diferente: en lugar de Ki * (error integrado), calcule la integral de (Ki * error). 
Hay varias razones para hacerlo; puede leerlos en una publicación de blog que escribí sobre cómo implementar los controladores PI correctamente .
                 
                
                
                
               
        
<stdint.h>foruint8_tyuint16_t, en lugar deunsigned intyunsigned char.unsignedvariables para un controlador PI? Esto agrega mucha complejidad a su código; losif/elsecasos separados son innecesarios (a menos que use ganancias diferentes dependiendo del signo de error) También está usando el valor absoluto de la derivada, que es incorrecto.PID_derivativeasignación; obtienes el mismo valor si cambiasPID_erroryPID_lastError. Y para el caso que ya ha perdidoPID_errorsigno 's: si la última vezsetMotorSpeed =8ycurrentMotorSpeed = 15, y esta vezsetMotorSpeed = 15ycurrentMotorSpeed = 8, a continuación, obtendrá unPID_derivativevalor de 0, lo cual es incorrecto.unsigned chares un tipo de 8 bits yunsigned intes de 16 bits: siPID_kd = 8yPID_derivative = 32, entonces su producto será(unsigned char)256 == 0, porque en C, el producto de dos enteros del mismo tipo T también es de ese tipo mismo tipo T. Si desea hacer una multiplicación 8x8 -> 16, debe convertir uno de los términos en un número de 16 bits sin signo antes de la multiplicación, o utilizar un compilador intrínseco (MCHP los llama "incorporados") diseñados para darte una multiplicación de 8x8 -> 16.