motor1.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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. uint16 ccpr; // copy of CCPR1&2
  31. uint16 c; // integer delay count
  32. uint16 step_no; // progress of move
  33. uint16 step_down; // start of down-ramp
  34. uint16 move; // total steps to move
  35. uint16 midpt; // midpoint of move
  36. uint32 c32; // 24.8 fixed point delay count
  37. int16 denom; // 4.n+1 in ramp algo
  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. uint16 const ccpPhase[] = {0x909, 0x908, 0x808, 0x809}; // 00,01,11,10
  41. void current_on(){/* code as needed */} // motor drive current
  42. void current_off(){/* code as needed */} // reduce to holding value
  43. uint16 make16(uint8 l, uint8 r) {
  44. return (uint16) l << 8 + r;
  45. }
  46. // compiler-specific ISR declaration
  47. void __interrupt isr_motor_step(void) { // CCP1 match -> step pulse + IRQ
  48. ccpr += c; // next comparator value
  49. switch (ramp_sts) {
  50. case ramp_up: // accel
  51. if (step_no == midpt) { // midpoint: decel
  52. ramp_sts = ramp_down;
  53. denom = ((step_no - move) << 2) + 1;
  54. if (!(move & 1)) { // even move: repeat last delay before decel
  55. denom += 4;
  56. break;
  57. }
  58. }
  59. // no break: share code for ramp algo
  60. case ramp_down: // decel
  61. if (step_no == move - 1) { // next irq is cleanup (no step)
  62. ramp_sts = ramp_last;
  63. break;
  64. }
  65. denom += 4;
  66. c32 -= (c32 << 1) / denom; // ramp algorithm
  67. // beware confict with foreground code if long div not reentrant
  68. c = (c32 + 128) >> 8; // round 24.8format->int16
  69. if (c <= C_MIN) { // go to constant speed
  70. ramp_sts = ramp_max;
  71. step_down = move - step_no;
  72. c = C_MIN;
  73. break;
  74. }
  75. break;
  76. case ramp_max: // constant speed
  77. if (step_no == step_down) { // start decel
  78. ramp_sts = ramp_down;
  79. denom = ((step_no - move) << 2) + 5;
  80. }
  81. break;
  82. default: // last step: cleanup
  83. ramp_sts = ramp_idle;
  84. current_off(); // reduce motor current to holding value
  85. CCP1IE = 0; // disable_interrupts(INT_CCP1);
  86. run_flg = false; // move complete
  87. break;
  88. } // switch (ramp_sts)
  89. if (ramp_sts != ramp_idle) {
  90. motor_pos += pos_inc;
  91. ++step_no;
  92. CCPR2H = CCPR1H = (ccpr >> 8); // timer value at next CCP match
  93. CCPR2L = CCPR1L = (ccpr & 0xff);
  94. if (ramp_sts != ramp_last) // else repeat last action: no step
  95. phase_ix = (phase_ix + phase_inc) & 3;
  96. phase = ccpPhase[phase_ix];
  97. CCP1CON = phase & 0xff; // set CCP action on next match
  98. CCP2CON = phase >> 8;
  99. } // if (ramp_sts != ramp_idle)
  100. } // isr_motor_step()
  101. void motor_run(int16 pos_new) { // set up to drive motor to pos_new (absolute step#)
  102. if (pos_new < motor_pos) { // get direction & #steps
  103. move = motor_pos - pos_new;
  104. pos_inc = -1;
  105. phase_inc = 0xff;
  106. }
  107. else if (pos_new != motor_pos) {
  108. move = pos_new - motor_pos;
  109. pos_inc = 1;
  110. phase_inc = 1;
  111. } else return; // already there
  112. midpt = (move - 1) >> 1;
  113. c = C0;
  114. c32 = c << 8; // keep c in 24.8 fixed-point format for ramp calcs
  115. step_no = 0; // step counter
  116. denom = 1; // 4.n+1, n=0
  117. ramp_sts = ramp_up; // start ramp state-machine
  118. run_flg = true;
  119. T1CONbits.TMR1ON = 0; // stop timer1;
  120. ccpr = make16(TMR1H, TMR1L); // 16bit value of Timer1
  121. ccpr += 1000; // 1st step + irq 1ms after timer1 restart
  122. CCPR2H = CCPR1H = (ccpr >> 8);
  123. CCPR2L = CCPR1L = (ccpr & 0xff);
  124. phase_ix = (phase_ix + phase_inc) & 3;
  125. phase = ccpPhase[phase_ix];
  126. CCP1CON = phase & 0xff; // sets action on match
  127. CCP2CON = phase >> 8;
  128. current_on(); // current in motor windings
  129. CCP1IE = 1; // enable_interrupts(INT_CCP1);
  130. T1CONbits.TMR1ON = 1; // restart timer1;
  131. } // motor_run()
  132. void initialize() {
  133. di(); // disable_interrupts(GLOBAL);
  134. CCP1IE = 0; // disable_interrupts(INT_CCP1);
  135. CCP2IE = 0; // disable_interrupts(INT_CCP2);
  136. PORTC = 0; // output_c(0);
  137. TRISC = 0; // set_tris_c(0);
  138. T3CON = 0;
  139. T1CON = 0x35;
  140. INTCONbits.PEIE = 1;
  141. INTCONbits.RBIF = 0;
  142. ei(); // enable_interrupts(GLOBAL);
  143. } // initialize()