1 // Demo program for stepper motor control with linear ramps
2 // Hardware: PIC18F252, L6219
19 // 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps)
23 // ramp state-machine states
30 // Types: int8,int16,int32=8,16,32bit integers, unsigned by default
31 int8 ramp_sts=ramp_idle;
32 signed int16 motor_pos = 0; // absolute step number
33 signed int16 pos_inc=0; // motor_pos increment
34 int16 phase=0; // ccpPhase[phase_ix]
35 int8 phase_ix=0; // index to ccpPhase[]
36 int8 phase_inc; // phase_ix increment
37 int8 run_flg; // true while motor is running
38 int16 ccpr; // copy of CCPR1&2
39 int16 c; // integer delay count
40 int16 step_no; // progress of move
41 int16 step_down; // start of down-ramp
42 int16 move; // total steps to move
43 int16 midpt; // midpoint of move
44 int32 c32; // 24.8 fixed point delay count
45 signed int16 denom; // 4.n+1 in ramp algo
47 // Config data to make CCP1&2 generate quadrature sequence on PHASE pins
48 // Action on CCP match: 8=set+irq; 9=clear+irq
49 int16 const ccpPhase[] = {0x909, 0x908, 0x808, 0x809}; // 00,01,11,10
51 void current_on(){/* code as needed */} // motor drive current
52 void current_off(){/* code as needed */} // reduce to holding value
54 // compiler-specific ISR declaration
57 { // CCP1 match -> step pulse + IRQ
58 ccpr += c; // next comparator value: add step delay count
61 case ramp_up: // accel
65 denom = ((step_no - move)<<2)+1;
67 { // even move: repeat last delay before decel
72 // no break: share code for ramp algo
73 case ramp_down: // decel
74 if (step_no == move-1)
75 { // next irq is cleanup (no step)
80 c32 -= (c32<<1)/denom; // ramp algorithm
81 // beware confict with foreground code if long div not reentrant
82 c = (c32+128)>>8; // round 24.8format->int16
84 { // go to constant speed
86 step_down = move - step_no;
91 case ramp_max: // constant speed
92 if (step_no == step_down)
95 denom = ((step_no - move)<<2)+5;
98 default: // last step: cleanup
100 current_off(); // reduce motor current to holding value
101 disable_interrupts(INT_CCP1);
102 run_flg = FALSE; // move complete
104 } // switch (ramp_sts)
105 if (ramp_sts!=ramp_idle)
107 motor_pos += pos_inc;
109 CCPR2H = CCPR1H = (ccpr >> 8); // timer value at next CCP match
110 CCPR2L = CCPR1L = (ccpr & 0xff);
111 if (ramp_sts!=ramp_last) // else repeat last action: no step
112 phase_ix = (phase_ix + phase_inc) & 3;
113 phase = ccpPhase[phase_ix];
114 CCP1CON = phase & 0xff; // set CCP action on next match
115 CCP2CON = phase >> 8;
116 } // if (ramp_sts != ramp_idle)
117 } // isr_motor_step()
119 void motor_run(short pos_new)
120 { // set up to drive motor to pos_new (absolute step#)
121 if (pos_new < motor_pos) // get direction & #steps
123 move = motor_pos-pos_new;
127 else if (pos_new != motor_pos)
129 move = pos_new-motor_pos;
133 else return; // already there
136 c32 = c<<8; // keep c in 24.8 fixed-point format for ramp calcs
137 step_no = 0; // step counter
138 denom = 1; // 4.n+1, n=0
139 ramp_sts = ramp_up; // start ramp state-machine
141 TMR1ON = 0; // stop timer1;
142 ccpr = make16(TMR1H,TMR1L); // 16bit value of Timer1
143 ccpr += 1000; // 1st step + irq 1ms after timer1 restart
144 CCPR2H = CCPR1H = (ccpr >> 8);
145 CCPR2L = CCPR1L = (ccpr & 0xff);
146 phase_ix = (phase_ix + phase_inc) & 3;
147 phase = ccpPhase[phase_ix];
148 CCP1CON = phase & 0xff; // sets action on match
149 CCP2CON = phase >> 8;
150 current_on(); // current in motor windings
151 enable_interrupts(INT_CCP1);
152 TMR1ON=1; // restart timer1;
158 disable_interrupts(GLOBAL);
159 disable_interrupts(INT_CCP1);
160 disable_interrupts(INT_CCP2);
165 enable_interrupts(GLOBAL);
172 { // repeat 5 revs forward & back
179 // end of file motor.c