Helfen Sie mit, den Code zu verstehen

Ich bin neu in der C-Programmierung. Ich brauche Ihre Hilfe, um einige bestimmte Zeilen in einem Codesegment für die sensorgesteuerte Steuerung eines bürstenlosen Gleichstrommotors zu verstehen. Es wurde für eine 16-Bit-MCU (dsPIC33FJ32MC710) geschrieben. Dieser bestimmte Abschnitt stammt aus der Interrupt-Service-Routine und enthält zwei ISRs. Können Sie mir bitte in einfachen Worten die mit gekennzeichneten Zeilen erklären //???? Was wird dort gemacht und warum? Auch andere Kommentare sind willkommen.

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;
        } 
}
Schlagen Sie 'C-Typumwandlung' nach.

Antworten (3)

Um in C (und anderen Sprachen, die keine gebrochene Mathematik unterstützen) gebrochene ganze Zahlen zu berechnen, ist es notwendig, solche Tricks anzuwenden. Was Sie wirklich gerne tun würden, ist, zwei 16-Bit-Zahlen zu multiplizieren und die hohen Bits des Produkts beizubehalten.

Der erste Satz von Ausdrücken wandelt 16-Bit-Zahlen in vorzeichenbehaftete 32-Bit-Zahlen um und berechnet dann das 32-Bit-Produkt. Sie verschieben es dann um 15 Bits nach rechts und verwerfen die niedrigstwertigen Bits. Es ist ein bisschen wie bei der Gleitkomma-Mathematik, wenn Sie zwei Mantissen multiplizieren (obwohl die Gleitkomma-Mathematik effizienter durchgeführt werden würde, da nicht berechnet werden muss, was verworfen wird).

Der zweite Ausdruck (polecount++ == POLEPAIRS) hat einen booleschen Wert basierend auf dem Vergleich des Werts der Variablen polecount mit POLEPAIRS. Die Variable polecount wird nachinkrementiert (inkrementiert nach dem Vergleich).

Polecount wird also nur erhöht, wenn die ifAussage wahr ist?
Nein, die Polzahl wird jedes Mal erhöht, wenn diese Linie erreicht wird - dies ist ein Nebeneffekt der Berechnung des Vergleichs. Der Teil danach {Zeug hier hinein} wird nur ausgeführt, wenn die 'if'-Anweisung wahr ist.
Was wäre der Nachteil gewesen, wenn die Variablen in 16-Bit statt in 32-Bit multipliziert worden wären? Weil sie schließlich durch Typumwandlung wieder in 16-Bit konvertiert werden.
Der Nachteil ist, dass das Produkt zwischen zwei 16-Bit-Zahlen nicht in 16 Bit passt, sodass es überlaufen würde und Sie nur die nutzlosen niederwertigen Bits erhalten würden. Auf diese Weise ist die Multiplikation in Ordnung, da 32 Bit das Ergebnis von 16bx16b enthalten können, aber dann wird das Ergebnis verschoben, wobei das niedrigere Sig verworfen wird. Bits und behält nur 16 Bits.
Das Segment behält also im Grunde (long)Kisdie Bits der Variablen Kis , die ursprünglich als unsigned int als LSBs definiert waren, und füllt Nullen als die oberen 16 MSBs auf?
@AdeelSabir Art von. Dies ist eigentlich kein gutes (übertragbares) C. Das Ergebnis der Rechtsverschiebung eines vorzeichenbehafteten Werts ist die in C definierte Implementierung (Ref. 6.5.7 in ISO/IEC 9899:1999 (E)). Vorzeichenbit wird bei jeder Verschiebung dupliziert. Der Programmierer hängt davon ab, ob diese Zahlen negativ sein können.

Diese Linien repräsentieren den Proportional- und Integralanteil der Motorsteuerung.

Der SpeedError wird direkt mit der Kps-Verstärkung multipliziert, und die Kis-Verstärkung multipliziert den SpeedError und addiert ihn zum integralen Ausgang SpeedIntegral_n_1 der letzten Zyklen.

Es sollte später einige Codezeilen geben, die die proportionalen und integralen Terme summieren, um die Motoreingabe zu bestimmen.

Dieses Regelverfahren versucht sicherzustellen, dass die Motordrehzahlregelung stabil ist und nicht schwingt. Das Einstellen der Proportional- und Integralverstärkung wirkt sich auf die Geschwindigkeit und Stabilität der Motorsteuerung aus.

Ja, ich habe diese fehlenden Zeilen hinzugefügt.
Ich habe Ihre Frage falsch verstanden, mehr C als Control.

Der >>-Operator ist eine bitweise Verschiebung nach rechts. Das Verschieben aller Bits nach links oder rechts innerhalb einer Binärzahl multipliziert oder dividiert die Zahl mit 2 (pro Verschiebung). Es kann auch vorkommen, dass bestimmte Bits an bestimmte Positionen verschoben werden sollen, möglicherweise um Bits an einem E/A-Port oder die Bits in einem speziellen internen Datenregister auszurichten.

Außerdem werden in einigen dieser Formeln eine oder mehrere Variablen in einen bestimmten Datentyp konvertiert (unter Verwendung eines Präfixes wie (int) oder (long) direkt vor der Zahl).

Für Bitverschiebungsoperatoren siehe: http://www.cprogramming.com/tutorial/bitwise_operators.html

Wird also in der Zeile timer3avg = ((timer3avg + timer3value) >> 1);der Durchschnitt nach der Formel (x+y)/2 berechnet ?
Warum auch ein intin a longzur Multiplikation umwandeln und dann wieder in das Original umwandeln int?
Ja, eine Verschiebung nach rechts ist eine Division durch 2. Wenn Sie eine Variable auf long setzen, erhalten Sie mehr nutzbare Bits in derselben Zahl (z. B.: Sie können eine 8-Bit-Zahl nicht 15 Mal verschieben). Die größere Anzahl von Bits kann auch eine höhere Genauigkeit ermöglichen, wenn sie richtig manipuliert wird.