概述

随着嵌入式系统的发展,步进电机的使用开始激增,只要涉及到把物体从一个地方移动到另外一个地方,都少不了步进电机的身影。本教程以stm32为例,使用ULN2003,TB6600电机驱动板,A4988,DRV8825,介绍步进电机的常用驱动方式。

从ULN2003开始

首先从最简单的入手,用ULN2003芯片,来驱动这种淘宝单片机套件中经常见到(但其实并没有什么用处)的5V四相五线步进电机。

长这个样子

用了配套的驱动板,但其实可以直接把ULN2003芯片插面包板上使用

(不知道我这么打广告这家淘宝店给不给钱)

上面提到了四相五线,仔细看有一条红线,即为5V电源线,还有黄、橙、粉、蓝四线,即名字里的四相,每条线都连接了电机内部的一个线圈,转子可以看做是一个磁铁,给四个线圈依次通电,线圈通电产生磁性,使转子旋转。这里有几种信号的输入方法,参考了一个很不错的制作网站中的一个帖子,链接附在这里:howtomechatronics

如上图所示,当给其中一个线圈通电时,对应线圈变为红色,产生磁性,那么怎么才能给线圈通电呢?之前我们提到了五线中还有一条5V的电源线,那么当把某一线圈接地时,电流便会流过线圈,这样,ULN2003的作用就很明显了
——将对应引脚接地。

如下图所示,ULN2003的工作方式是这样的,正视芯片(缺口端朝上),左边最下面的引脚接地,当左边的引脚输入高电平时,右边与它平行的引脚接地,所以我们只要用stm32控制对应的引脚依次为高电平就可以让它转动起来了。

接线如下图所示,用了野火的f103ZET6的核心板,PA5,PA6,PA7,PA8依次接IN1,IN2,IN3,IN4。用两节AA电池供电,在这里要注意,不能用板子直接供电,因为电机在启动瞬间会产生很大的感应电流而烧坏板子。为了使电平统一,还应该把板子的GND与电源负极连接。
(这里有一点小问题,就是Fritzing中没有我们用到的步进电机类型,所以在用了四线的代替)

实物图:

一、开始———波驱动或者单个线圈激发(Wave Drive or Single-Coil Excitation)

从上图我们可以看到,这个驱动方式是依次给线圈通电,然后在通电线圈断电的同时给下一个线圈通电,按照这个顺序循环往复。
下面是程序:

首先我们在user创建bsp_gpio.h与bsp_gpio.c,来初始化GPIO口,如接线所示,PA4-PA7依次接IN1-IN4

//IN1-PA4
#define IN1_GPIO_PORT     GPIOA
#define IN1_GPIO_CLK      RCC_APB2Periph_GPIOA
#define IN1_GPIO_PIN      GPIO_Pin_4//IN2-PA5
#define IN2_GPIO_PORT     GPIOA
#define IN2_GPIO_CLK      RCC_APB2Periph_GPIOA
#define IN2_GPIO_PIN      GPIO_Pin_5//IN3-PA6
#define IN3_GPIO_PORT     GPIOA
#define IN3_GPIO_CLK      RCC_APB2Periph_GPIOA
#define IN3_GPIO_PIN      GPIO_Pin_6//IN1-PA7
#define IN4_GPIO_PORT     GPIOA
#define IN4_GPIO_CLK      RCC_APB2Periph_GPIOA
#define IN4_GPIO_PIN      GPIO_Pin_7

之后我们使用直接操作BSRR与BRR寄存器的方式来控制IO

/* 直接操作寄存器的方法控制IO */
#define digitalHi(p,i)       {p->BSRR=i;}    //输出为高电平
#define digitalLo(p,i)       {p->BRR=i;}     //输出低电平/* 定义控制IO的宏 */
#define IN1_HIGH        digitalHi(IN1_GPIO_PORT,IN1_GPIO_PIN)
#define IN1_LOW         digitalLo(IN1_GPIO_PORT,IN1_GPIO_PIN)#define IN2_HIGH        digitalHi(IN2_GPIO_PORT,IN2_GPIO_PIN)
#define IN2_LOW         digitalLo(IN2_GPIO_PORT,IN2_GPIO_PIN)#define IN3_HIGH        digitalHi(IN3_GPIO_PORT,IN3_GPIO_PIN)
#define IN3_LOW         digitalLo(IN3_GPIO_PORT,IN3_GPIO_PIN)#define IN4_HIGH        digitalHi(IN4_GPIO_PORT,IN4_GPIO_PIN)
#define IN4_LOW         digitalLo(IN4_GPIO_PORT,IN4_GPIO_PIN)

使用宏定义对IO口封装,使Main函数更加直观,编写更加简单
之后在bsp_gpio.c中我们定义函数void GPIO_Config(void)来初始化IO口,全部设置为通用推挽输出,速度为50MHz。

