I am new to C programming. I need your help in understanding the some particular lines in a code segment for sensored control of a brushless dc motor. It was written for a 16-bit MCU (dsPIC33FJ32MC710). This particular section is from the interrupt service routine, and contains two ISRs.
Can you please explain to me in simple words, the lines marked by //???
? What is being done there, and why? Any other comments are also welcome.
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;
}
}
-
1\$\begingroup\$ Look up 'C typecasting'. \$\endgroup\$Adam Lawrence– Adam Lawrence2015年04月07日 19:16:30 +00:00Commented Apr 7, 2015 at 19:16
3 Answers 3
In order to do fractional integer math in C (and other languages that don't support fractional math), it's necessary to pull tricks like this. What you would really like to do is to multiply two 16-bit numbers and keep the high bits of the product.
The first set of expressions cast 16-bit numbers into signed 32-bit numbers, then calculate the 32-bit product. They then shift it right by 15 bits, discarding the least significant bits. It's a bit like what goes on with floating point math when you multiply two mantissas (though the floating point math would be done more efficiently since there's no need to calculate what will be discarded).
In the second expression (polecount++ == POLEPAIRS) has a boolean value based on the comparison of the value of the variable polecount to POLEPAIRS. The variable polecount is post-incremented (incremented after the comparison).
-
\$\begingroup\$ So polecount will be incremented only if the
if
statement is true? \$\endgroup\$Adeel– Adeel2015年04月07日 19:36:49 +00:00Commented Apr 7, 2015 at 19:36 -
1\$\begingroup\$ No, polecount is incremented whenever that line is reached- it's a side effect of the calculation of the comparison. The part after it {stuff in here} is executed only when the 'if' statement is true. \$\endgroup\$Spehro 'speff' Pefhany– Spehro 'speff' Pefhany2015年04月07日 19:38:40 +00:00Commented Apr 7, 2015 at 19:38
-
\$\begingroup\$ What would've been the drawback if the variables were multiplied in 16-bit instead of 32 bit? Because eventually they convert back to 16-bit, through typecasting. \$\endgroup\$Adeel– Adeel2015年04月07日 19:45:50 +00:00Commented Apr 7, 2015 at 19:45
-
2\$\begingroup\$ The drawback is that the product between two 16 bits number does not fit in 16 bits, so it would overflow and you will just get the useless less significant bits. In that way the multiplication is ok since 32 bits can hold the result of 16bx16b, but then the result is shifted, discarding the less sig. bits and keeping only 16 bits. \$\endgroup\$Vladimir Cravero– Vladimir Cravero2015年04月07日 20:05:52 +00:00Commented Apr 7, 2015 at 20:05
-
\$\begingroup\$ So basically the segment
(long)Kis
keeps the bits of variable Kis originally defined as an unsigned int as LSBs, and pads zeros as the upper 16 MSBs? \$\endgroup\$Adeel– Adeel2015年04月07日 20:39:24 +00:00Commented Apr 7, 2015 at 20:39
These lines represent the proportional and integral part of the motor control.
The SpeedError is multiplied by the Kps gain directly and the Kis gain multiplies the SpeedError and adds it to last cycles integral output SpeedIntegral_n_1.
There should be some lines of code later that sum the proportional and integral terms to determine the motor input.
This control method is attempting to ensure that the motor speed control is stable and does not oscillate. Adjusting the proportional and integral gains will effect the speed and stability of the motor control.
The>> operator is a bitwise shift to the right. Shifting all bits left or right within a binary number will multiply or divide the number by 2 (per each shift). There may also be times where you want to have certain bits shifted into certain positions, possibly for aligning bits on an I/O port or the bits within a special internal data register.
Also, In some of these formulas one or more of the variables are being converted to a certain data type, (using a prefix such as (int) or (long) just ahead of the number).
For bit shift operator See: http://www.cprogramming.com/tutorial/bitwise_operators.html
-
\$\begingroup\$ So in the line
timer3avg = ((timer3avg + timer3value) >> 1);
is the average being calculated according to the formula (x+y)/2 ? \$\endgroup\$Adeel– Adeel2015年04月07日 19:58:46 +00:00Commented Apr 7, 2015 at 19:58 -
\$\begingroup\$ Also, why convert an
int
to along
for multiplication, then convert back to originalint
? \$\endgroup\$Adeel– Adeel2015年04月07日 20:03:50 +00:00Commented Apr 7, 2015 at 20:03 -
1\$\begingroup\$ Yes, one shift right is a divide by 2. Setting a variable to a long gives you more useable bits in the same number (For eg: You cannot shift an 8-bit number 15 times). The larger number of bits can also allow more precision if manipulated correctly. \$\endgroup\$Nedd– Nedd2015年04月07日 20:19:15 +00:00Commented Apr 7, 2015 at 20:19
Explore related questions
See similar questions with these tags.