Soy nuevo en la programación en C. Necesito su ayuda para comprender algunas líneas particulares en un segmento de código para el control sensorizado de un motor de CC sin escobillas. Fue escrito para una MCU de 16 bits (dsPIC33FJ32MC710). Esta sección en particular es de la rutina de servicio de interrupción y contiene dos ISR. ¿ Puede explicarme con palabras sencillas las líneas marcadas con //???
? ¿Qué se está haciendo allí y por qué? Cualquier otro comentario también es bienvenido.
int DesiredSpeed;
int ActualSpeed;
int SpeedError;
long SpeedIntegral = 0, SpeedIntegral_n_1 = 0, SpeedProportional = 0;
long DutyCycle = 0;
unsigned int Kps = 20000; // Proportional gain
unsigned int Kis = 2000; // Integral gain
void __attribute__((interrupt, no_auto_psv)) _T1Interrupt (void)
{
#ifdef CLOSEDLOOP
ActualSpeed = SPEEDMULT/timer3avg;
SpeedError = DesiredSpeed - ActualSpeed;
SpeedProportional = (int)(((long)Kps*(long)SpeedError) >> 15); // ???
SpeedIntegral = SpeedIntegral_n_1 + (int)(((long)Kis*(long)SpeedError) >> 15); //???
SpeedIntegral_n_1 = SpeedIntegral;
DutyCycle = SpeedIntegral + SpeedProportional;
PDC1 = (int)(((long)(PTPER*2)*(long)DutyCycle) >> 15); // ??? PWM duty cycle
1PDC2 = PDC1;
PDC3 = PDC1;
#endif // in closed loop algorithm
IFS0bits.T1IF = 0;
}
void __attribute__((interrupt, no_auto_psv)) _IC1Interrupt (void)
{
int Hall_Index;
IFS0bits.IC1IF = 0; // Clear interrupt flag
HallValue = (unsigned int)((PORTB >> 1) & 0x0007); // Read halls
if (Flags.Direction)
{
OVDCON = StateTableFwd[HallValue];
Hall_Index = HALL_INDEX_F;
}
else
{
OVDCON = StateTableRev[HallValue];
Hall_Index = HALL_INDEX_R;
}
// The code below is uses TMR3 to calculate the speed of the rotor
if (HallValue == Hall_Index) // has the same position been sensed?
if (polecount++ == POLEPAIRS) //has one mech rev elasped? // ???
{ // yes then read timer 3
timer3value = TMR3;
TMR3 = 0;
timer3avg = ((timer3avg + timer3value) >> 1); // ???
polecount = 1;
}
}
Para hacer matemáticas fraccionarias con enteros en C (y otros lenguajes que no admiten matemáticas fraccionarias), es necesario hacer trucos como este. Lo que realmente le gustaría hacer es multiplicar dos números de 16 bits y mantener los bits altos del producto.
El primer conjunto de expresiones convierte números de 16 bits en números de 32 bits con signo y luego calcula el producto de 32 bits. Luego lo desplazan 15 bits hacia la derecha, descartando los bits menos significativos. Es un poco como lo que sucede con las matemáticas de coma flotante cuando multiplicas dos mantisas (aunque las matemáticas de coma flotante se harían de manera más eficiente ya que no hay necesidad de calcular lo que se descartará).
En la segunda expresión (polecount++ == POLPAIRS) tiene un valor booleano basado en la comparación del valor de la variable polecount con POLPAIRS. El número de polos variable se incrementa posteriormente (se incrementa después de la comparación).
if
declaración es verdadera?(long)Kis
mantiene los bits de la variable Kis originalmente definidos como un int sin firmar como LSB, y rellena con ceros como los 16 MSB superiores.Estas líneas representan la parte proporcional e integral del control del motor.
El SpeedError se multiplica directamente por la ganancia de Kps y la ganancia de Kis multiplica el SpeedError y lo suma a la salida integral de los últimos ciclos SpeedIntegral_n_1.
Debería haber algunas líneas de código más adelante que sumen los términos proporcional e integral para determinar la entrada del motor.
Este método de control intenta garantizar que el control de velocidad del motor sea estable y no oscile. El ajuste de las ganancias proporcionales e integrales afectará la velocidad y la estabilidad del control del motor.
El operador >> es un desplazamiento bit a bit hacia la derecha. Desplazar todos los bits hacia la izquierda o hacia la derecha dentro de un número binario multiplicará o dividirá el número por 2 (por cada cambio). También puede haber momentos en los que desee cambiar ciertos bits a ciertas posiciones, posiblemente para alinear bits en un puerto de E/S o los bits dentro de un registro de datos interno especial.
Además, en algunas de estas fórmulas, una o más de las variables se convierten a un determinado tipo de datos (usando un prefijo como (int) o (largo) justo antes del número).
Para el operador de desplazamiento de bits, consulte: http://www.cprogramming.com/tutorial/bitwise_operators.html
timer3avg = ((timer3avg + timer3value) >> 1);
se calcula el promedio de acuerdo con la fórmula (x+y)/2 ?int
a a long
para la multiplicación y luego volver a convertir al original int
?
adam lorenzo