void GPIO_Config(void)
{       /*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*开启引脚相关的GPIO外设时钟*/RCC_APB2PeriphClockCmd( IN1_GPIO_CLK | IN2_GPIO_CLK | IN3_GPIO_CLK | IN4_GPIO_CLK , ENABLE);/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = IN1_GPIO_PIN;   /*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*设置引脚速率为50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化GPIO*/GPIO_Init(IN1_GPIO_PORT, &GPIO_InitStructure);  /*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = IN2_GPIO_PIN;/*调用库函数,初始化GPIO*/GPIO_Init(IN2_GPIO_PORT, &GPIO_InitStructure);/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = IN3_GPIO_PIN;/*调用库函数,初始化GPIOF*/GPIO_Init(IN3_GPIO_PORT, &GPIO_InitStructure);/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = IN4_GPIO_PIN;/*调用库函数,初始化GPIOF*/GPIO_Init(IN4_GPIO_PORT, &GPIO_InitStructure);//所有引脚初始化为低电平IN1_LOW;IN2_LOW;IN3_LOW;IN4_LOW;
}

这样,对IO口的初始化配置完成,来到Main函数,首先调用GPIO_Config();来对GPIO口进行初始化,之后在while(1)这个死循环中,重复进行以下动作:

1.给一个线圈通电;

2.延时一定时间;

3.将通电线圈断电,同时给下一个线圈通电;

4.重复1,2,3步。

(注:这里的通电指对应引脚输出高电平,断电指对应引脚输出低电平)
为了实现延时功能,在这里使用了系统滴答计时器,可实现毫秒计时。

void SysTick_Delay_Ms(__IO uint32_t ms)
{uint32_t i;SysTick_Config(72000);for(i=0; i<ms ; i++){while(!(SysTick->CTRL)&(1<<16));}SysTick->CTRL &= SysTick_CTRL_ENABLE_Msk;
}while函数:while(1){IN1_HIGH;SysTick_Delay_Ms(DelayTime);IN1_LOW;IN2_HIGH;SysTick_Delay_Ms(DelayTime);IN2_LOW;IN3_HIGH;SysTick_Delay_Ms(DelayTime);IN3_LOW;IN4_HIGH;SysTick_Delay_Ms(DelayTime);IN4_LOW;}

到这里驱动程序就写好了,DelayTime在main.c数开头用宏定义,改变其大小,可以调节步进电机的转速,经过实验DelayTime的最小值为6500左右,如果数值过小,由于转换过快,步进电机只会抖动而不会转动。如果把驱动过程反过来,可以实现反向。
如果顺序烧录后电机只是抖动而不转动,除了上面提到的问题之外,还可能是接线顺序的问题,可以调整线序来使电机线圈实现依次通电。

实验成功后,继续完善程序,定义一个stepper(Dir,Speed)来实现控制电机转动方向与速度

enum dir{Pos,Neg};void stepper(uint8_t dir,int speed)
{if(dir == Pos){IN1_HIGH;SysTick_Delay_Ms(speed);IN1_LOW;IN2_HIGH;SysTick_Delay_Ms(speed);IN2_LOW;IN3_HIGH;SysTick_Delay_Ms(speed);IN3_LOW;IN4_HIGH;SysTick_Delay_Ms(speed);IN4_LOW;}else{IN1_HIGH;SysTick_Delay_Ms(speed);IN1_LOW;IN4_HIGH;SysTick_Delay_Ms(speed);IN4_LOW;IN3_HIGH;SysTick_Delay_Ms(speed);IN3_LOW;IN2_HIGH;SysTick_Delay_Ms(speed);IN2_LOW;}
}

新的main函数

