In the introduction to stepper motors we showed the basics of how they work. Now we need the software that will control our motors. As of today we have three stepper click boards. This article will introduce you how to use the reworked AccelStepper library (a very good and popular lib) to build your own complete solution.
The library is reworked in pure C for usage with our compilers and can be used for all three stepper clicks. Small modification are needed, depending on which MCU you are using, to achieve good timing and precision of the controlled stepper motor.
Stepper 3 click
Stepper 3 click board carries Texas Instruments's ULN2003 Darlington transistors array. The board allows more freedom than previous two stepper click boards. Each phase of the stepper motor can be controlled directly by the user which provides great control of the stepper motor and opens many possibilities for exploring.
The click uses only 4 GPIO pins and allows usage of internal 5 V power supply or usage of external power supply. The voltage from the external supply should be in range 0 V to 30 V. There are also LEDs for every single phase which represents the visual feedback to the user about current condition.
Stepper Library
The reworked library can be used with all our compilers and for almost any kind of stepper driver including our three stepper click boards. As we said some modifications are needed to adapt the library for your MCU and your kind of driver.
The adaptation should start from the HAL layer and init function. The library requires configuration of the MCU timer to achieve proper functionality. What we need to do is to configure MCU timer counter increments every one microsecond. Implementation of this kind of job requires better knowledge of the timers. In other words, you will need the datasheet. Our TimerCalculator can also be very helpful because it will give you an idea what registers should be edited.
void stepper_hal_init( uint16_t cpu_MHz ) { #if defined( __MIKROC_PRO_FOR_ARM__ ) RCC_APB1ENR.TIM2EN = 1; TIM2_CR1.CEN = 0; TIM2_PSC = ( cpu_MHz ); TIM2_DIER.UIE = 1; TIM2_CR1.CEN = 1; #endif } uint16_t stepper_hal_micros( void ) { uint16_t res = 0; #if defined( __MIKROC_PRO_FOR_ARM__ ) res = TIM2_CNT; #endif return res; }
This example shows how to do this for STM32F10x MCUs. We are setting up the prescaler at exactly the same value like MCU's frequency (in MHz) because we want our timer increment counter at 1.000.000 times per second. Now the function stepper_hal_micros() returns the content of timer register which actually represent the time in microseconds and this function is used for calculation of the delay between steps in higher layer.
It is important to say that the size of the counter register will have an impact on the functionality of the library. In this case TIM2_CNT is a 16 bit register which means that the maximum value that can be stored inside is 65535. That means that every 65535 microseconds our counter will rollover and start to count again from zero. As you guess this means that the slowest speed that we can achieve is delay of 65535 microseconds between steps or 15 steps per second.
Adaptation for PIC microcontrollers is little different. PIC has 8 bit registers which limits us to very high minimum speed because of rollover every 255 microseconds. There is a solution for this. Not all, but some PIC timers allow us to use 2 registers for the time counter. One register will hold the higher part of our timer and the second register will hold the lower part of the timer. In that case our stepper_hal_micros() will return the value composed of both registers.
void stepper_hal_init ( uint16_t cpu_MHz ) { #if defined( __MIKROC_PRO_FOR_PIC__ ) cpu_MHz /= 4; if( cpu_MHz == 1 ) T5CON = 0x01; else if( cpu_MHz == 2 ) T5CON = 0x11; else if( cpu_MHz == 4 ) T5CON = 0x21; else T5CON = 0x31; TMR5H = 0; TMR5L = 0; #endif } uint16_t stepper_hal_micros ( void ) { uint16_t res = 0; #if defined( __MIKROC_PRO_FOR_PIC__ ) res |= TMR5H; res <<= 8; res |= TMR5L; #endif return res; }
The adaptation technique for other MCU types is pretty similar. There are also other solutions for slower , for example you can configure timer to increment counter every 10 microseconds and then from stepper_hal_micros you can return value multiplied by 10. That will allow lower steps per second value but also it can have impact to the timing precision. The choice is yours.
Implementation for Other Stepper Boards
As the implementation for Stepper 3 click board requires defining the pins inside the application and nothing more, the situation with stepper 2 and stepper click is a little bit different. For stepper boards where is no access to the every single phase, functions for step forward and step back must be implemented and then assigned as function pointers to the stepper library.
void forward( void ) { STEPPER_DIR = 0; ST_PIN = 0; ST_PIN = 1; } void backward( void ) { STEPPER_DIR = 1; ST_PIN = 0; ST_PIN = 1; } void main() { stepper_init( 0, 72, false, false, true ); stepper_init_fp( forward, backward ); stepper_set_max_speed( 30.0 ); stepper_set_speed( 30.0 ); while( 1 ) { stepper_run_speed(); } }
As you can see first of all we have defined the functions for forward and backward step and then after the initialization we assign those functions to the function pointers. After that, what you see, is just a simple test procedure for the library.
Summary
Library can be downloaded from our Libstock page. You can make your own improvements and adaptation. It is very simple library and in same time usable on almost any kind of unipolar motor. Examples of implementation can be found inside the packages for our compilers but also on many other projects.