This is the fifth day of my participation in Gwen Challenge

Recently, I found a stepper motor module I bought before, which was driven by 5V microcontroller. Suddenly want to try to use STM32F103 MCU 3.3V direct drive ULN2003 this chip.

The ULN2003 can be directly driven at 3.3V. The motor drive process is shared below.

Take a look at the actual picture first

The microcontroller uses STM32F103C8T6 minimum system. The motor and drive board are complete modules bought online.

The schematic diagram of the drive board is as follows

The stepper motor uses 5-line 4-phase DC deceleration stepper motor Diameter: 28mm voltage: 5V stepping Angle: 5.625 x 1/64 deceleration ratio: 1/64

Interval Angle: 5.625/64 = 0.087 degrees (that is, theoretically, if you give a pulse, the external shaft of the motor rotates by 0.087 degrees), that is, if the internal rotor of a pulse rotates by 5.625 degrees, but the external shaft rotates by 0.087 degrees due to 64 times deceleration, then if the external shaft rotates by 0.087 degrees, 360/0.087=4096 pulses are required. With a 4-phase 8-beat drive, 8 pulses are a cycle, so 4096/8=512 cycles are needed, and the external axis has just turned one turn.

Motor drive is generally divided into three methods

1. 1 phase excitation method: each moment only one coil is connected, the other rest.

Simple, low power consumption, good accuracy.

(Disadvantages) Small torque, large vibration, each excitation signal is a nominal Angle. Phase excitation method A->B->C->D

Two, 2 phase excitation method: every moment there are two coil conduction.

(advantages) large torque, small vibration.

Each excitation signal is at a nominal Angle. 2 phase excitation AB->BC->CD->DA

Three, 1-2 phase excitation method: 1 phase and 2 phase alternating conduction.

(Advantage) High precision, smooth operation, each excitation signal rotation 1/2 nominal Angle, called half step drive. (The first two are called 4-phase 4-beat, and this one is called 4-phase 8-beat)

1-2 Phase excitation A–>AB–>B –> BC –>C –>CD –>D –>DA

Here’s how to do all three in code

ULN2003 This small drive board IN1, IN2, IN3, IN4 four pins and the IO port of the single chip microcomputer are directly connected with Dupont wire, in order to facilitate control, first define the IO port to be used. Directly in the LED project modification.

Create a new bSP_motor. H header file and declare the port in the header file.

#define LA PBout(6) //A phase #define LB PBout(7) //B phase #define LC PBout(8) //C phase #define LD PBout(9) //D phase /* Define the GPIO port for motor connection, The user only needs to modify the following code to change the control motor pin */ #define LA_GPIO_PORT GPIOB /* GPIO port */ #define LA_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO port clock */ #define LA_GPIO_PIN GPIO_Pin_6 #define LB_GPIO_PORT GPIOB #define LB_GPIO_CLK RCC_APB2Periph_GPIOB #define LB_GPIO_PIN GPIO_Pin_7 #define LC_GPIO_PORT GPIOB #define LC_GPIO_CLK RCC_APB2Periph_GPIOB #define LC_GPIO_PIN GPIO_Pin_8 #define LD_GPIO_PORT GPIOB #define LD_GPIO_CLK RCC_APB2Periph_GPIOB #define LD_GPIO_PIN GPIO_Pin_9Copy the code

Here the use of PB port 6, 7, 8, 9 four ports to control, the port uses the method defined by the bit belt, so that it is more convenient to control with the program. You can consult relevant information about bitband definition. The port and clock were renamed using macro definitions. In this way, when you need to change the IO port later, you only need to change the IO port in the header file, without changing the code in the program, which is convenient for program transplantation.

The driver code shall be written below. First, the 1-phase excitation method shall be used, that is, the 4 IO ports shall take turns to be high level, and the high level can be successively given to LA, LB, LC and LD by using bitband operation. In order to make the operation more convenient, the values of these four ports form a byte, and stored in an array, through the subscript to call the number in the array in turn. Here LA is the least significant byte bit0 and LD is the third byte bit3.

Thus, when the motor conduction phase sequence is D-C-B-A, the value in the array is defined as

u8 phasecw[4] = {0x08, 0x04, 0x02, 0x01};
Copy the code

The motor conduction phase sequence is A-B-C-D, and the value in the array is

u8 phaseccw[4] = {0x01, 0x02, 0x04, 0x08};
Copy the code

Create a new bsp_motor.c file and write a function to call the array

