Anda di halaman 1dari 6

/****************************************************************************

**
DC_motor_xtal.c - run a DC motor at xtal "clockwork" locked speed
Started 8 Apr 2013 - Copyright www.RomanBlack.com, allowed for public use,
you must mention me as the author and please provide
a link to my web page where this system is described;
www.RomanBlack.com/onesec/DCmotor_xtal.htm

PIC16F628A - 20MHz HS xtal (see web page for schematic)


Compiler - MikroC for PIC v8
PIC pins;
RA0 = digital ST input, quad encoder A
RA1 = digital ST input, quad encoder B
RB3 = CCP1 output, PWM to motor, HI = ON
RB0 = echo encoder A output
RB1 = echo encoder A output

PIC configs; MCRLE off, BODEN off, BORES off, WDT off, LVP off, PWRT on
*****************************************************************************
*/

// This constant sets the motor speed. The value is in nanoSeconds per pulse,
// as we are using a quadrature encoder there are 4 pulses per encoder slot.
// My encoder had 36 slots, so that makes 36*4 or 144 pulses per revolution.
// Example; 1 motor rev per second = 144 pulses /sec.
// nS per pulse = 1 billion / 144 = 6944444
//#define MOTOR_PULSE_PERIOD 1736111 // 4 RPS
//#define MOTOR_PULSE_PERIOD 3472222 // 2 RPS
#define MOTOR_PULSE_PERIOD 6944444 // 1 RPS
//#define MOTOR_PULSE_PERIOD 13888889 // 0.5 RPS

// This constant sets the proportional gain. Basically it sets how much
// more PWM % is added for each pulse behind that the motor gets.
// ie; if set to 10, the PWM is increased by 10% for each pulse behind.
// Values must be within 1-50. Values of 10 or 16 worked well with
// low motor RPMs, for higher RPMs a smaller value like 2 to 8 can be used.
#define MOTOR_PROP_GAIN 10

// global vars
unsigned char rpos;

// reference position of xtal based freq

unsigned char mpos;

// actual motor position

unsigned char mlag;

// amount the motor lags the reference

unsigned char enc_new; // holds motor's quadrature encoder data for testing
unsigned char enc_last;
unsigned long bres;

// bresenham accumulator used to make ref frequency

unsigned char pins;

// temporary var for echoing encoder signals

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
void interrupt()
{
//------------------------------------------------------// This is TMR0 int, prescaled at 2:1 so we get here every 512 instructions.
// This int does the entire closed loop speed control;
// 1. updates encoder to see if motor has moved, records it position
// 2. updates reference freq generator, records its position
// 3. compares the two, sets PWM if motor lags behind reference
// 4. limit both counts, so they never roll, but still retain all error
//------------------------------------------------------// clear int flag straight away to give max safe time
INTCON.T0IF = 0;

// 1. updates encoder to see if motor has moved, records it position


enc_new = (PORTA & 0b00000011); // get the 2 encoder bits
if(enc_new != enc_last)
{
if(enc_new.F1 != enc_last.F0) mpos++; // record new motor position
else

mpos--;

enc_last = enc_new;
}

// 2. updates reference freq generator, records its position


bres += 102400;

// add nS per interrupt period (512 insts * 200nS)

if(bres >= MOTOR_PULSE_PERIOD) // if reached a new reference step


{
bres -= MOTOR_PULSE_PERIOD;
rpos++;

// record new xtal-locked reference position

// 3. compares the two, set PWM% if motor lags behind reference


if(mpos < rpos) // if motor lagging behind
{
mlag = (rpos - mpos);

// find how far it's lagging behind

if(mlag >= (100/MOTOR_PROP_GAIN)) CCPR1L = 100; // full power if is too far behind
else CCPR1L = (mlag * MOTOR_PROP_GAIN);

// else adjust PWM if slightly behind

}
else

// else if motor is fast, cut all power!

{
CCPR1L = 0;
}

// 4. limit both counts, so they never roll, but still retain all error

if(rpos>250 || mpos>250)
{
rpos -= 50;
mpos -= 50;
}

}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+

//============================================================================
=
// MAIN
//============================================================================
=
void main()
{
//------------------------------------------------------// setup PIC 16F628A
CMCON = 0b00000111;

PORTA = 0b00000000;
TRISA = 0b00000011;

PORTB = 0b00000000;
TRISB = 0b00000000;

// comparators OFF, all pins digital

//
// RA0,RA1 used for digital ST encoder inputs

//
// RB3 is CCP1 PWM out, RB0,RB1 are encoder echo outputs

// set TMR2 to roll every 100 ticks, PWM freq = 5mil/16/100 = 3125 Hz
T2CON = 0b00000111;
PR2 = (100-1);

// TMR2 ON, 16:1 prescale

// PWM total period of 100

// set PWM out on CCP1


CCPR1L = 0;

// PWM range 0-100% = start with PWM of 0%

CCP1CON = 0b00001100; // CCP1 on, set to PWM mode

// TMR0 used for interrupt, makes interrupt every 512 insts


OPTION_REG = 0b10000000; // PORTB pullups OFF, TMR0 on, 2:1 prescale

//------------------------------------------------------// setup before main loop


Delay_mS(200); // allow PSU voltages time to stabilise

// setup vars etc, will be used in interrupt


bres = 0;
rpos = 0;
mpos = 0;

// finally start TMR0 roll interrupt


INTCON = 0b10100000; // GIE=on, TMR0IE=on

//------------------------------------------------------// main run loop


while(1)
{
//------------------------------------------------// We don't need to do anything in main loop as the motor speed
// control is done entirely in the TMR0 interrupt.

//------------------------------------------------// For convenience in setting up the encoder trimpots,

// echo the two encoder pins out two spare PORTB digital outputs!
pins = 0;
if(PORTA.F0) pins.F0 = 1;
if(PORTA.F1) pins.F1 = 1;
PORTB = pins; // output those two pins only (PWM output is not affected)
}
}
//-----------------------------------------------------------------------------

Anda mungkin juga menyukai