safe_numerics/example/Motor.c
Andrey Semashev 9b4408a5ac Fix ends of lines, remove executable permission (#72)
* Converted Windows ends of line to UNIX.

Text files in git must have UNIX ends of lines, to be converted to Windows
EOLs on checkout, as required by git settings on the user's system.

* Removed executable permission from header.
2019-06-23 12:12:57 -07:00

180 lines
4.9 KiB
C

// Demo program for stepper motor control with linear ramps
// Hardware: PIC18F252, L6219
#include "18F252.h"
// PIC18F252 SFRs
#byte TRISC = 0xf94
#byte T3CON = 0xfb1
#byte CCP2CON = 0xfba
#byte CCPR2L = 0xfbb
#byte CCPR2H = 0xfbc
#byte CCP1CON = 0xfbd
#byte CCPR1L = 0xfbe
#byte CCPR1H = 0xfbf
#byte T1CON = 0xfcd
#byte TMR1L = 0xfce
#byte TMR1H = 0xfcf
#bit TMR1ON = T1CON.0
// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps)
#define C0 50000
#define C_MIN 2500
// ramp state-machine states
#define ramp_idle 0
#define ramp_up 1
#define ramp_max 2
#define ramp_down 3
#define ramp_last 4
// Types: int8,int16,int32=8,16,32bit integers, unsigned by default
int8 ramp_sts=ramp_idle;
signed int16 motor_pos = 0; // absolute step number
signed int16 pos_inc=0; // motor_pos increment
int16 phase=0; // ccpPhase[phase_ix]
int8 phase_ix=0; // index to ccpPhase[]
int8 phase_inc; // phase_ix increment
int8 run_flg; // true while motor is running
int16 ccpr; // copy of CCPR1&2
int16 c; // integer delay count
int16 step_no; // progress of move
int16 step_down; // start of down-ramp
int16 move; // total steps to move
int16 midpt; // midpoint of move
int32 c32; // 24.8 fixed point delay count
signed int16 denom; // 4.n+1 in ramp algo
// Config data to make CCP1&2 generate quadrature sequence on PHASE pins
// Action on CCP match: 8=set+irq; 9=clear+irq
int16 const ccpPhase[] = {0x909, 0x908, 0x808, 0x809}; // 00,01,11,10
void current_on(){/* code as needed */} // motor drive current
void current_off(){/* code as needed */} // reduce to holding value
// compiler-specific ISR declaration
#INT_CCP1
void isr_motor_step()
{ // CCP1 match -> step pulse + IRQ
ccpr += c; // next comparator value: add step delay count
switch (ramp_sts)
{
case ramp_up: // accel
if (step_no==midpt)
{ // midpoint: decel
ramp_sts = ramp_down;
denom = ((step_no - move)<<2)+1;
if (!(move & 1))
{ // even move: repeat last delay before decel
denom +=4;
break;
}
}
// no break: share code for ramp algo
case ramp_down: // decel
if (step_no == move-1)
{ // next irq is cleanup (no step)
ramp_sts = ramp_last;
break;
}
denom+=4;
c32 -= (c32<<1)/denom; // ramp algorithm
// beware confict with foreground code if long div not reentrant
c = (c32+128)>>8; // round 24.8format->int16
if (c <= C_MIN)
{ // go to constant speed
ramp_sts = ramp_max;
step_down = move - step_no;
c = C_MIN;
break;
}
break;
case ramp_max: // constant speed
if (step_no == step_down)
{ // start decel
ramp_sts = ramp_down;
denom = ((step_no - move)<<2)+5;
}
break;
default: // last step: cleanup
ramp_sts = ramp_idle;
current_off(); // reduce motor current to holding value
disable_interrupts(INT_CCP1);
run_flg = FALSE; // move complete
break;
} // switch (ramp_sts)
if (ramp_sts!=ramp_idle)
{
motor_pos += pos_inc;
++step_no;
CCPR2H = CCPR1H = (ccpr >> 8); // timer value at next CCP match
CCPR2L = CCPR1L = (ccpr & 0xff);
if (ramp_sts!=ramp_last) // else repeat last action: no step
phase_ix = (phase_ix + phase_inc) & 3;
phase = ccpPhase[phase_ix];
CCP1CON = phase & 0xff; // set CCP action on next match
CCP2CON = phase >> 8;
} // if (ramp_sts != ramp_idle)
} // isr_motor_step()
void motor_run(short pos_new)
{ // set up to drive motor to pos_new (absolute step#)
if (pos_new < motor_pos) // get direction & #steps
{
move = motor_pos-pos_new;
pos_inc = -1;
phase_inc = 0xff;
}
else if (pos_new != motor_pos)
{
move = pos_new-motor_pos;
pos_inc = 1;
phase_inc = 1;
}
else return; // already there
midpt = (move-1)>>1;
c = C0;
c32 = c<<8; // keep c in 24.8 fixed-point format for ramp calcs
step_no = 0; // step counter
denom = 1; // 4.n+1, n=0
ramp_sts = ramp_up; // start ramp state-machine
run_flg = TRUE;
TMR1ON = 0; // stop timer1;
ccpr = make16(TMR1H,TMR1L); // 16bit value of Timer1
ccpr += 1000; // 1st step + irq 1ms after timer1 restart
CCPR2H = CCPR1H = (ccpr >> 8);
CCPR2L = CCPR1L = (ccpr & 0xff);
phase_ix = (phase_ix + phase_inc) & 3;
phase = ccpPhase[phase_ix];
CCP1CON = phase & 0xff; // sets action on match
CCP2CON = phase >> 8;
current_on(); // current in motor windings
enable_interrupts(INT_CCP1);
TMR1ON=1; // restart timer1;
} // motor_run()
void initialize()
{
disable_interrupts(GLOBAL);
disable_interrupts(INT_CCP1);
disable_interrupts(INT_CCP2);
output_c(0);
set_tris_c(0);
T3CON = 0;
T1CON = 0x35;
enable_interrupts(GLOBAL);
} // initialize()
void main()
{
initialize();
while (1)
{ // repeat 5 revs forward & back
motor_run(1000);
while (run_flg);
motor_run(0);
while (run_flg);
}
} // main()
// end of file motor.c