motor3.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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. #include <assert.h>
  16. // ramp state-machine states
  17. enum ramp_state {
  18. ramp_idle = 0,
  19. ramp_up = 1,
  20. ramp_const = 2,
  21. ramp_down = 3,
  22. };
  23. // ***************************
  24. // 1. Define state variables using custom strong types
  25. // initial setup
  26. enum ramp_state ramp_sts;
  27. position_t motor_position;
  28. position_t m; // target position
  29. position_t m2; // midpoint or point where acceleration changes
  30. direction_t d; // direction of traval -1 or +1
  31. // curent state along travel
  32. step_t i; // step number
  33. c_t c; // 24.8 fixed point delay count increment
  34. ccpr_t ccpr; // 24.8 fixed point delay count
  35. phase_ix_t phase_ix; // motor phase index
  36. // ***************************
  37. // 2. Surround all literal values with the "literal" keyword
  38. // Config data to make CCP1&2 generate quadrature sequence on PHASE pins
  39. // Action on CCP match: 8=set+irq; 9=clear+irq
  40. phase_t const ccpPhase[] = {
  41. literal(0x909),
  42. literal(0x908),
  43. literal(0x808),
  44. literal(0x809)
  45. }; // 00,01,11,10
  46. void current_on(){/* code as needed */} // motor drive current
  47. void current_off(){/* code as needed */} // reduce to holding value
  48. // ***************************
  49. // 3. Refactor code to make it easier to understand
  50. // and relate to the documentation
  51. bool busy(){
  52. return ramp_idle != ramp_sts;
  53. }
  54. // set outputs to energize motor coils
  55. void update(ccpr_t ccpr, phase_ix_t phase_ix){
  56. // energize correct windings
  57. const phase_t phase = ccpPhase[phase_ix];
  58. CCP1CON = phase & literal(0xff); // set CCP action on next match
  59. CCP2CON = phase >> literal(8);
  60. // timer value at next CCP match
  61. CCPR1H = literal(0xff) & (ccpr >> literal(8));
  62. CCPR1L = literal(0xff) & ccpr;
  63. }
  64. // compiler-specific ISR declaration
  65. // ***************************
  66. // 4. Rewrite interrupt handler in a way which mirrors the orginal
  67. // description of the algorithm and minimizes usage of state variable,
  68. // accumulated values, etc.
  69. void __interrupt isr_motor_step(void) { // CCP1 match -> step pulse + IRQ
  70. // *** possible exception
  71. // motor_position += d;
  72. // use the following to avoid mixing exception policies which is an error
  73. if(d < 0)
  74. --motor_position;
  75. else
  76. ++motor_position;
  77. // *** possible exception
  78. ++i;
  79. // calculate next difference in time
  80. for(;;){
  81. switch (ramp_sts) {
  82. case ramp_up: // acceleration
  83. if (i == m2) {
  84. ramp_sts = ramp_down;
  85. continue;
  86. }
  87. // equation 13
  88. // *** possible negative overflow on update of c
  89. c -= literal(2) * c / (literal(4) * i + literal(1));
  90. if(c < C_MIN){
  91. c = C_MIN;
  92. ramp_sts = ramp_const;
  93. // *** possible exception
  94. m2 = m - i; // new inflection point
  95. continue;
  96. }
  97. break;
  98. case ramp_const: // constant speed
  99. if(i > m2) {
  100. ramp_sts = ramp_down;
  101. continue;
  102. }
  103. break;
  104. case ramp_down: // deceleration
  105. if (i == m) {
  106. ramp_sts = ramp_idle;
  107. current_off(); // reduce motor current to holding value
  108. CCP1IE = literal(0); // disable_interrupts(INT_CCP1);
  109. return;
  110. }
  111. // equation 14
  112. // *** possible positive overflow on update of c
  113. // note: re-arrange expression to avoid negative result
  114. // from difference of two unsigned values
  115. c += literal(2) * c / (literal(4) * (m - i) - literal(1));
  116. if(c > C0){
  117. c = C0;
  118. }
  119. break;
  120. default:
  121. // should never arrive here!
  122. assert(false);
  123. } // switch (ramp_sts)
  124. break;
  125. }
  126. assert(c <= C0 && c >= C_MIN);
  127. // *** possible exception
  128. ccpr = literal(0xffffff) & (ccpr + c);
  129. phase_ix = (phase_ix + d) & literal(3);
  130. update(ccpr, phase_ix);
  131. } // isr_motor_step()
  132. // set up to drive motor to pos_new (absolute step#)
  133. void motor_run(position_t new_position) {
  134. if(new_position > motor_position){
  135. d = literal(1);
  136. // *** possible exception
  137. m = new_position - motor_position;
  138. }
  139. else
  140. if(motor_position > new_position){
  141. d = literal(-1);
  142. // *** possible exception
  143. m = motor_position - new_position;
  144. }
  145. else{
  146. d = literal(0);
  147. m = literal(0);
  148. ramp_sts = ramp_idle; // start ramp state-machine
  149. return;
  150. }
  151. i = literal(0);
  152. m2 = m / literal(2);
  153. ramp_sts = ramp_up; // start ramp state-machine
  154. T1CONbits.TMR1ON = literal(0); // stop timer1;
  155. current_on(); // current in motor windings
  156. c = C0;
  157. ccpr = (TMR1H << literal(8) | TMR1L) + C0 + literal(1000);
  158. phase_ix = d & literal(3);
  159. update(ccpr, phase_ix);
  160. CCP1IE = literal(1); // enable_interrupts(INT_CCP1);
  161. T1CONbits.TMR1ON = literal(1); // restart timer1;
  162. } // motor_run()
  163. void initialize() {
  164. di(); // disable_interrupts(GLOBAL);
  165. motor_position = literal(0);
  166. CCP1IE = literal(0); // disable_interrupts(INT_CCP1);
  167. CCP2IE = literal(0); // disable_interrupts(INT_CCP2);
  168. PORTC = literal(0); // output_c(0);
  169. TRISC = literal(0); // set_tris_c(0);
  170. T3CON = literal(0);
  171. T1CON = literal(0x35);
  172. INTCONbits.PEIE = literal(1);
  173. INTCONbits.RBIF = literal(0);
  174. ei(); // enable_interrupts(GLOBAL);
  175. } // initialize()