motor2.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * david austin
  3. * http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time
  4. * DECEMBER 30, 2004
  5. *
  6. * Demo program for stepper motor control with linear ramps
  7. * Hardware: PIC18F252, L6219
  8. *
  9. * Copyright (c) 2015 Robert Ramey
  10. *
  11. * Distributed under the Boost Software License, Version 1.0. (See
  12. * accompanying file LICENSE_1_0.txt or copy at
  13. * http://www.boost.org/LICENSE_1_0.txt)
  14. */
  15. // ramp state-machine states
  16. enum ramp_state {
  17. ramp_idle = 0,
  18. ramp_up = 1,
  19. ramp_max = 2,
  20. ramp_down = 3,
  21. ramp_last = 4,
  22. };
  23. enum ramp_state ramp_sts=ramp_idle;
  24. int16 motor_pos = 0; // absolute step number
  25. int16 pos_inc=0; // motor_pos increment
  26. uint16 phase=0; // ccpPhase[phase_ix]
  27. uint8 phase_ix=0; // index to ccpPhase[]
  28. uint8 phase_inc; // phase_ix increment
  29. uint8 run_flg; // true while motor is running
  30. // ***************************
  31. // 1. keep track of total delay count
  32. uint32 ccpr; // 24.8 fixed point delay count
  33. uint32 c; // 24.8 fixed point delay count increment
  34. uint16 step_no; // progress of move
  35. uint16 step_down; // start of down-ramp
  36. uint16 move; // total steps to move
  37. uint16 midpt; // midpoint of move
  38. int16 denom; // 4.n+1 in ramp algo
  39. // Config data to make CCP1&2 generate quadrature sequence on PHASE pins
  40. // Action on CCP match: 8=set+irq; 9=clear+irq
  41. uint16 const ccpPhase[] = {0x909, 0x908, 0x808, 0x809}; // 00,01,11,10
  42. void current_on(){/* code as needed */} // motor drive current
  43. void current_off(){/* code as needed */} // reduce to holding value
  44. uint16 make16(uint8 l, uint8 r) {
  45. return (uint16) l << 8 + r;
  46. }
  47. // compiler-specific ISR declaration
  48. void __interrupt isr_motor_step(void) { // CCP1 match -> step pulse + IRQ
  49. ccpr += c; // next comparator value
  50. switch (ramp_sts) {
  51. case ramp_up: // accel
  52. if (step_no == midpt) { // midpoint: decel
  53. ramp_sts = ramp_down;
  54. // ***************************
  55. // 2. convert shift to multiplication
  56. // 3. avoid negative result from subtraction of unsigned values
  57. // denom = ((step_no - move) << 2) + 1;
  58. if(step_no > move)
  59. denom = ((step_no - move) * 4) + 1;
  60. else
  61. denom = ((move - step_no) * 4) - 1;
  62. if (!(move & 1)) { // even move: repeat last delay before decel
  63. denom += 4;
  64. break;
  65. }
  66. }
  67. // no break: share code for ramp algo
  68. case ramp_down: // decel
  69. if (step_no == move - 1) { // next irq is cleanup (no step)
  70. ramp_sts = ramp_last;
  71. break;
  72. }
  73. denom += 4;
  74. // calculate increment/decrement in delay count
  75. // ***************************
  76. // 3. avoid negative result from subtraction of unsigned values
  77. // c -= (c << 1) / denom; // ramp algorithm
  78. if(denom > 0)
  79. c -= (c << 1) / denom;
  80. else
  81. c += (c << 1) / -denom;
  82. if (c <= C_MIN) { // go to constant speed
  83. ramp_sts = ramp_max;
  84. step_down = move - step_no;
  85. c = C_MIN;
  86. break;
  87. }
  88. break;
  89. case ramp_max: // constant speed
  90. if (step_no == step_down) { // start decel
  91. ramp_sts = ramp_down;
  92. // ***************************
  93. // 2. convert shift to multiplication
  94. // 3. avoid negative result from subtraction of unsigned values
  95. // denom = ((step_no - move) << 2) + 1;
  96. denom = 5 - ((move - step_no) * 4);
  97. }
  98. break;
  99. default: // last step: cleanup
  100. ramp_sts = ramp_idle;
  101. current_off(); // reduce motor current to holding value
  102. CCP1IE = 0; // disable_interrupts(INT_CCP1);
  103. run_flg = false; // move complete
  104. break;
  105. } // switch (ramp_sts)
  106. if (ramp_sts != ramp_idle) {
  107. motor_pos += pos_inc;
  108. ++step_no;
  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()
  118. void motor_run(int16 pos_new) { // set up to drive motor to pos_new (absolute step#)
  119. if (pos_new < motor_pos) { // get direction & #steps
  120. move = motor_pos - pos_new;
  121. pos_inc = -1;
  122. phase_inc = 0xff;
  123. }
  124. else if (pos_new != motor_pos) {
  125. move = pos_new - motor_pos;
  126. pos_inc = 1;
  127. phase_inc = 1;
  128. } else return; // already there
  129. midpt = (move - 1) >> 1;
  130. c = C0;
  131. step_no = 0; // step counter
  132. denom = 1; // 4.n+1, n=0
  133. ramp_sts = ramp_up; // start ramp state-machine
  134. run_flg = true;
  135. T1CONbits.TMR1ON = 0; // stop timer1;
  136. ccpr = make16(TMR1H, TMR1L); // 16bit value of Timer1
  137. ccpr += 1000; // 1st step + irq 1ms after timer1 restart
  138. CCPR2H = CCPR1H = (ccpr >> 8);
  139. CCPR2L = CCPR1L = (ccpr & 0xff);
  140. phase_ix = (phase_ix + phase_inc) & 3;
  141. phase = ccpPhase[phase_ix];
  142. CCP1CON = phase & 0xff; // sets action on match
  143. CCP2CON = phase >> 8;
  144. current_on(); // current in motor windings
  145. CCP1IE = 1; // enable_interrupts(INT_CCP1);
  146. T1CONbits.TMR1ON = 1; // restart timer1;
  147. } // motor_run()
  148. void initialize() {
  149. di(); // disable_interrupts(GLOBAL);
  150. CCP1IE = 0; // disable_interrupts(INT_CCP1);
  151. CCP2IE = 0; // disable_interrupts(INT_CCP2);
  152. PORTC = 0; // output_c(0);
  153. TRISC = 0; // set_tris_c(0);
  154. T3CON = 0;
  155. T1CON = 0x35;
  156. INTCONbits.PEIE = 1;
  157. INTCONbits.RBIF = 0;
  158. ei(); // enable_interrupts(GLOBAL);
  159. } // initialize()