基于PIC18系列单片机的直流有刷伺控制系统:(来处于国外贴)
1:原理图(PDF)
2:原理图及PCB图(EAGLE)
3:带pid + 编码器的控制程序。main.c
电路原理图如下:
单片机源程序如下:
// Vertical motor driver code
// Oringially made by Kevin Wolfe 2009-2011
// Modified by Matt Moses 2010-2011
//
#include
//#include
//#include
//#include
#define counterToSpeedScalar 150
#define numCountsPerStep 1
#define maxSpeed 255
#define Kp 35.0
#define Kd 0.0
#define Ki 0.0
#define dt 0.01
#define speedStep 1
#define errorTol 1
#define tempADSpeed 255
#define stepHomeThreshold 500
#define upTorqueLimit 150
#define downTorqueLimit -120
#pragma config IESO = ON
#pragma config FSCM = ON
#pragma config OSC = INTIO2
#pragma config PWRT = OFF
#pragma config BOR = OFF
#pragma config WDT = OFF
#pragma config MCLRE = OFF
/****** DISABLE LVP (LOW-VOLTAGE Programming) ******/
/* This allows RB5 to operate as an interuppt on change I/O pin */
#pragma config LVP = OFF
/***************************************************/
void low_isr (void);
void high_isr (void);
void set_motor_output (unsigned char desiredPWM, unsigned char desiredDirection);
#pragma code high_vector_section=0x8
void high_vector (void)
{
_asm GOTO high_isr _endasm
}
#pragma code
#pragma code low_vector_section=0x18
void low_vector (void)
{
_asm GOTO low_isr _endasm
}
#pragma code
volatile int stepHighCounter = 0;
volatile char stepPulses = 0;
//volatile int stepCounts;
volatile int currentCounter = 0;
//volatile unsigned char currentADvalue;
volatile unsigned char trigger = 0;
//volatile structPrevStates prevStates;
//volatile enum { DIR_CW = 0, DIR_CCW = 1 } direction;
volatile enum { LOW = 0, HIGH = 1} prevA = LOW;
// changeToggle is a varb used for debugging
volatile enum {LOW = 0, HIGH = 1} changeToggle;
#pragma interrupt high_isr
void high_isr(void)
{
if ( INTCONbits.INT0IF ) //step pulse flag
{
// reset stepTimerFoo
stepHighCounter = 1;
// do important stuff
if ( PORTBbits.RB1 ) //Check direction pin
{
stepPulses++;
}
else
{
stepPulses--;
}
INTCONbits.INT0IF = 0; //reset step flag
}
if ( INTCONbits.RBIF ) //PORTB change interrupt
{
// // This is a little block for debugging - toggles A every time a change on PORTB
//
// if (changeToggle) {
// changeToggle = 0;
// PORTAbits.RA1 = 0;
// }
// else {
// changeToggle = 1;
// PORTAbits.RA1 = 1;
// }
if ( PORTBbits.RB5^prevA ) //CW Rotation
{
currentCounter++;
//PORTAbits.RA1 = 0;
}
else //CCW Rotation
{
currentCounter--;
//PORTAbits.RA1 = 1;
// if (changeToggle) {
// changeToggle = 0;
// PORTAbits.RA1 = 0;
// }
// else {
// changeToggle = 1;
// PORTAbits.RA1 = 1;
// }
}
prevA = PORTBbits.RB4;
PORTAbits.RA1 = PORTBbits.RB5;
INTCONbits.RBIF = 0; //resetQuadFlag
}
}
#pragma interruptlow low_isr
void low_isr(void) //timer interupt
{
trigger = 1;
INTCONbits.TMR0IF = 0; // reset TMR0 interrupt flag
}
void set_motor_output(unsigned char desiredPWM, unsigned char desiredDirection)
{
if ( desiredDirection )
{
PORTBbits.RB2 = 0;
CCPR1L = desiredPWM; // This is the register for the 8 MSB of the PWM pin RB3.
}
else
{
PORTBbits.RB2 = 1;
CCPR1L = (desiredPWM ); // This is the register for the 8 MSB of the PWM pin RB3.
}
}
long abs(long i)
{
if (i < 0)
return -i;
else
return i;
}
char sgn(long i)
{
if (i < 0)
return -1;
else if (i > 0)
return 1;
else
return 0;
}
void main (void)
{
long prevCounter = 0;
unsigned char tempTrigger = 0;
char tempStepPulses = 0;
long tempCurrentCounter = 0;
unsigned char currentADvalue = tempADSpeed;
long desiredCounter = 0;
long error = 0;
long prevError = 0;
long velocity = 0;
float integral = 0.0;
float derivative = 0.0;
long output = 0;
char testState = 0;
long testCounter = 0;
char homeFlag = 0;
enum { LOW = 0, HIGH = 1} homeDir = LOW;
/*************** SETUP INTERRUPTS ******************/
INTCONbits.GIEH = 0; // Temporarily disable global interrupts
INTCONbits.GIEL = 0; // Temporarily disable peripheral interrupts
INTCONbits.TMR0IE = 1; // Enable TMR0 Overflow interrupt
INTCONbits.INT0IE = 1; // Enable external interrupt on INT0/RB0
INTCONbits.RBIE = 1; // Enable Port B change interrupt
//INTCON2bits.RBPU = 0; // Enable Port B pull-ups
INTCON2bits.RBPU = 1; // Disable Port B pull-ups
INTCON2bits.INTEDG0 = 1; // Interrupt on rising edge for INT0
INTCON2bits.TMR0IP = 0; // Set TMR0
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』