Quote:
Originally Posted by Alan Anderson
Anyone else feel like sharing?
|
Streamlined, non-directional Encoder Tach code and added a ring buffer. This is used with 100 counts per revolution encoders on each wheel and provides good low speed resolution while still allowing the PID loop to compute new values every 26ms.
Some will recognize Kevin's interrupt framework, but everything else is different.
Here's the relevant portion of the interrupt routine:
Code:
volatile unsigned int Tach_Count[NUM_TACH];
unsigned char Old_Port_B = 0xFF;
void InterruptHandlerLow () {
unsigned char Port_B;
unsigned char Port_B_Delta;
// other interrupt handler code removed for clarity.
else if (INTCON3bits.INT2IF && INTCON3bits.INT2IE) { // encoder 1 interrupt?
INTCON3bits.INT2IF = 0; // clear the interrupt flag
Tach_Count[0]++;
}
else if (INTCON3bits.INT3IF && INTCON3bits.INT3IE) { // encoder 2 interrupt?
INTCON3bits.INT3IF = 0; // clear the interrupt flag
Tach_Count[1]++;
}
else if (INTCONbits.RBIF && INTCONbits.RBIE) { // encoder 3-6 interrupt?
Port_B = PORTB; // remove the "mismatch condition" by reading port b
INTCONbits.RBIF = 0; // clear the interrupt flag
Port_B_Delta = Port_B ^ Old_Port_B; // determine which bits have changed
Old_Port_B = Port_B; // save a copy of port b for next time around
if(Port_B_Delta & 0x10) { // did external interrupt 3 change state?
if (Port_B & 0x10) {
Tach_Count[2]++;
}
}
if(Port_B_Delta & 0x20) { // did external interrupt 4 change state?
if (Port_B & 0x20) {
Tach_Count[3]++;
}
}
}
}
Initialization:
Code:
unsigned char i, j;
for(i=0;i<NUM_TACH;i++) {
TachHead[i] = 0;
for(j=0;j<TACHBUFSIZE;j++) {
TachBuf[i][j] = 0;
}
}
And here's the foreground tach code that runs in the 26ms loop:
Code:
#define NUM_TACH 4
#define TACHBUFSIZE 4
extern unsigned int Tach_Count[]; // interrupt routine edge counter
unsigned char i, j;
unsigned int TachBuf[NUM_TACH][TACHBUFSIZE]; // ring buffer
unsigned char TachHead[NUM_TACH]; // TachBuf head pointer
unsigned int Tach[NUM_TACH]; // Tach result register.
// disable tach interrupts, grab current count, and reset counter
INTCON3bits.INT2IE = 0; // Disable INT2 for tach 1
INTCON3bits.INT3IE = 0; // Disable INT3 for tach 2
INTCONbits.RBIE = 0; // Disable Port B change interrupt for tach 3&4
// get current tach values into local var, then reset the counter
for (i=0;i<NUM_TACH;i++) {
TachBuf[i][TachHead[i]] = Tach_Count[i]; // place current tach count into ring buffer & inc buffer
Tach_Count[i] = 0;
}
INTCON3bits.INT2IE = 1; // INT2 on
INTCON3bits.INT3IE = 1; // INT3 on
INTCONbits.RBIE = 1; // Port B change interrupt on
// sum up the tach counts in ring buffer into Tach[]
for (i=0;i<NUM_TACH;i++) {
Tach[i] = 0;
for(j=0;j<TACHBUFSIZE;j++) {
Tach[i] += TachBuf[i][j];
}
if (++TachHead[i] >= TACHBUFSIZE) {
TachHead[i] = 0;
}
}
// Tach[] now contains the unsigned wheel speeds