# steppermotor

Single stepper motor library (unipolar or bipolar)

Author | Richard Zengerink, Copyright © 2009..2010, all rights reserved.
Adapted-by | Rob Hamerling (2016)
Compiler | 2.4q5

Description

    Library for a single stepper motor.
                 Includes configurable startup- en slowdown-curves
                 and optionally user-defined control patterns.
                 Designed and tested with a unipolar motor,
                 but can be used with a bipolar motor as well.
                 Supports inverting and non-inverting buffer-ICs
    .
    Required declarations before including the library:
       This library uses 4 control pins to control a stepper motor.
       When all pins are in the same nibble (most efficient) declare an alias
       for this nibble, for example when pins pin_B0 through pin_B3 are used:
          alias stepper_coils  is  portB_low
       and set all the pins if this nibble to output:
          portB_low_direction = ALL_OUTPUT
       Alternatively with individual pins (not necessarily on the same nibble)
          alias stepper_coil1a is pin_B0
          alias stepper_coil2a is pin_B1
          alias stepper_coil1b is pin_C0
          alias stepper_coil2b is pin_C1
       and set these pins to output:
          pin_B0 = OUTPUT
          pin_B1 = OUTPUT
          pin_C0 = OUTPUT
          pin_C1 = OUTPUT
       The wiring of the 4 pins to the coils must of course match
       the bit patterns in the arrays below!
    .
       A constant array of bit patterns is required to
       specify the signal state for each half-step:
          const byte STEPPER_ARRAY[8] =
             {
             0b_0001,             -- coil 1a
             0b_0011,             -- coil 1a + 2a
             0b_0010,             -- coil 2a
             0b_0110,             -- coil 2a + 1b
             0b_0100,             -- coil 1b
             0b_1100,             -- coil 1b + 2b
             0b_1000,             -- coil 2b
             0b_1001              -- coil 2b + 1a
             }
      These bit patterns are examples for a unipolar stepper motor and
      are the defaults when the array is absent in the user program.
      The entries specify the bit pattern for every half step in
      clock-wise rotation.
      In full-step mode only the even entries of the array are used.
      With bipolar stepper motors or with special buffer-ICs
      the appropriate patterns need be defined by the user program.
      In any case the bit pattern should match the actual wiring and
      your definition of clockwise!
    .
      Specify a bit constant to indicate when you use an inverting
      buffer-IC to control the stepper motor:
          const bit STEPPER_INVERTING_BUFFER = TRUE
      When not specified the default behaviour is non-inverting.
    .
      A word constant must be declared which specifies the number of steps
      for a complete rotation of the stepper motor axis in full-step mode,
      for example:
         const word STEPPER_STEPS_PER_ROTATION = 200
    .
      A bit variable 'stepper_cw' must be declared to specify the direction of
      rotation. Value TRUE means 'clockwise' and FALSE 'counter-clockwise'.
         var bit stepper_cw = TRUE
      Make sure your wiring matches this setting and the way the stepper moves.
      The value may be changed dynamically by the user program.
    .
      A bit variable 'stepper_fullstep' must be declared to indicate
      that the stepper must run at full-steps (TRUE) or half-steps (FALSE).
         var bit stepper_fullstep = TRUE
      The value may be changed dynamically by the user program.
    .
    This library was initially designed for PICs with 16-bits wide Timer0.
    This excluded the use of midrange PICs, which have only 8-bits Timer0.
    A 16-bits timer is required to support a wide enough speedrange
    of stepper motors. When using a PIC without a 16-bits wide Timer0
    this revised version of the library automatically selects Timer3 or
    the PWM3 modules when present.
    .
    Available public procedures:
       stepper_run()        -- set motor speed (accellerate/decellerate smoothly)
       stepper_stop()       -- stop motor (decellerate smoothly)
       stepper_hold()       -- stop motor immediately and lock it (keep powered)
       stepper_accel()      -- set acceleration ratio (smooth accelleration)
       stepper_decel()      -- set decellaration ratio (smooth decelleration)
       stepper_detach()     -- stop motor immediately and release it (power off)
       stepper_attach()     -- lock motor in position (power on, no stepping)
       stepper_actual_rpm() -- return actual rpm

