硬件准备
一块主控板STM32F103C8T6
一块ULN2003步进电机驱动板
一个五线四相步进电机
方案实现
接线:
ULN2003 | STM32F103C8T6 |
IN1 | PA0 |
IN2 | PA1 |
IN3 | PA3 |
IN4 | PA4 |
- | GND |
+(5V-12V) | 5V |
PS:①STM32如果用STLink供电,ULN2003的+可以接在STlink的5V或者STM32的5V上面
②如果STM32用锂电池供电,可以用3.7V锂电池,那么ULN2003需要外接电源,因为给STM32用3.7V供电,5V引脚口实际电压只有3.5V左右,带不动步进电机,注意让ULN2003与STM32供地,供地是为了让两者的电平信号一致
③如果STM32用5V锂电池供电,注意只能接在5V引脚口,同样ULN2003要么在外接一块电池,要么与STM32并联
接线如图所示:供电自行选择
代码实现:
Stepper.c代码如下
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Stepper.h"
uint8_t STEP; // 用于存储电机正在走过的整步编号
/**
* @brief 步进电机输出端GPIO初始化函数
* @param 无
* @retval 无
*/
void Stepper_GPIOInit(void)
{
// 选择PA0,PA1,PA2,PA3分别为相A,B,C,D的输出
RCC_APB2PeriphClockCmd(Stepper_CLK, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStruct.GPIO_Pin = Stepper_LA | Stepper_LB | Stepper_LC | Stepper_LD | StepperL_LA | StepperL_LB | StepperL_LC | StepperL_LD;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(Stepper_Output_GPIO, &GPIO_InitStruct);
GPIO_ResetBits(Stepper_Output_GPIO, Stepper_LA | Stepper_LB | Stepper_LC | Stepper_LD);
}
/**
* @brief 电机停转函数
* @param 无
* @retval 无
*/
void Stepper_Stop(void)
{
GPIO_ResetBits(Stepper_Output_GPIO, Stepper_LA | Stepper_LB | Stepper_LC | Stepper_LD | StepperL_LA | StepperL_LB | StepperL_LC | StepperL_LD);
}
/**
* @brief 4拍单相整步驱动函数
* @param StepNum 整步编号,0~3对应A~D
* @param Delay_Time_xms 每步旋转后延时时间x ms,用于控制步进电机速度(一般需大于等于2)
* @retval 无
*/
void Stepper_SingleStep(uint8_t StepNum, uint16_t Delay_Time_xms)
{
switch(StepNum)
{
case 0: // A
GPIO_WriteBit(Stepper_Output_GPIO, Stepper_LA, Bit_SET);
GPIO_WriteBit(Stepper_Output_GPIO, Stepper_LB | Stepper_LC | Stepper_LD, Bit_RESET);
GPIO_WriteBit(Stepper_Output_GPIO, StepperL_LA, Bit_SET);
GPIO_WriteBit(Stepper_Output_GPIO, StepperL_LB | StepperL_LC | StepperL_LD, Bit_RESET);
break;
case 1: // B
GPIO_WriteBit(Stepper_Output_GPIO, Stepper_LB, Bit_SET);
GPIO_WriteBit(Stepper_Output_GPIO, Stepper_LA | Stepper_LC | Stepper_LD, Bit_RESET);
GPIO_WriteBit(Stepper_Output_GPIO, StepperL_LB, Bit_SET);
GPIO_WriteBit(Stepper_Output_GPIO, StepperL_LA | StepperL_LC | StepperL_LD, Bit_RESET);
break;
case 2: // C
GPIO_WriteBit(Stepper_Output_GPIO, Stepper_LC, Bit_SET);
GPIO_WriteBit(Stepper_Output_GPIO, Stepper_LA | Stepper_LB | Stepper_LD, Bit_RESET);
GPIO_WriteBit(Stepper_Output_GPIO, StepperL_LC, Bit_SET);
GPIO_WriteBit(Stepper_Output_GPIO, StepperL_LA | StepperL_LB | StepperL_LD, Bit_RESET);
break;
case 3: // D
GPIO_WriteBit(Stepper_Output_GPIO, Stepper_LD, Bit_SET);
GPIO_WriteBit(Stepper_Output_GPIO, Stepper_LA | Stepper_LB | Stepper_LC, Bit_RESET);
GPIO_WriteBit(Stepper_Output_GPIO, StepperL_LD, Bit_SET);
GPIO_WriteBit(Stepper_Output_GPIO, StepperL_LA | StepperL_LB | StepperL_LC, Bit_RESET);
break;
default: break;
}
Delay_ms(Delay_Time_xms); // 延时,控制电机速度
Stepper_Stop(); // 断电,防止电机过热
}
/**
* @brief 步进电机按步旋转
* @param direction 电机旋转方向,可以是Foreward(正传)或者Reversal(反转)
* @param step 电机转过的步数
* @param Delay_Time_xms 每步旋转后延时时间x ms,用于控制步进电机速度(一般需大于等于2)
* @retval 无
*/
void Stepper_RotateByStep(RotDirection direction, uint32_t step, uint16_t Delay_Time_xms)
{
for (uint32_t i = 0; i < step; i ++)
{
if (direction == Foreward) // 电机正传
{
STEP ++;
if (STEP > 3)
{
STEP = 0;
}
}
else if (direction == Reversal) // 电机反转
{
if (STEP < 1)
{
STEP = 4;
}
STEP --;
}
Stepper_SingleStep(STEP, Delay_Time_xms);
}
}
/**
* @brief 步进电机按整数圈旋转
* @param direction 电机旋转方向,可以是Foreward(正传)或者Reversal(反转)
* @param Loop 电机旋转的圈数
* @param Delay_Time_xms 每步旋转后延时时间x ms,用于控制步进电机速度(一般需大于等于2)
* @retval
*/
void Stepper_RotateByLoop(RotDirection direction, uint32_t Loop, uint16_t Delay_Time_xms)
{
Stepper_RotateByStep(direction, Loop * 2048, Delay_Time_xms);
}
Stepper.h代码如下
#ifndef __STEPPER_H_
#define __STEPPER_H_
// 电机的旋转方向
typedef enum
{
Foreward = 0,
Reversal = 1
} RotDirection;
// 需要使用其他端口时,只需要更改以下的宏定义即可
// 这里需要保证四个输出端口同属一个GPIO
// 如果不能满足这一点,需要更改Stepper.c中初始化函数Stepper_Init和Stepper_RotateByStep中的一些变量名称
// 这里的宏定义是为了提高程序的可读性和可移植性,但使用stm32f10x.h中定义的原始名称也未尝不可
#define Stepper_CLK RCC_APB2Periph_GPIOA
#define Stepper_Output_GPIO GPIOA
#define Stepper_LA GPIO_Pin_0
#define Stepper_LB GPIO_Pin_1
#define Stepper_LC GPIO_Pin_2
#define Stepper_LD GPIO_Pin_3
#define StepperL_LA GPIO_Pin_4
#define StepperL_LB GPIO_Pin_5
#define StepperL_LC GPIO_Pin_6
#define StepperL_LD GPIO_Pin_7
void Stepper_GPIOInit(void);
void Stepper_Stop(void);
void Stepper_SingleStep(uint8_t StepNum, uint16_t Delay_Time_xms);
void Stepper_RotateByStep(RotDirection direction, uint32_t step, uint16_t Delay_Time_xms);
void Stepper_RotateByLoop(RotDirection direction, uint32_t Loop, uint16_t Delay_Time_xms);
#endif
Delay.c代码如下
#include "stm32f10x.h"
/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
Delay.h代码如下
#ifndef __DELAY_H
#define __DELAY_H
void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);
#endif
main函数代码如下
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Stepper.h"
int main()
{
Stepper_GPIOInit();
while(1)
{
Stepper_RotateByLoop(Foreward, 1, 3);
Stepper_RotateByLoop(Reversal, 1, 3);
}
}
代码核心就是这些,放在STM32基础模板工程里面即可
实验现象是步进电机正转一圈以后反转一圈,循环往复