一、步进电机介绍
01**、步进电机基本概念**
- 步进电机是将电脉冲信号转换为角位移****/****线位移的开环控制元件。
- 非超载时,转速与停止位置仅由脉冲频率、脉冲数决定,不受负载影响。
- 每输入一个脉冲,电机转过一个固定步距角,无累积误差,控制简单。
- 必须搭配脉冲信号****+****功率驱动电路使用,涉及机械、电机、电子、计算机多领域知识。
02**、步进电机分类**
- 永磁式**:二相为主,转矩与体积小**,步距角 7.5°/15°。
- **反应式:**三相为主,转矩大,步距角 1.5°;噪声与振动大,已基本淘汰。
- **混合式:**结合永磁式与反应式优点,分二相、五相,应用最广泛。


03 步进电机的****主要技术指标
(1)相数
内部线圈组数。常用二****/三/四/**五相;相数不同步距角不同,二相电机的步距角为 0.9°/1.8° ,三相为 0.75° /1.5° 、五相为 0.36° /0.72° 。使用细分驱动器**后,可通过细分数调整步距角,相数不再起决定作用。
(2)步距角
每输入一个脉冲电机转过的角度。分固有步距角与实际工作步距角,实际值受驱动器影响。
(3)拍数
完成一个磁场周期变化所需的脉冲数;四相电机常见四拍、八拍两种运行方式。
(4)保持转矩
电机通电不转时的锁定力矩,是步进电机最核心参数;低速力矩接近保持转矩,高速时输出力矩与功率会明显衰减。
二、步进电机工作原理
01****步进电机基本特性
- 步进电机是将电脉冲转换为角位移****/****线位移的电磁机械装置。
- 具备快速启停特性,电机的负荷不超动态转矩时,可通过脉冲瞬间启动或停止。
- 步距角、转速仅由输入脉冲频率决定,不受温度、气压、振动、电网电压及负载波动影响,适合精确定位场景。
02****核心工作原理
- 常见接线:三线、四线、五线、六线,控制逻辑一致,均由脉冲信号驱动。
- 旋转角度与脉冲个数成正比,每发一个脉冲,电机转动固定角度。
- 转向由励磁脉冲顺序控制,正序正转、逆序反转。
步进电机组成最主要的就是转子和定子部分。
定子:步进电机中固定不动的部分,是电机的磁场与线圈载体。
转子:步进电机中可以旋转的部分,是输出角位移 / 线位移的执行部件。
步进电机的电流流过定子产生磁场的过程叫做励磁。


下面是以2相4线的步进电机举例:

二相步进电机,电机转子的旋转,是由不同磁极的磁场相斥和相吸实现的。如右图所示,A相产生N极磁场吸引转子的S极,B相产生S极磁场吸引转子的N极,使转子产生旋转的动力。如果**改变A、B相定子线圈的电流方向,电机会产生另一步的旋转。**连续改变A、B相定子线圈的电流方向,电机会产生连续的旋转。

03****励磁方式
**一相励磁:**瞬间仅 1****个线圈导通,每步转动 1.8°。
**特点:**结构简单、精度好、功耗小,但转矩小、振动大。

**二相励磁:**瞬间 2****个线圈同时导通,每步转动 1.8°。
**特点:**转矩大、振动小,目前应用最广泛。

**一二相励磁(半步励磁):**一相与二相交替导通,每步转动 0.9°。
**特点:**分辨率高、运转平滑,适用场景广泛。
三、步进电机实验原理
本次实验是使用普中TMS320F28335单片机。
01 ULN2003 芯片介绍
ULN2003 是一个单片高电压、高电流的达林顿晶体管阵列集成电路。
(1)主要特点
①500mA 额定集电极电流(单个输出)
②高电压输出:50V
③输入和各种逻辑类型兼容
④继电器驱动器
(2)逻辑框图

从上图可以很容易理解该芯片的使用方法,其内部实际上就相当于非门电路,即输入高输出为低,输入低输出高。
(3)封装

02 硬件电路设计


从原理图可知,ULN2003 与 TC1508S 输入管脚兼容,二者步进电机 IO 口定义一致。
**区别在于:**ULN2003 可以驱动4相5线的步进电机(也可以驱动2相4线的电机),TC1508S 可以驱动2相4线步进电机。