Notes

    - Log of changes 2016/02
       * loading of 16-bits timers by a procedure for proper sequence
       * changed global non-static variables which are used only in
         one procedure into local variables
       * added support for other Fosc values than 48 MHz
       * introduced a constant 'STEPPER_INVERTING_BUFFER' to support
         positive and negative logic for motor control (depending of buffer IC)
       * stepper_attach() uses current entry in stepper array in stead of all zero
       * added use of Timer3 for PICs with an 8-bit Timer0 (midrange)
       * fixed 'flippering' effect which occurred randomly when switching
         from half-step ccw to full-step cw rotation.
       * fixed very long first step when accellerating from zero speed.
       * added, improved, aligned comments
       * renamed several variables/constants/procedures
       * enforced Jallib standards, i.c. global names prefixed by  'stepper_'
    - Log of changes 2016/03
       * Added support for control pins not in the same nibble.
       * Stepper motor stops always on full-step position
       * Added support for use of 16-bits timer of PWM3 module when
         no 16-bits Timer0 or Timer3 is available (12/16f15xx).
       * Added function returning actual RPM (pos:cw, neg:ccw)
       * Added support for 16-bits timer0 of 16f183xx/188xx
       * All timers temporary disabled for (re-)loading.

Dependencies

No dependency found

## Summary

### Global variables/contants

- `var word stepper_set_speed = 0`
- `var byte stepper_step_index = 0`
- `var word stepper_steptimer_interval = 0`
- `var word stepper_actual_speed = 0`
- `var byte stepper_steptimer_byte[2] at stepper_steptimer_interval`
- `var bit stepper_to_stop = FALSE`
- `var word stepper_accel_ratio = 0`
- `var bit stepper_decel_active = FALSE`
- `var word stepper_decel_ratio = 0`
- `const word STEPPER_TIMER1_RELOAD = 65535 - word(target_clock / 4 / STEPPER_TIMER1_PRESCALE / 100)`
- `var bit stepper_slope_speedset = FALSE`
- `var bit stepper_accel_active = FALSE`
- `var bit stepper_running = FALSE`

### Procedures

- `stepper_accel(word in sec, word in rpm)`
- `stepper_hold()`
- `stepper_timer1_off()`
- `stepper_attach()`
- `stepper_slope_timer_isr()`
- `stepper_timer_load(word in t)`
- `stepper_steptimer_isr()`
- `stepper_decel(word in sec, word in rpm)`
- `stepper_run(word in rpm)`
- `stepper_timer1_on()`
- `stepper_detach()`
- `stepper_stop()`
- `stepper_control(byte in p)`

### Functions

- `stepper_actual_rpm() return sword`
- `stepper_stepticks(word in rpm) return word`

## API details

### Global variables/contants

- `var word stepper_set_speed = 0`

      desired speed in 1/10 rpm

- `var byte stepper_step_index = 0`

      index in step pattern array

- `var word stepper_steptimer_interval = 0`

      holds actual interval for stepper timer

- `var word stepper_actual_speed = 0`

      actual speed in 1/10 rpm

- `var byte stepper_steptimer_byte[2] at stepper_steptimer_interval`

      THMxH/TMRxL

- `var bit stepper_to_stop = FALSE`

      is set during stop slope and reset after stop

- `var word stepper_accel_ratio = 0`

      accelleration ratio in rpm/sec

- `var bit stepper_decel_active = FALSE`

      is set during decelleration

- `var word stepper_decel_ratio = 0`

      decelleration ratio in rpm/sec

- `const word STEPPER_TIMER1_RELOAD = 65535 - word(target_clock / 4 / STEPPER_TIMER1_PRESCALE / 100)`

  No documentation found

