项目介绍
由于刚刚好手上有学长遗留下来的步进电机驱动器和步进电机,便使用灵动 Mini-F5375-OB 开发做主控驱动步进电机。
该项目基于灵动 Mini-F5375-OB 开发板结合开关电源LRS-75-24(24v输出电压)、硬石QY1249步进电机驱动器、42BYGH47步进电机套件。实现控制步进电机转动,换向,刹车启动实验。
开关电源LRS-75-24
参数信息
输出电压:24V
功能:交流电转直流电(AC-DC)
连接方式: 全桥式连接
步进电机介绍
步进电机又称为脉冲电机,基于最基本的电磁铁原理,它是一种可以自由回转的电磁铁,其动作原理是依靠气隙磁导的变化来产生电磁转矩。
电机的转速和停止位置只取决于脉冲信号的频率和数量,步进电机的脉冲与步进旋转的角度成正比,脉冲的频率与步进的转速成正比,步进电机只有周期性的误差,使得在速度、位置等控制领域用步进电机来控制变的非常的简单。
本次实验使用42BYGH47步进电机,如下图:
参数信息
型号: 42步进电机
电源方式: 直流电
电压: ≤36V
步角距: 1.8°
保持转矩: 0.4NM
额定电流: 1.5A
相电感: 4mH
相 电阻: 2.19Ω
重量: 0.3KG
电机长度: 40MM
出线数量: 4
防护等级: IP54
工作原理
步进电机的转子为永磁体,当电流流过定子绕组时,定子绕组产生一矢量磁场。磁场会带动转子旋转一定的角度, 使得转子的一对磁场方向与定子的磁场方向一致。当定子的矢量磁场旋转一个角度。转子也随着该磁场转步距角。 每输入一个电脉冲,电动机转动一个角度前进一步。
步进电机图:
步进电机极性区分
步进电机又分为单极性的步进电机和双极性的步进电机。
左侧为单极性步进电机,右侧为双极性的步进电机。
图中的红色箭头为电流的走向。
单双极性是指一个步进电机里面有几种电流的流向,四根线的电流走向汇总到公共线。
双极性电机是指电机中有两个电流的回路。
单极性步进电机驱动原理
单极性步进电机整步旋转的过程,在图示中分为5根线,分别为A、B、C、D和公共端(+),公共端需要一直通电, 剩下ABCD相中只要有一个相通电,即可形成回路产生磁场。
图中的通电顺序为A->B->C->D,即可完成上图中的顺时针旋转, 如果想要逆时针旋转只需要将其倒序即可。
单相通电产生的整步旋转,两相通电也可以产生,两个相邻的相通电。图中的通电顺序为AB->BC->CD->DA,同理逆时针旋转的顺序为逆序。
具体看下图:
如果通电顺序为:A->AB->B->BC->C->CD->D->DA 转子每次只走半步45度,所以这也被称为半步驱动,与整步相比半步的旋转方式旋转起来更加的顺滑。
双极性步进电机驱动原理
双极性的步进电机整步,步进顺序。
- 单相激励步进,每次通电产生磁性的相只有一个,要么A相,要么B相。
第一步:将A相通电,根据电磁铁原理,产生磁性,并且因异性相吸,所以磁场将转子固定在第一步的位置;
第二步:当A相关闭,B相通电时,转子会旋转90°;
第三步:B相关闭、A相通电,但极性与第1步相反,这促使转子再次旋转90°。
第四步:A相关闭、B相通电,极性与第2步相反。
重复该顺序促使转子按90°的步距角顺时针旋转。
- 双相激励,两相同时通电的旋转顺序,一次只能换相一次。
第一步:A相通电,B相不通电
第二步:A、B相全部通电,且电流相同,产生相同磁性
第三步:B相通电,A断电
第四步:B相通电,A相通电,且电流相等,产生相同磁性
第五步:A相通电,B断电
第六步:A、B相全部通电,且电流相同,产生相同磁性
第七步:B相通电,A断电
第八步:B相通电,A相通电,且电流相等,产生相同磁性
一个90°的步进电机将每半步移动45°,具体见下图
细分器驱动原理
细分的原理就是:通过改变定子的电流比例,改变转子在一个整步中的不同位置,可以将一个整步分成多个小步来运行。
图(a)为A相电流很大,B相的电流极其微弱,接近0;
图(C)为A相和B相的电流相同。
图(b)和图(d)这两个是由于A相和B相的电流不同产生位置情况;
驱动器简介
驱动器起到将控制器信号放大或者转换的作用,如下图所示,控制器输出方向信号和脉冲信号来控制步进电机驱动器, 驱动器将其功率放大然后作用到步进电机上。
驱动器特定:
参数
说明
输入电压:
DC9-40V
输出电流:
0.5-4.0A
细 分:
1,2/A,2/B,4,8,16,32
湿 度:
不能结露,不能有水珠
重 量:
0.2 千克
输入电流:
推荐使用开关电源功率 5A
最大功耗:
160W
温 度:
工作温度-10~45℃;存放温度-40℃~70℃
2) 输入输出端说明
信号输入端
EN-:电机脱机控制负。
EN+:电机脱机控制正。 电机绕组连接
DIR-:电机正、反转控制负。
DIR+:电机正、反转控制正。
PUL-:脉冲信号输入负。
PUL+:脉冲信号输入正。
电机绕组连接
A+:连接电机绕组 A+相。
A-:连接电机绕组 A-相。
B+:连接电机绕组 B+相。
B-:连接电机绕组 B-
电源电压连接
GND:电源负端“-”
VCC:电源正端“+”
接线方式
输入信号接口有两种接法:采用共阳极接法或共阴极接法。
共阴极接法如图所示:
共阳极接法如图所示:
细分数设定
细分数是以驱动板上的拨码开关选择设定的,用户可根据驱动器外盒上 的细分选择表的数据设定(最好在断电情况下设定) 。细分后步进电机步距 角按下列方法计算:步距角=电机固有步距角/细分数。如:一台固有步距角 为 1.8°的步进电机在 4 细分下步距角为 1.8° /4=0.45°驱动板上拨码开关 1、 2、 3、分别对应 S1、 S2、 S3。
电流大小设定
驱动板上拨码开关 4、 5、 6 分别对应 S4、 S5、 S6.
硬件连接
采用共阳极接法:
MM32F5375
硬石QY1249步进电机驱动器
42BYGH47步进电机
PC6
PUL-
黑 (A+)
PC8
DIR-
绿 (A-)
PC9
ENA-
红 (B+)
5V
PUL+/DIR+/ENA+
蓝 (B-)
VCC:接开关电源输出端+;GND:接开关电源输出端-;
注:接线仅供参考,具体情况具体分析;
由于资源有限,最好开发板端IO口需要和驱动器隔离开(光耦隔离:可以有效防止开发板烧毁)如下图:
软件设计
工程创建:
工程基于灵动官方hal库进行搭建,具体工程目录如下图:
libraries目录:
hardware目录:
project目录:
mdk目录:
user目录:
工程分布:
代码设计(使用PWM比较输出):
编程要点
- LED GPIO初始化以及控制函数。
- 按键 GPIO初始化以及控制函数。
- 使用RCC实现Delay函数。
- 步进电机相关GPIO初始化及控制函数。
- 步进电机定时器初始化。
gpio.h
#ifndef _GPIO_H
#define _GPIO_H
#include "HAL_conf.h"
//LED
#define LED_1_PORT GPIOB
#define LED_1_PIN GPIO_Pin_14
#define LED_2_PORT GPIOB
#define LED_2_PIN GPIO_Pin_15
//KEY
#define KEY_1_PORT GPIOB
#define KEY_1_PIN GPIO_Pin_0
#define KEY_2_PORT GPIOB
#define KEY_2_PIN GPIO_Pin_1
//步进电机DIR(方向) ENA(使能)
#define STEP_DIR_PORT GPIOC
#define STEP_DIR_PIN GPIO_Pin_8
#define STEP_ENA_PORT GPIOC
#define STEP_ENA_PIN GPIO_Pin_9
typedef enum
{
LED1,
LED2,
} LEDn_TypeDef;
typedef enum
{
LED_OFF,
LED_ON
}LEDs_TypeDef;
typedef enum
{
KEY1,
KEY2,
}KEYn_TypeDef;
typedef enum
{
KEY_RELEASED ,
KEY_PRESSED
}KEYs_TypeDef;
//步进电机开关
typedef enum
{
STEP_OFF,
STEP_ON
}STEPs_TypeDef;
//正反转
typedef enum
{
STEP_DIR_Z,
STEP_DIR_F
}STEPd_TypeDef;
void led_init(void);
void led_control(LEDn_TypeDef number, LEDs_TypeDef status);
void key_init(void);
KEYs_TypeDef key_scan(KEYn_TypeDef number);
void stepmotor_gpio_init(void);
void stepmotor_enable_control(STEPs_TypeDef status);
void stepmotor_dir_control(STEPd_TypeDef dir);
gpio.c
#include "gpio.h"
#include "delay.h"
void led_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = LED_1_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LED_1_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LED_2_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LED_2_PORT, &GPIO_InitStructure);
GPIO_SetBits(LED_1_PORT, LED_1_PIN);
GPIO_SetBits(LED_2_PORT, LED_2_PIN);
}
void key_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = KEY_1_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(KEY_1_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEY_2_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(KEY_2_PORT, &GPIO_InitStructure);
}
void stepmotor_gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = STEP_DIR_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(STEP_DIR_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = STEP_ENA_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(STEP_ENA_PORT, &GPIO_InitStructure);
GPIO_SetBits(STEP_DIR_PORT, STEP_DIR_PIN);
GPIO_ResetBits(STEP_ENA_PORT, STEP_ENA_PIN);
}
void led_control(LEDn_TypeDef number, LEDs_TypeDef status)
{
switch(number)
{
case LED1:
if (status)
{
GPIO_ResetBits(LED_1_PORT, LED_1_PIN);
}
else
{
GPIO_SetBits(LED_1_PORT, LED_1_PIN);
}
break;
case LED2:
if (status)
{
GPIO_ResetBits(LED_1_PORT, LED_2_PIN);
}
else
{
GPIO_SetBits(LED_2_PORT, LED_2_PIN);
}
break;
}
}
KEYs_TypeDef key_scan(KEYn_TypeDef number)
{
if (KEY1 == number)
{
if (GPIO_ReadInputDataBit(KEY_1_PORT, KEY_1_PIN))
{
delay_ms(10);
if (GPIO_ReadInputDataBit(KEY_1_PORT, KEY_1_PIN))
{
while (GPIO_ReadInputDataBit(KEY_1_PORT, KEY_1_PIN));
return KEY_PRESSED;
}
}
return KEY_RELEASED;
}
if (KEY2 == number)
{
if (GPIO_ReadInputDataBit(KEY_2_PORT, KEY_2_PIN))
{
delay_ms(10);
if (GPIO_ReadInputDataBit(KEY_2_PORT, KEY_2_PIN))
{
while (GPIO_ReadInputDataBit(KEY_2_PORT, KEY_2_PIN));
return KEY_PRESSED;
}
}
return KEY_RELEASED;
}
}
void stepmotor_enable_control(STEPs_TypeDef status)
{
if (status)
{
GPIO_SetBits(STEP_ENA_PORT, STEP_ENA_PIN);
}
else
{
GPIO_ResetBits(STEP_ENA_PORT, STEP_ENA_PIN);
}
}
void stepmotor_dir_control(STEPd_TypeDef dir)
{
if (dir)
{
GPIO_SetBits(STEP_DIR_PORT, STEP_DIR_PIN);
}
else
{
GPIO_ResetBits(STEP_DIR_PORT, STEP_DIR_PIN);
}
}
delay.h
#ifndef _DELAY_H
#define _DELAY_H
#include "HAL_conf.h"
#ifdef _PLATFORM_C_
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN volatile uint32_t DelayTick;
void delay_init(void);
void delay_ms(uint32_t t);
#endif
delay.c
#define _PLATFORM_C_
#include "delay.h"
void delay_init(void)
{
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
if (SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000))
{
while (1)
{
}
}
NVIC_SetPriority(SysTick_IRQn, 0x0);
}
void delay_ms(uint32_t t)
{
DelayTick = t;
while (0 != DelayTick)
{
}
}
timer.h
#ifndef _TEMER_H
#define _TEMER_H
#include "HAL_conf.h"
void stepmotor_tim_init(void);
#endif
timer.c
#include "timer.h"
static void tim8_gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_3); /* TIM8_CH1 */
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOC, &GPIO_InitStruct);
}
static void tim8_oc_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStruct);
TIM_TimeBaseStruct.TIM_Prescaler = 72;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStruct.TIM_Period = 100;
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_Div1;
TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStruct);
TIM_Cmd(TIM8, ENABLE);
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_Toggle; //使用翻转模式
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStruct.TIM_Pulse = 1;
TIM_OC1Init(TIM8, &TIM_OCInitStruct);
TIM_CtrlPWMOutputs(TIM8, ENABLE);
}
void stepmotor_tim_init(void)
{
tim8_oc_init();
tim8_gpio_init();
}
mm32f370\_it.c
void SysTick_Handler(void)
{
if (0 != DelayTick)
{
DelayTick--;
}
}
main.c
#define _MAIN_C_
/* Files include */
#include "main.h"
#include "gpio.h"
#include "delay.h"
#include "timer.h"
/* Private typedef ****************************************************************************************************/
/* Private define *****************************************************************************************************/
/* Private macro ******************************************************************************************************/
/* Private variables **************************************************************************************************/
uint8_t stepmotor_enable_flag = 0;
uint8_t stepmotor_dir_flag = 0;
/* Private functions **************************************************************************************************/
/***********************************************************************************************************************
* @brief This function is main entrance
* @note main
* @param none
* @retval none
*********************************************************************************************************************/
int main(void)
{
delay_init();
led_init();
key_init();
stepmotor_gpio_init();
stepmotor_tim_init();
while (1)
{
if (key_scan(KEY1))
{
stepmotor_enable_flag = !stepmotor_enable_flag;
stepmotor_enable_control(stepmotor_enable_flag);
led_control(LED1, stepmotor_enable_flag);
}
if (key_scan(KEY2))
{
stepmotor_dir_flag = !stepmotor_dir_flag;
stepmotor_dir_control(stepmotor_dir_flag);
led_control(LED2, stepmotor_dir_flag);
}
delay_ms(100);
}
}
/********************************************** (C) Copyright MindMotion **********************************************/
下载验证
- 将开发板与驱动器连接好;将电机、驱动、电源连接好;
- 给开发板供电,编译下载配套源码,复位开发板;
演示效果
按下key1进行步进电机和led1开启和关闭,按下key2进行步进电机的方向控制和led2的开启和关闭(差不了视频,不知道为啥)。
总结与扩展
本文介绍了灵动 Mini-F5375-OB 开发板结合开关电源LRS-75-24(24v输出电压)、硬石QY1249步进电机驱动器、42BYGH47步进电机套件。实现控制步进电机转动,换向,刹车启动实验,为 MM32F5 系列单片机的应用和快速开发提供了参考。
由于手上没有编码器,所以没有做速度闭环等更高阶的控制,感兴趣的小伙伴可以进行扩展噢。