int main(void)
{enum dir{Pos,Neg};GPIO_Config();while(1){int i;for(i = 0;i < 1000;i++)      //电机正转stepper(Pos,8000);     SysTick_Delay_Ms(500000);    //延时for(i = 0;i < 1000;i++)      //电机反转stepper(Neg,8000); SysTick_Delay_Ms(500000);    //延时}
}


成功了!电机转动起来,并且能够改变方向

二、其它驱动方法

在上面我们成功驱动电机使其转动起来,但是这样的方式效率很低,原文作者还提到了更好的几种驱动方法


(上图)这种方法延长了线圈的通电时间,使得同时会有两个线圈通电,但是用这种方法一转仍然是四步。

(上图)于是有了半步驱动这种方式,这其实是上面两种方式的结合,用这种方式控制,一转变成了八步。

(上图)现在用的最多的是这种微步控制方式,可以看到结果调制的正弦波被输入到电机中,用这种方式,转子的转动更加平滑,同时电机各部分受到的力也随之减小,这样电机工作过程中的振动与丢步大大减小。这就是所谓的输入pwm波控制步进电机。
但是问题在于,pwm波的调制不像输出高低电平那么简单,而且一般用到的步进电机驱动电流超过了板子的提供范围,所以在实际应用中,更多的是使用驱动板或者驱动芯片,这将在之后的文章中讲到。

用stm32驱动步进电机(一) ——使用ULN2003芯片相关推荐

  1. STM32驱动步进电机(最全的版本寄存器+HAL库实现)

    步进电机 1 简介 1.1 什么是步进电机 1.2 步进电机和直流电机区别 1.3 器材与配置 1.3.1 步进电机 1.3.2 驱动器 1.3.3 引脚 2 定时器的 3 驱动代码 3.1 初始化 ...

  2. 【常用芯片】ULN2003工作原理及中文资料(实例:STM32驱动28BYJ48步进电机)

    ULN2003的基本介绍 ULN2003的概述 ULN2003是高耐压.大电流复合晶体管阵列,由七个硅NPN 复合晶体管组成.一般采用DIP-16 或SOP-16 塑料封装. ULN2003的主要特点 ...

  3. 【STM32】步进电机及其驱动(ULN2003驱动28BYJ-48丨按键控制电机旋转)

    本篇文章包含的内容 一.步进电机的结构和工作原理 1.1 步进控制系统的组成 1.2 步进电机简介 1.3 步进电机的分类 1.4 步进电机的工作原理 1.4.1 单极性步进电机(5线4相) 1.4. ...

  4. STM32驱动十个步进电机

    https://download.csdn.net/download/qq_36958104/12015084 程序链接 脉冲很正点   //stm32驱动步进电机 串口输出控制旋转角度 光电开关检测 ...

  5. STM32+ULN2003驱动步进电机

    选用的步进电机的型号为28BYJ-48(或MP28GA,5V,转速比1/64),驱动电路选用uln2003芯片的驱动板,其控制时序图如下: 四相八拍:A->AB->B ->BC -& ...

  6. STM32控制ULN2003驱动步进电机28BYJ-48

    步进电机 步进电动机又称脉冲电动机,是一种将电脉冲信号转换成相应角位移或线位移的电动机.每输入一个脉冲信号,转子就转动一个角度或前进一步,其输出的角位移或线位移与输入的脉冲数成正比,转速与脉冲频率成正 ...

  7. STM32控制步进电机:基于定时器中断的ULN2003驱动器/步进电机驱动程序

    STM32控制步进电机:基于定时器中断的ULN2003驱动器/步进电机驱动程序 一.ULN2003驱动器 1.工作原理 2.步距角以及一圈所需步数的计算 二.硬件连接 三.STM32F103定时器中断 ...

  8. stm32读取目标芯片_使用stm32驱动RC522读IC卡(代码留言邮箱)

    RC522与PN532简介 关于STM32驱动方式 接线说明 程序烧录 查看卡号 总结 RC522与PN532简介 在写这篇文章之前有写过一篇有关于PN532的文章,RC522与PN532在使用上都可 ...

  9. 【Proteus仿真】Arduino+uln2003驱动步进电机+单按键启保停正反转控制

    [Proteus仿真]Arduino+uln2003驱动步进电机+单按键启保停正反转控制 Proteus仿真 功能实现 采用外部中断来获取按键信息 程序代码 #define LED ( 13 )#de ...

最新文章

  1. 解决cocopods不提示第三方库名字的方法
  2. Oculus Connect 4 演讲——留住用户和建立联系(视频) | 【翻译】
  3. VC++ 2012 单元测试入门
  4. 关于ffmpeg中rtmp无法设置超时时间的bug修复
  5. 洛谷 - P3391 【模板】文艺平衡树(Splay-区间反转)
  6. jvm对于java的意义_谈谈对JVM的理解
  7. codeforces1494 D. Dogeforces(构造)
  8. maven 按业务拆分模块_Maven模块拆分方法
  9. [贪心算法] 例6.2 今年暑假不AC
  10. Nacos系列:Nacos的三种部署模式 1
  11. CCF202012-4 食材运输(100分题解链接)
  12. MacOS 安装 Matlab R2021b 手记
  13. linux centos安装配置prosody
  14. canvas实现图片剪切
  15. Python numpy.ones_like函数方法的使用
  16. 【ZYNQ】从入门到秃头10 DDS增强版实验ADDA测试(基于ALINX 7020 AN108)
  17. 无法在此iPhone上激活Touch ID,怎么解决?
  18. 微信小程序-图片等比例显示不变形
  19. 关于显著性检验,你想要的都在这儿了!!(基础篇)
  20. php三元运算符要多个赋值,php中三元运算符用法

热门文章

  1. RGBA-ABGR-RGB666
  2. 各大杀毒软件比较与引擎介绍
  3. java数据结构停车场管理系统_停车场管理系统数据结构毕业论文.doc
  4. 请求的名称有效,但是找不到请求的类型的数据。
  5. protege系列(一):本体开发101:创建第一个本体的指南
  6. 深度学习新技术在搜狗搜索广告中的深化应用
  7. 2008年12月15日 属于我的分手日
  8. 微软MSDN文档及应用加速下载
  9. DOS批处理高级教程(三) : 批处理变量和set命令详解
  10. 奈雪的茶什么情况,上市第一天就跌了15%!