- `var bit stepper_slope_speedset = FALSE`

      TRUE while accellerating/decellerating

- `var bit stepper_accel_active = FALSE`

      is set during accelleration

- `var bit stepper_running = FALSE`

      is set during run and reset after stop

### Procedures

- `stepper_accel(word in sec, word in rpm)`

      Descr: Determine accelleration ratio
      Input: - sec      (word) number of 0.1 seconds
       rpm      (word) number of 0.1 RPM
      Notes: - The stepper speed will increase with # RPMs per 10 ms
      For example: with stepper_accel(100,3000)
      the stepper accellerates with 300 RPM in 10 seconds (30 RPM/sec)
      or accellerate in 2 seconds from 0 to 60 RPM or from 50 to 110 RPM, etc.
       Accelleration (and decelleration) settings are only taken into account
      when stepper speed is changed, e.g. with stepper_run() or stepper_stop()
      and may be changed any time.

- `stepper_hold()`

      Descr: Immediately stop and lock stepper
      Notes: Stepper locked on full-step boundary.
      This prevents a (half) step in the wrong direction when
      switching from half to full-step mode at restart.

- `stepper_timer1_off()`

      Deactivate timer1

- `stepper_attach()`

      Descr: (re-)power one coil

- `stepper_slope_timer_isr()`

       Accelleration/Decelleration Timer interrupt handler -------
      When Timer1 active this handler is called every 0.01 seconds
      When accelerating or decellerating the steptime is adjusted.

- `stepper_timer_load(word in t)`

      Load stepper timer
      Timer is temporarily stopped
      (PWM3 module has double buffering, no need to stop)

- `stepper_steptimer_isr()`

         Step timer interrupt handler ------

- `stepper_decel(word in sec, word in rpm)`

      Descr: Determine decelleration ratio
      Input: - sec      (word) number of 0.1 seconds
       rpm      (word) number of 0.1 RPM
      Notes: The stepper speed will decrease with # RPMs per 10 ms
      See also the notes with stepper_accel()

- `stepper_run(word in rpm)`

      Descr: Set stepper speed to desired RPM
      Input: data (word) in 0.1 RPM   (50 means 5 RPM)
      Notes: - Power to one (or two with halfstep) coils is applied automatically
       Depending on current speed and the specified accelleration and
      decelleration settings the stepper speed may change gradually.
       Use stepper_detach() to remove power (automatic with rpm zero)

- `stepper_timer1_on()`

      Activate timer1 interrupts (100 per second)

- `stepper_detach()`

      Descr: Immediately stop stepper and release the stepper (all coils power off)

- `stepper_stop()`

      Descr: Stop the stepper gradually according to decelleration ratio
      Notes: One coil (maybe 2 with half-step) will remain powered, locks the stepper
      Use stepper_detach() to remove power and unlock the stepper

- `stepper_control(byte in p)`

      Control the stepper motor
      Activate the coils with pattern 'p' (low nibble)
      Control by nibble or individual pins
      Take care of inverting steppermotor buffer

### Functions

- `stepper_actual_rpm() return sword`

      Descr:   Obtain current stepper speed RPM
      Returns: The actual RPM in units of 0.1 RPM
      A negative value means counter-clockwise rotation

- `stepper_stepticks(word in rpm) return word`

      Descr:   Calculate pulse width for specified RPM
      Returns: Steptime in timer ticks
      Notes: - Prescaler value may be changed depending on RPM
      Timer0: 1:2 for high RPM,  1:256 for low RPM
      Timer3: 1:1                1:8
      PWM3:   1:1                1:8
      (PWM3 allows 1:128, but is not needed with LFINTOSC at 31 KHz)

## Related samples

Here are the list of samples which use this library:

16f1618 | 16f1618_steppermotor.jal
18f25k50 | 18f25k50_steppermotor.jal