前言
我们常见电机有直流电机,舵机,编码电机,步进电机,伺服电机。直流电机,舵机等尝适用于精度要求不是很高的场景,但对于一些精度要求比较高的功能上就需要使用到步进电机,伺服电机等电机。
电机
我们以42步进电机为例,图中为二相四线,分为A组,B组,拿到一个未知的步进电机我们可以将其中两根线短接在一起,扭动转子,如果能扭动,则这两根线不是一组,则换一根线,同样的方法,直到某两根线短接在一起,扭动转子时有阻力,则这两根线为一组
驱动
常见驱动有两种
今天讲解的是下面这款闭环驱动,
接口说明
接线
有共阴极和共阳极两种接法,效果都一样,只是在代码里改变引脚高低电平的顺序不一样,其他没什么区别,这里我们采用共阳级接法,
一,两根线将MF+,DR+,PU+短接一起,再用一根线节PU+到单片机+5v引脚口
二,DR-接PA4,PU-接PA3.
三,MF-可接可不接,强迫症的话接去单片机+5V引脚口
单片机与驱动的控制部分接线完成,接下来是,电机与驱动器的接线
一,用文章开头我说的方法将带电机的线分组
二,将每组分别接入驱动的A,B口,正负不用管。
电机与驱动的接线完成,现在只需要将驱动的+V,-V接到电源接线完成。带风扇这个是我的升压模块,因为没24V电源所以需要升压模块。
接口讲解
我们只需要记住,PU是脉冲信号,用于控制电机转动。DR用于控制电机转动方向即可。
驱动拨挡讲解
Peak是驱动峰值电流,RMS是工作电流,两者对应关系是Peak = RMS * 1.4;
我们可以通过上图拨动SW1,SW2,SW3,选取我们想要的工作电流和峰值电流,本次讲解里我们用工作电流1.5A, 2.1A的峰值电流。将SW1拨动到ON即可,
电机精度拨挡
Pulse是脉冲数,数值越大,电机一个脉冲内转动角度就越小,对应电机精度就越高,拨挡方法同上,本次讲解我们用1600档,也就是带电机转动一圈需要1600个脉冲信号。
代码讲解
我们先来理解一下电机的部分知识,方便理解代码。
一般来说步进电机的步距为1.8度,则360 / 1.8 = 200步,则电机转动一圈需要200步,也就是200个脉冲信号,而我在前面提到的驱动器电机精度拨挡,拨到了1600档,也就是将电机转动一圈所需的步数从200增加到了1600步,这也就是说电机的精度被我们通过驱动提到了1.8度 / 8 = 0.225度,则一个脉冲电机走0.225步,走完一圈需要1600步,我们看上图,最大可以达到一圈需要40000步,这个精度就很高了吧,这款驱动可以用于医疗器械,当然这是题外话,医疗方面的嵌入式门槛比较高,回到正文,现在我们的代码需要给电机1600个脉冲信号。
脉冲信号可以用翻转电平来模拟,翻转一次就是一个脉冲信号
上才艺,家人们
关键代码
void Motor_Run(uint32_t dir, uint32_t num, uint32_t speed)
{
// 根据dir的值设置电机方向
if(dir == 1)
{
GPIO_SetBits(GPIOA, GPIO_Pin_4);
}
if(dir == 0)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
}
// 循环num*3200次,每次延迟speed微秒,翻转GPIOA的Pin3,实现电机转动
for(uint32_t i = 0; i <= (num*3200); i++)
{
Delay_us(speed);
GPIOA->ODR ^= GPIO_Pin_3; // 操作寄存器翻转GPIOA的Pin3
}
}
dir 电机转动方向,num:电机转动圈数,speed:电机转动速度
我是用一个for循环来依次给电机脉冲信号,每循环一次,给一个脉冲信号。电机走一步。这样说就很简单了吧,当循环结束,脉冲信号也结束,电机走完1600步,转了一圈。
控制转速原理:
在for循环里加一个延时,这样每循环一次就等待一次延时,这样电机每步之间延时一定时间,1600步下来,不就达到控制转速原理了;
MOTOR.H
#include "stm32f10x.h" // Device header
#include "Delay.h"
/**
* 函 数:直流电机初始化
* 参 数:无
* 返 回 值:无
*/
void Motor_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_4 | GPIO_Pin_3); //设置GPIOA的Pin4、Pin3为高电平
}
/**
* @brief 控制电机运行
*
* 该函数用于根据指定的方向、运行次数和速度控制电机运行。
* 通过设置GPIOA的Pin4控制电机方向,通过翻转GPIOA的Pin3控制电机转动。
*
* @param dir 电机运行方向,1表示正转,0表示反转。
* @param num 电机运行的圈数,单位为圈。
* @param speed 电机运行的速度,单位为us。
*/
void Motor_Run(uint32_t dir, uint32_t num, uint32_t speed)
{
// 根据dir的值设置电机方向
if(dir == 1)
{
GPIO_SetBits(GPIOA, GPIO_Pin_4);
}
if(dir == 0)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
}
// 循环num*3200次,每次延迟speed微秒,翻转GPIOA的Pin3,实现电机转动
for(uint32_t i = 0; i <= (num*3200); i++)
{
Delay_us(speed);
GPIOA->ODR ^= GPIO_Pin_3; // 操作寄存器翻转GPIOA的Pin3
}
}
我们只需要在需要的地方调用该接口就好了,如果挡位很高的话建议速度不要太快,不要问为什么,问就是作者亲测,血的教训!!!!!!!