Motor.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Demo program for stepper motor control with linear ramps
  2. // Hardware: PIC18F252, L6219
  3. #include "18F252.h"
  4. // PIC18F252 SFRs
  5. #byte TRISC = 0xf94
  6. #byte T3CON = 0xfb1
  7. #byte CCP2CON = 0xfba
  8. #byte CCPR2L = 0xfbb
  9. #byte CCPR2H = 0xfbc
  10. #byte CCP1CON = 0xfbd
  11. #byte CCPR1L = 0xfbe
  12. #byte CCPR1H = 0xfbf
  13. #byte T1CON = 0xfcd
  14. #byte TMR1L = 0xfce
  15. #byte TMR1H = 0xfcf
  16. #bit TMR1ON = T1CON.0
  17. // 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps)
  18. #define C0 50000
  19. #define C_MIN 2500
  20. // ramp state-machine states
  21. #define ramp_idle 0
  22. #define ramp_up 1
  23. #define ramp_max 2
  24. #define ramp_down 3
  25. #define ramp_last 4
  26. // Types: int8,int16,int32=8,16,32bit integers, unsigned by default
  27. int8 ramp_sts=ramp_idle;
  28. signed int16 motor_pos = 0; // absolute step number
  29. signed int16 pos_inc=0; // motor_pos increment
  30. int16 phase=0; // ccpPhase[phase_ix]
  31. int8 phase_ix=0; // index to ccpPhase[]
  32. int8 phase_inc; // phase_ix increment
  33. int8 run_flg; // true while motor is running
  34. int16 ccpr; // copy of CCPR1&2
  35. int16 c; // integer delay count
  36. int16 step_no; // progress of move
  37. int16 step_down; // start of down-ramp
  38. int16 move; // total steps to move
  39. int16 midpt; // midpoint of move
  40. int32 c32; // 24.8 fixed point delay count
  41. signed int16 denom; // 4.n+1 in ramp algo
  42. // Config data to make CCP1&2 generate quadrature sequence on PHASE pins
  43. // Action on CCP match: 8=set+irq; 9=clear+irq
  44. int16 const ccpPhase[] = {0x909, 0x908, 0x808, 0x809}; // 00,01,11,10
  45. void current_on(){/* code as needed */} // motor drive current
  46. void current_off(){/* code as needed */} // reduce to holding value
  47. // compiler-specific ISR declaration
  48. #INT_CCP1
  49. void isr_motor_step()
  50. { // CCP1 match -> step pulse + IRQ
  51. ccpr += c; // next comparator value: add step delay count
  52. switch (ramp_sts)
  53. {
  54. case ramp_up: // accel
  55. if (step_no==midpt)
  56. { // midpoint: decel
  57. ramp_sts = ramp_down;
  58. denom = ((step_no - move)<<2)+1;
  59. if (!(move & 1))
  60. { // even move: repeat last delay before decel
  61. denom +=4;
  62. break;
  63. }
  64. }
  65. // no break: share code for ramp algo
  66. case ramp_down: // decel
  67. if (step_no == move-1)
  68. { // next irq is cleanup (no step)
  69. ramp_sts = ramp_last;
  70. break;
  71. }
  72. denom+=4;
  73. c32 -= (c32<<1)/denom; // ramp algorithm
  74. // beware confict with foreground code if long div not reentrant
  75. c = (c32+128)>>8; // round 24.8format->int16
  76. if (c <= C_MIN)
  77. { // go to constant speed
  78. ramp_sts = ramp_max;
  79. step_down = move - step_no;
  80. c = C_MIN;
  81. break;
  82. }
  83. break;
  84. case ramp_max: // constant speed
  85. if (step_no == step_down)
  86. { // start decel
  87. ramp_sts = ramp_down;
  88. denom = ((step_no - move)<<2)+5;
  89. }
  90. break;
  91. default: // last step: cleanup
  92. ramp_sts = ramp_idle;
  93. current_off(); // reduce motor current to holding value
  94. disable_interrupts(INT_CCP1);
  95. run_flg = FALSE; // move complete
  96. break;
  97. } // switch (ramp_sts)
  98. if (ramp_sts!=ramp_idle)
  99. {
  100. motor_pos += pos_inc;
  101. ++step_no;
  102. CCPR2H = CCPR1H = (ccpr >> 8); // timer value at next CCP match
  103. CCPR2L = CCPR1L = (ccpr & 0xff);
  104. if (ramp_sts!=ramp_last) // else repeat last action: no step
  105. phase_ix = (phase_ix + phase_inc) & 3;
  106. phase = ccpPhase[phase_ix];
  107. CCP1CON = phase & 0xff; // set CCP action on next match
  108. CCP2CON = phase >> 8;
  109. } // if (ramp_sts != ramp_idle)
  110. } // isr_motor_step()
  111. void motor_run(short pos_new)
  112. { // set up to drive motor to pos_new (absolute step#)
  113. if (pos_new < motor_pos) // get direction & #steps
  114. {
  115. move = motor_pos-pos_new;
  116. pos_inc = -1;
  117. phase_inc = 0xff;
  118. }
  119. else if (pos_new != motor_pos)
  120. {
  121. move = pos_new-motor_pos;
  122. pos_inc = 1;
  123. phase_inc = 1;
  124. }
  125. else return; // already there
  126. midpt = (move-1)>>1;
  127. c = C0;
  128. c32 = c<<8; // keep c in 24.8 fixed-point format for ramp calcs
  129. step_no = 0; // step counter
  130. denom = 1; // 4.n+1, n=0
  131. ramp_sts = ramp_up; // start ramp state-machine
  132. run_flg = TRUE;
  133. TMR1ON = 0; // stop timer1;
  134. ccpr = make16(TMR1H,TMR1L); // 16bit value of Timer1
  135. ccpr += 1000; // 1st step + irq 1ms after timer1 restart
  136. CCPR2H = CCPR1H = (ccpr >> 8);
  137. CCPR2L = CCPR1L = (ccpr & 0xff);
  138. phase_ix = (phase_ix + phase_inc) & 3;
  139. phase = ccpPhase[phase_ix];
  140. CCP1CON = phase & 0xff; // sets action on match
  141. CCP2CON = phase >> 8;
  142. current_on(); // current in motor windings
  143. enable_interrupts(INT_CCP1);
  144. TMR1ON=1; // restart timer1;
  145. } // motor_run()
  146. void initialize()
  147. {
  148. disable_interrupts(GLOBAL);
  149. disable_interrupts(INT_CCP1);
  150. disable_interrupts(INT_CCP2);
  151. output_c(0);
  152. set_tris_c(0);
  153. T3CON = 0;
  154. T1CON = 0x35;
  155. enable_interrupts(GLOBAL);
  156. } // initialize()
  157. void main()
  158. {
  159. initialize();
  160. while (1)
  161. { // repeat 5 revs forward & back
  162. motor_run(1000);
  163. while (run_flg);
  164. motor_run(0);
  165. while (run_flg);
  166. }
  167. } // main()
  168. // end of file motor.c