03 接线
使用仿真器将开发板和电脑连接成功后,把编写好的程序编译后,如果没有 报错即可将点击仿真调试,程序即会写入到芯片的RAM内。将四线双极性步进电 机正确接入到直流电机模块的J2输出端子的上,电机与开发板接口管脚连接如 下:
电机A- ---> OA
电机A+ ---> OB
电机B- ---> OC
电机B+ ---> OD
如下图所示:

上图是使用TC1508S 驱动步进电机

上图: 如果使用的是五线四相步进电机就使用ULN2003,即可将其接入到步进电机模块接口M1上, 板上接口是防呆的所以也不会出现插反问题。
四、步进电机程序
注意:下面程序是使用TC1508S 驱动步进电机的。
(1)key.h
cpp
/*
* key.h
*
* Created on: 2018-1-22
* Author: Administrator
* 功能说明:F28335矩阵按键驱动头文件,包含引脚定义、宏定义、函数声明
*/
#ifndef KEY_H_
#define KEY_H_
// 包含F28335官方底层寄存器定义头文件
#include "DSP2833x_Device.h"
// 包含F28335工程示例通用头文件
#include "DSP2833x_Examples.h"
//======================== 按键行引脚(输出控制)定义 ========================
// 行1:GPIO48 输出低电平
#define KEY_L1_SetL (GpioDataRegs.GPBCLEAR.bit.GPIO48=1)
// 行2:GPIO49 输出低电平
#define KEY_L2_SetL (GpioDataRegs.GPBCLEAR.bit.GPIO49=1)
// 行3:GPIO50 输出低电平
#define KEY_L3_SetL (GpioDataRegs.GPBCLEAR.bit.GPIO50=1)
// 行1:GPIO48 输出高电平
#define KEY_L1_SetH (GpioDataRegs.GPBSET.bit.GPIO48=1)
// 行2:GPIO49 输出高电平
#define KEY_L2_SetH (GpioDataRegs.GPBSET.bit.GPIO49=1)
// 行3:GPIO50 输出高电平
#define KEY_L3_SetH (GpioDataRegs.GPBSET.bit.GPIO50=1)
//======================== 按键列引脚(输入检测)定义 ========================
// 列1:读取GPIO12引脚电平
#define KEY_H1 (GpioDataRegs.GPADAT.bit.GPIO12)
// 列2:读取GPIO13引脚电平
#define KEY_H2 (GpioDataRegs.GPADAT.bit.GPIO13)
// 列3:读取GPIO14引脚电平
#define KEY_H3 (GpioDataRegs.GPADAT.bit.GPIO14)
//======================== 按键返回值宏定义 ========================
// 按键1按下返回值
#define KEY1_PRESS 1
// 按键2按下返回值
#define KEY2_PRESS 2
// 按键3按下返回值
#define KEY3_PRESS 3
// 按键4按下返回值
#define KEY4_PRESS 4
// 按键5按下返回值
#define KEY5_PRESS 5
// 按键6按下返回值
#define KEY6_PRESS 6
// 按键7按下返回值
#define KEY7_PRESS 7
// 按键8按下返回值
#define KEY8_PRESS 8
// 按键9按下返回值
#define KEY9_PRESS 9
// 无按键按下返回值
#define KEY_UNPRESS 0
//======================== 函数声明 ========================
// 按键初始化函数:配置行列引脚的输入/输出模式
void KEY_Init(void);
// 按键扫描函数
// mode:扫描模式(0=连续扫描,1=单次扫描/松手检测)
// 返回值:按键编号(1-9)或 0(无按键)
char KEY_Scan(char mode);
#endif /* KEY_H_ */
(2)key.c
cpp
/*
* key.c
* 功能:TMS320F28335 3×3矩阵按键驱动实现文件
* 驱动方式:行输出扫描 + 列输入检测,支持按键消抖、单次/连续扫描
* Created on: 2018-1-22
* Author: Administrator
*/
#include "key.h"
/**********************************************************
* 函数名:KEY_Init
* 功能 :矩阵按键GPIO初始化
* 入口 :无
* 返回 :无
* 说明 :配置列引脚为上拉输入,行引脚为推挽输出,初始输出高电平
**********************************************************/
void KEY_Init(void)
{
// 开启受保护的寄存器写使能
EALLOW;
// 开启GPIO时钟,必须先开时钟才能操作GPIO
SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1;
//==================== 列引脚配置(输入检测)GPIO12/13/14 ====================
// GPIO12 配置为普通GPIO功能
GpioCtrlRegs.GPAMUX1.bit.GPIO12=0;
// GPIO12 配置为输入模式
GpioCtrlRegs.GPADIR.bit.GPIO12=0;
// GPIO12 使能内部上拉电阻(按键未按下时保持高电平)
GpioCtrlRegs.GPAPUD.bit.GPIO12=0;
// GPIO13 配置为普通GPIO、输入、上拉使能
GpioCtrlRegs.GPAMUX1.bit.GPIO13=0;
GpioCtrlRegs.GPADIR.bit.GPIO13=0;
GpioCtrlRegs.GPAPUD.bit.GPIO13=0;
// GPIO14 配置为普通GPIO、输入、上拉使能
GpioCtrlRegs.GPAMUX1.bit.GPIO14=0;
GpioCtrlRegs.GPADIR.bit.GPIO14=0;
GpioCtrlRegs.GPAPUD.bit.GPIO14=0;
//==================== 行引脚配置(输出扫描)GPIO48/49/50 ====================
// GPIO48 配置为普通GPIO功能
GpioCtrlRegs.GPBMUX2.bit.GPIO48=0;
// GPIO48 配置为输出模式
GpioCtrlRegs.GPBDIR.bit.GPIO48=1;
// GPIO48 使能内部上拉电阻
GpioCtrlRegs.GPBPUD.bit.GPIO48=0;
// GPIO49 配置为普通GPIO、输出、上拉使能
GpioCtrlRegs.GPBMUX2.bit.GPIO49=0;
GpioCtrlRegs.GPBDIR.bit.GPIO49=1;
GpioCtrlRegs.GPBPUD.bit.GPIO49=0;
// GPIO50 配置为普通GPIO、输出、上拉使能
GpioCtrlRegs.GPBMUX2.bit.GPIO50=0;
GpioCtrlRegs.GPBDIR.bit.GPIO50=1;
GpioCtrlRegs.GPBPUD.bit.GPIO50=0;
// 关闭受保护的寄存器写使能
EDIS;
// 行引脚初始状态:全部输出高电平(无按键按下)
GpioDataRegs.GPBSET.bit.GPIO48=1;
GpioDataRegs.GPBSET.bit.GPIO49=1;
GpioDataRegs.GPBSET.bit.GPIO50=1;
}
/**********************************************************
* 函数名:KEY_Scan
* 功能 :3×3矩阵按键扫描函数
* 入口 :mode - 扫描模式
* mode=0:连续扫描(按住不放持续返回键值)
* mode=1:单次扫描(按下只返回一次,松手后才能再次触发)
* 返回 :按键值 1~9(对应KEY1~KEY9),0表示无按键按下
**********************************************************/
char KEY_Scan(char mode)
{
// 静态变量:记录3行按键的状态,用于松手检测(只在第一次按下时有效)
static char keyl1=1;
static char keyl2=1;
static char keyl3=1;
//======================== 第一行扫描:拉低L1,拉高L2/L3 ========================
KEY_L1_SetL; // 行1输出低电平
KEY_L2_SetH; // 行2输出高电平
KEY_L3_SetH; // 行3输出高电平
// 判断:行1未被锁定 + 任意一列检测到低电平(按键按下)
if(keyl1==1&&(KEY_H1==0||KEY_H2==0||KEY_H3==0))
{
DELAY_US(10000); // 软件消抖:延时10ms,避开按键抖动干扰
keyl1=0; // 锁定行1,防止重复触发
// 判断具体是哪一列按键按下
if(KEY_H1==0)
{
return KEY1_PRESS; // 第一行第一列:KEY1
}
else if(KEY_H2==0)
{
return KEY4_PRESS; // 第一行第二列:KEY4
}
else if(KEY_H3==0)
{
return KEY7_PRESS; // 第一行第三列:KEY7
}
}
// 所有列都为高电平 → 按键松开 → 解除行1锁定
else if(KEY_H1==1&&KEY_H2==1&&KEY_H3==1)
{
keyl1=1;
}
// 单次扫描模式:强制解锁,确保按下只返回一次
if(mode)
keyl1=1;
//======================== 第二行扫描:拉低L2,拉高L1/L3 ========================
KEY_L2_SetL;
KEY_L1_SetH;
KEY_L3_SetH;
if(keyl2==1&&(KEY_H1==0||KEY_H2==0||KEY_H3==0))
{
DELAY_US(10000);
keyl2=0;
if(KEY_H1==0)
{
return KEY2_PRESS; // 第二行第一列:KEY2
}
else if(KEY_H2==0)
{
return KEY5_PRESS; // 第二行第二列:KEY5
}
else if(KEY_H3==0)
{
return KEY8_PRESS; // 第二行第三列:KEY8
}
}
else if(KEY_H1==1&&KEY_H2==1&&KEY_H3==1)
{
keyl2=1;
}
if(mode)
keyl2=1;
//======================== 第三行扫描:拉低L3,拉高L1/L2 ========================
KEY_L3_SetL;
KEY_L1_SetH;
KEY_L2_SetH;
if(keyl3==1&&(KEY_H1==0||KEY_H2==0||KEY_H3==0))
{
DELAY_US(10000);
keyl3=0;
if(KEY_H1==0)
{
return KEY3_PRESS; // 第三行第一列:KEY3
}
else if(KEY_H2==0)
{
return KEY6_PRESS; // 第三行第二列:KEY6
}
else if(KEY_H3==0)
{
return KEY9_PRESS; // 第三行第三列:KEY9
}
}
else if(KEY_H1==1&&KEY_H2==1&&KEY_H3==1)
{
keyl3=1;
}
if(mode)
keyl3=1;
// 无任何按键按下
return KEY_UNPRESS;
}
(3)step_motor.c
cpp
/*
* step_motor.c
*
* Created on: 2018-1-23
* Author: Administrator
* 功能说明:TMS320F28335 步进电机驱动源文件
* 实现步进电机控制GPIO初始化
*/
#include "step_motor.h"
/**********************************************************
* 函数名:Step_Motor_Init
* 功能 :步进电机控制引脚初始化
* 入口 :无
* 返回 :无
* 说明 :配置GPIO2/3/4/5为通用推挽输出,初始输出低电平
**********************************************************/
void Step_Motor_Init(void)
{
// 开启受保护寄存器写使能(F28335操作关键寄存器必须加)
EALLOW;
// 开启GPIO时钟,必须先开启时钟才能正常操作GPIO引脚
SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1;
//==================== 步进电机控制引脚配置 ====================
// GPIO2 配置为普通GPIO功能(0=通用IO,1=外设功能)
GpioCtrlRegs.GPAMUX1.bit.GPIO2=0;
// GPIO2 配置为输出模式(0=输入,1=输出)
GpioCtrlRegs.GPADIR.bit.GPIO2=1;
// GPIO3 配置为普通GPIO、输出模式
GpioCtrlRegs.GPAMUX1.bit.GPIO3=0;
GpioCtrlRegs.GPADIR.bit.GPIO3=1;
// GPIO4 配置为普通GPIO、输出模式
GpioCtrlRegs.GPAMUX1.bit.GPIO4=0;
GpioCtrlRegs.GPADIR.bit.GPIO4=1;
// GPIO5 配置为普通GPIO、输出模式
GpioCtrlRegs.GPAMUX1.bit.GPIO5=0;
GpioCtrlRegs.GPADIR.bit.GPIO5=1;
// 关闭受保护寄存器写使能
EDIS;
//==================== 引脚初始电平设置 ====================
// GPIO2 输出低电平
GpioDataRegs.GPACLEAR.bit.GPIO2=1;
// GPIO3 输出低电平
GpioDataRegs.GPACLEAR.bit.GPIO3=1;
// GPIO4 输出低电平
GpioDataRegs.GPACLEAR.bit.GPIO4=1;
// GPIO5 输出低电平
GpioDataRegs.GPACLEAR.bit.GPIO5=1;
}
(4)step_motor.h
cpp
/*
* step_motor.h
*
* Created on: 2018-1-23
* Author: Administrator
*/
#ifndef STEP_MOTOR_H_
#define STEP_MOTOR_H_
#include "DSP2833x_Device.h" // DSP2833x 头文件
#include "DSP2833x_Examples.h" // DSP2833x 例子相关头文件
#define STEP_MOTOR_4LINE2
//#define STEP_MOTOR_5LINE4
// A相设置高电平
#define MOTO_OUTA_SETH (GpioDataRegs.GPASET.bit.GPIO2=1)
#define MOTO_OUTA_SETL (GpioDataRegs.GPACLEAR.bit.GPIO2=1)
#define MOTO_OUTB_SETH (GpioDataRegs.GPASET.bit.GPIO3=1)
#define MOTO_OUTB_SETL (GpioDataRegs.GPACLEAR.bit.GPIO3=1)
#define MOTO_OUTC_SETH (GpioDataRegs.GPASET.bit.GPIO4=1)
#define MOTO_OUTC_SETL (GpioDataRegs.GPACLEAR.bit.GPIO4=1)
#define MOTO_OUTD_SETH (GpioDataRegs.GPASET.bit.GPIO5=1)
#define MOTO_OUTD_SETL (GpioDataRegs.GPACLEAR.bit.GPIO5=1)
void Step_Motor_Init(void);
#endif /* STEP_MOTOR_H_ */
(5)main.c
cpp
#include "DSP2833x_Device.h"
#include "DSP2833x_Examples.h"
#include "leds.h"
#include "key.h"
#include "step_motor.h"
// 这个是5线4相的电机步进表
//#ifdef STEP_MOTOR_5LINE4
//unsigned char Step_table_ZTurn[]={0xfff7,0xfffb,0xffdf,0xffef};
//unsigned char Step_table_FTurn[]={0xffef,0xffdf,0xfffb,0xfff7};
//#endif
// 4线2相的电机步进表
#ifdef STEP_MOTOR_4LINE2
// 电机正转
unsigned char Step_table_ZTurn[]={0xfff7,0xffdf,0xfffb,0xffef};
/** 0xfff7: 0111 A相线圈反向通电
0xffdf: 1101 B相线圈反向通电
0xfffb: 1011 A相线圈正向通电
0xffef: 1110 B相线圈正向通电
通电顺序是:磁场顺序:A 反 → B 反 → A 正 → B 正
**/
// 电机反转
unsigned char Step_table_FTurn[]={0xffef,0xfffb,0xffdf,0xfff7};
/** 0xffef: 1111 1111 1110 1111 GPIO4 = 0, B相线圈正向通电
0xfffb: 1111 1111 1111 1011 GPIO2 = 0, A相线圈正向通电
0xffdf: 1111 1111 1101 1111 GPIO5 = 0, B相线圈反向通电
0xfff7: 1111 1111 1111 0111 GPIO3 = 0, A相线圈反向通电
通电顺序是:磁场顺序: B 正→ A 正 → B 反→ A 反
**/
#endif
// ===================== 调速参数 =====================
int speed_delay = 8000;
#define MIN_DELAY 3000
#define MAX_DELAY 10000
// 运行模式:0=停止 1=正转 2=反转
char run_mode = 0;
// =====================================================
void main()
{
int i=0;
char key=0;
char j=0;
InitSysCtrl();
LED_Init();
KEY_Init();
Step_Motor_Init();
while(1)
{
key = KEY_Scan(0);
// ===================== 按键设置模式 =====================
if(key == KEY1_PRESS) run_mode = 1; // 一直正转
if(key == KEY2_PRESS) run_mode = 2; // 一直反转
if(key == KEY5_PRESS) run_mode = 0; // 立即停止
// 调速
if(key == KEY3_PRESS){
speed_delay -= 1000;
if(speed_delay < MIN_DELAY) speed_delay = MIN_DELAY;
}
if(key == KEY4_PRESS){
speed_delay += 1000;
if(speed_delay > MAX_DELAY) speed_delay = MAX_DELAY;
}
// =========================================================
// ===================== 电机运行 =====================
if(run_mode == 1) // 正转
{
// 将十六进制数值0xffef写入到 GPIOA 的数据寄存器,此数值经过设计,能直接设置 GPIO2/3/4/5 的高低电平,从而实现一个节拍的励磁状态。
GpioDataRegs.GPADAT.all = Step_table_ZTurn[j];
j = (j+1) % 4;
DELAY_US(speed_delay);
}
else if(run_mode == 2) // 反转
{
GpioDataRegs.GPADAT.all = Step_table_FTurn[j];
j = (j+1) % 4;
DELAY_US(speed_delay);
}
else // 停止
{
GpioDataRegs.GPADAT.all = 0xFFFF; // 不给线圈通电,电机停止转动
}
// =====================================================
if(i++%2000 == 0) LED1_TOGGLE;
}
}
步进电机工作原理步进电机工作