void MotorCW( void ) { u8 i; u8 temp = 0; for( i = 0; i < 4; i++ ) { temp = phasecw[i]; LD = ( temp >> 3 ) & 0x01; // set bit4 to LC = (temp >> 2) &0x01; LB = ( temp >> 1 ) & 0x01; LA = ( temp >> 0 ) & 0x01; // take the value of bit0 delay_ms(2); }}Copy the code

Through A for loop, it reads the values in the array successively, and then reads the values of the corresponding bits according to the positions of phases A, B, C, and D, and directly assigns the values to the IO port. This motor drive function is written, in the main program directly call this function can control the motor rotation.

If you want to change to 2-phase excitation, just replace the data in the array.

U8 phasecw[4] = {0x0c, 0x06, 0x03,0x09}; Dc-cb-ba-ad U8 PhasECCW [4] = {0x03, 0x06, 0x0C, 0x09}; dC-CB-BA-AD U8 PhasECCW [4] = {0x03, 0x06, 0x0C, 0x09}; // Reverse motor conduction phase sequence AB-BC-Cd-daCopy the code

If you want to change to 1-2 phase excitation, you just change the values in the array.

u8 phasecw[8] = {0x08, 0x0c, 0x04, 0x06, 0x02, 0x03, 0x01, 0x09}; Dc-cb-b-ba-a U8 PhasECCW [8] = {0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x89}; // Reverse motor conduction phase sequence A-AB-B-BC-C-CD-daCopy the code

With the 1-2 phase excitation control, you need to send 8 pulses at a time, which is 4 phases and 8 beats, so you need to send 8 arrays for a cycle, and change the number of cycles in the for loop to 8.

void MotorCW( void ) { u8 i; u8 temp = 0; for( i = 0; i < 8; i++ ) { temp = phasecw[i]; LD = ( temp >> 3 ) & 0x01; // set bit4 to LC = (temp >> 2) &0x01; LB = ( temp >> 1 ) & 0x01; LA = ( temp >> 0 ) & 0x01; // take the value of bit0 delay_ms(2); }}Copy the code

Then call this function directly from the main program to get the motor running.

int main( void ) { NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 ); Motor_GPIO_Config(); while ( 1 ) { MotorCW(); }}Copy the code

So it seems that driving the motor is very simple with keil simulation simulation waveform

1 phase excitation method D-C-B-A

2 phase excitation method DC-CB-BA-AD

1-2 phase excitation method D-DC-C-CB-B-BA-A-AD

The waveform is consistent with the theory, indicating that the drive is correct.

Here should be over, but also hand cheap to the main program added a LED flash program, this plus something wrong.

int main( void ) { u16 cnt = 0; NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 ); LED_GPIO_Config(); Motor_GPIO_Config(); while ( 1 ) { LED1_TOGGLE; MotorCW(); delay_ms(20); }}Copy the code

A 20ms delay is added to the main program and the LED light is flipped. After the program burns in, it turns out the motor won’t work. What’s going on here? Let’s take a look at the simulated waveform.

The problem is found in this view. Why does the waveform of A suddenly become longer?

u8 phasecw[4] = {0x08, 0x04, 0x02, 0x01};
Copy the code

The values given in the array are 8, 4, 2 and 1 successively, that is, phase D, C, B and A are high level in turn. The high level of other three-phase only lasts for 2ms, but the level of phase A lasts for more than 20 ms. What is the reason? A careful analysis of the program execution flow revealed the problem. In the for cycle, four phases are assigned in turn, and A phase is assigned the last value. When item A is assigned A value, the other three items are low level, and item A is high level. Then the program exits the FOR cycle and returns to the main program. After removing the 20ms delay, the motor runs normally and the waveform is normal. In other words, it is this delay that affects the rotation of the motor.

So you can’t use delay in the main program? The LED flicker function is no longer available? Can also let a motor driver to the MCU commandeer not? Of course, this is not possible. We must find out the root cause of this problem. Since the high level of item A has not been reset after the last assignment to item A, please manually reset item A. Force the level of item A to zero.

Add a reset function

void MotorStop( void )
{
    LA = 0;
    LB = 0;
    LC = 0;
    LD = 0;
}
Copy the code

This function forces the four phases to be reset, and then forces the four phases to be reset after each cycle of motor drive.

void MotorCW( void ) { u8 i; u8 temp = 0; for( i = 0; i < 4; i++ ) { temp = phasecw[i]; LD = ( temp >> 3 ) & 0x01; // set bit4 to LC = (temp >> 2) &0x01; LB = ( temp >> 1 ) & 0x01; LA = ( temp >> 0 ) & 0x01; // take the value of bit0 delay_ms(2); } MotorStop(); // All phases need to be reset at the end of a cycle, otherwise the last term, if set to high, will remain high. }Copy the code

After the reset function is added, 20ms delay is still added to the main program to continue to view the waveform simulation.

Now the waveform is normal, the motor slowly turns after downloading the program, and the LED lights start flashing. It shows that at the beginning of the drive, only the logic of phase, but did not consider the problem of phase reset, considering the problem is still not comprehensive.

Down in the main program with the motor positive and negative rotation function, so that the motor is turning a circle, and then reverse a circle.

int main( void ) { u16 cnt = 0; NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 ); LED_GPIO_Config(); Motor_GPIO_Config(); while ( 1 ) { cnt++; If (CNT <= 512) // if(CNT <= 512) Else if(CNT <= 1024) MotorCCW(); // invert else {CNT = 0; LED1_TOGGLE; delay_ms( 500 ); }}}Copy the code

Here, 4-phase 8-beat drive is adopted, 8 pulses are a cycle, so 4096/8=512 cycles are needed, and the external axis has just improved one cycle. The counter turns forward when it is less than 512, and the timer reverses when it is between 512 and 1024. Then the LED light flips once, at a delay of 500ms. Here, we should also pay attention to a problem. In the motor drive function, the delay time of each pulse should not be less than 2ms after the actual test. When the delay is too small, the motor jitter is serious, but it will not rotate. The greater the delay, the slower the motor rotation.

Up to this point the motor driver has worked perfectly.